authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-01 09:56:01-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-12-01 09:56:01-05:00
logb36c07a95a6cf9b2cc120133b44cbd0673e6823a
tree2c2bf8ff9137d51b80ae56dc70ef9375b8c13583
parentb220be7a33a9835a1ec7a033e472830290332d57
parent4b6740e19d57454f3c4eac0c2e9a92ce08e7ec04
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'origin/master' into remove-array-type-coercion


65 files changed, 3020 insertions(+), 994 deletions(-)

doc/langref.html.in+4-4
...@@ -7455,6 +7455,10 @@ fn add(a: i32, b: i32) i32 { return a + b; }...@@ -7455,6 +7455,10 @@ fn add(a: i32, b: i32) i32 { return a + b; }
7455 Attempting to convert a number which is out of range of the destination type results in7455 Attempting to convert a number which is out of range of the destination type results in
7456 safety-protected {#link|Undefined Behavior#}.7456 safety-protected {#link|Undefined Behavior#}.
7457 </p>7457 </p>
7458 <p>
7459 If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#},
7460 then this is semantically equivalent to {#link|Type Coercion#}.
7461 </p>
7458 {#header_close#}7462 {#header_close#}
74597463
7460 {#header_open|@intToEnum#}7464 {#header_open|@intToEnum#}
...@@ -8206,10 +8210,6 @@ test "integer truncation" {...@@ -8206,10 +8210,6 @@ test "integer truncation" {
8206 This function always truncates the significant bits of the integer, regardless8210 This function always truncates the significant bits of the integer, regardless
8207 of endianness on the target platform.8211 of endianness on the target platform.
8208 </p>8212 </p>
8209 <p>
8210 If {#syntax#}T{#endsyntax#} is {#syntax#}comptime_int{#endsyntax#},
8211 then this is semantically equivalent to {#link|Type Coercion#}.
8212 </p>
8213 {#header_close#}8213 {#header_close#}
82148214
8215 {#header_open|@Type#}8215 {#header_open|@Type#}
lib/std/array_list.zig+17
...@@ -40,6 +40,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {...@@ -40,6 +40,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
40 .allocator = allocator,40 .allocator = allocator,
41 };41 };
42 }42 }
43
44 /// Initialize with capacity to hold at least num elements.
45 /// Deinitialize with `deinit` or use `toOwnedSlice`.
46 pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
47 var self = Self.init(allocator);
48 try self.ensureCapacity(num);
49 return self;
50 }
4351
44 /// Release all allocated memory.52 /// Release all allocated memory.
45 pub fn deinit(self: Self) void {53 pub fn deinit(self: Self) void {
...@@ -271,6 +279,15 @@ test "std.ArrayList.init" {...@@ -271,6 +279,15 @@ test "std.ArrayList.init" {
271 testing.expect(list.capacity() == 0);279 testing.expect(list.capacity() == 0);
272}280}
273281
282test "std.ArrayList.initCapacity" {
283 var bytes: [1024]u8 = undefined;
284 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
285 var list = try ArrayList(i8).initCapacity(allocator, 200);
286 defer list.deinit();
287 testing.expect(list.count() == 0);
288 testing.expect(list.capacity() >= 200);
289}
290
274test "std.ArrayList.basic" {291test "std.ArrayList.basic" {
275 var bytes: [1024]u8 = undefined;292 var bytes: [1024]u8 = undefined;
276 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;293 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
lib/std/buffer.zig+35-1
...@@ -16,13 +16,22 @@ pub const Buffer = struct {...@@ -16,13 +16,22 @@ pub const Buffer = struct {
16 mem.copy(u8, self.list.items, m);16 mem.copy(u8, self.list.items, m);
17 return self;17 return self;
18 }18 }
1919
20 /// Initialize memory to size bytes of undefined values.
20 /// Must deinitialize with deinit.21 /// Must deinitialize with deinit.
21 pub fn initSize(allocator: *Allocator, size: usize) !Buffer {22 pub fn initSize(allocator: *Allocator, size: usize) !Buffer {
22 var self = initNull(allocator);23 var self = initNull(allocator);
23 try self.resize(size);24 try self.resize(size);
24 return self;25 return self;
25 }26 }
27
28 /// Initialize with capacity to hold at least num bytes.
29 /// Must deinitialize with deinit.
30 pub fn initCapacity(allocator: *Allocator, num: usize) !Buffer {
31 var self = Buffer{ .list = try ArrayList(u8).initCapacity(allocator, num + 1) };
32 self.list.appendAssumeCapacity(0);
33 return self;
34 }
2635
27 /// Must deinitialize with deinit.36 /// Must deinitialize with deinit.
28 /// None of the other operations are valid until you do one of these:37 /// None of the other operations are valid until you do one of these:
...@@ -98,6 +107,13 @@ pub const Buffer = struct {...@@ -98,6 +107,13 @@ pub const Buffer = struct {
98 pub fn len(self: Buffer) usize {107 pub fn len(self: Buffer) usize {
99 return self.list.len - 1;108 return self.list.len - 1;
100 }109 }
110
111 pub fn capacity(self: Buffer) usize {
112 return if (self.list.items.len > 0)
113 self.list.items.len - 1
114 else
115 0;
116 }
101117
102 pub fn append(self: *Buffer, m: []const u8) !void {118 pub fn append(self: *Buffer, m: []const u8) !void {
103 const old_len = self.len();119 const old_len = self.len();
...@@ -151,3 +167,21 @@ test "simple Buffer" {...@@ -151,3 +167,21 @@ test "simple Buffer" {
151 try buf2.resize(4);167 try buf2.resize(4);
152 testing.expect(buf.startsWith(buf2.toSlice()));168 testing.expect(buf.startsWith(buf2.toSlice()));
153}169}
170
171test "Buffer.initSize" {
172 var buf = try Buffer.initSize(debug.global_allocator, 3);
173 testing.expect(buf.len() == 3);
174 try buf.append("hello");
175 testing.expect(mem.eql(u8, buf.toSliceConst()[3..], "hello"));
176}
177
178test "Buffer.initCapacity" {
179 var buf = try Buffer.initCapacity(debug.global_allocator, 10);
180 testing.expect(buf.len() == 0);
181 testing.expect(buf.capacity() >= 10);
182 const old_cap = buf.capacity();
183 try buf.append("hello");
184 testing.expect(buf.len() == 5);
185 testing.expect(buf.capacity() == old_cap);
186 testing.expect(mem.eql(u8, buf.toSliceConst(), "hello"));
187}
lib/std/build.zig+23-9
...@@ -2062,14 +2062,28 @@ pub const RunStep = struct {...@@ -2062,14 +2062,28 @@ pub const RunStep = struct {
2062 }2062 }
20632063
2064 pub fn addPathDir(self: *RunStep, search_path: []const u8) void {2064 pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
2065 const PATH = if (builtin.os == .windows) "Path" else "PATH";
2066 const env_map = self.getEnvMap();2065 const env_map = self.getEnvMap();
2067 const prev_path = env_map.get(PATH) orelse {2066
2068 env_map.set(PATH, search_path) catch unreachable;2067 var key: []const u8 = undefined;
2069 return;2068 var prev_path: ?[]const u8 = undefined;
2070 };2069 if (builtin.os == .windows) {
2071 const new_path = self.builder.fmt("{}" ++ &[1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path);2070 key = "Path";
2072 env_map.set(PATH, new_path) catch unreachable;2071 prev_path = env_map.get(key);
2072 if (prev_path == null) {
2073 key = "PATH";
2074 prev_path = env_map.get(key);
2075 }
2076 } else {
2077 key = "PATH";
2078 prev_path = env_map.get(key);
2079 }
2080
2081 if (prev_path) |pp| {
2082 const new_path = self.builder.fmt("{}" ++ [1]u8{fs.path.delimiter} ++ "{}", pp, search_path);
2083 env_map.set(key, new_path) catch unreachable;
2084 } else {
2085 env_map.set(key, search_path) catch unreachable;
2086 }
2073 }2087 }
20742088
2075 pub fn getEnvMap(self: *RunStep) *BufMap {2089 pub fn getEnvMap(self: *RunStep) *BufMap {
...@@ -2178,7 +2192,7 @@ const InstallArtifactStep = struct {...@@ -2178,7 +2192,7 @@ const InstallArtifactStep = struct {
21782192
2179 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);2193 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
2180 try builder.updateFile(self.artifact.getOutputPath(), full_dest_path);2194 try builder.updateFile(self.artifact.getOutputPath(), full_dest_path);
2181 if (self.artifact.isDynamicLibrary()) {2195 if (self.artifact.isDynamicLibrary() and self.artifact.target.wantSharedLibSymLinks()) {
2182 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename);2196 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename);
2183 }2197 }
2184 if (self.pdb_dir) |pdb_dir| {2198 if (self.pdb_dir) |pdb_dir| {
...@@ -2405,7 +2419,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 {...@@ -2405,7 +2419,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 {
2405 const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" });2419 const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" });
2406 defer allocator.free(path_file);2420 defer allocator.free(path_file);
24072421
2408 const file = fs.File.openRead(path_file) catch return null;2422 const file = fs.cwd().openFile(path_file, .{}) catch return null;
2409 defer file.close();2423 defer file.close();
24102424
2411 const size = @intCast(usize, try file.getEndPos());2425 const size = @intCast(usize, try file.getEndPos());
lib/std/c.zig+1
...@@ -220,6 +220,7 @@ pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int;...@@ -220,6 +220,7 @@ pub extern "c" fn pthread_mutex_destroy(mutex: *pthread_mutex_t) c_int;
220220
221pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};221pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
222pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int;222pub extern "c" fn pthread_cond_wait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t) c_int;
223pub extern "c" fn pthread_cond_timedwait(noalias cond: *pthread_cond_t, noalias mutex: *pthread_mutex_t, noalias abstime: *const timespec) c_int;
223pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;224pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
224pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;225pub extern "c" fn pthread_cond_destroy(cond: *pthread_cond_t) c_int;
225226
lib/std/debug.zig+8-2
...@@ -1131,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {...@@ -1131,7 +1131,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
1131}1131}
11321132
1133fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {1133fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
1134 var f = try File.openRead(line_info.file_name);1134 var f = try fs.cwd().openFile(line_info.file_name, .{});
1135 defer f.close();1135 defer f.close();
1136 // TODO fstat and make sure that the file has the correct size1136 // TODO fstat and make sure that the file has the correct size
11371137
...@@ -2089,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u...@@ -2089,7 +2089,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
2089 const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));2089 const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));
20902090
2091 gop.kv.value = MachOFile{2091 gop.kv.value = MachOFile{
2092 .bytes = try std.fs.Dir.cwd().readFileAllocAligned(2092 .bytes = try std.fs.cwd().readFileAllocAligned(
2093 di.ofiles.allocator,2093 di.ofiles.allocator,
2094 ofile_path,2094 ofile_path,
2095 maxInt(usize),2095 maxInt(usize),
...@@ -2417,6 +2417,12 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con...@@ -2417,6 +2417,12 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con
2417 std.debug.warn("Segmentation fault at address 0x{x}\n", addr);2417 std.debug.warn("Segmentation fault at address 0x{x}\n", addr);
24182418
2419 switch (builtin.arch) {2419 switch (builtin.arch) {
2420 .i386 => {
2421 const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
2422 const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_EIP]);
2423 const bp = @intCast(usize, ctx.mcontext.gregs[os.REG_EBP]);
2424 dumpStackTraceFromBase(bp, ip);
2425 },
2420 .x86_64 => {2426 .x86_64 => {
2421 const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));2427 const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
2422 const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]);2428 const ip = @intCast(usize, ctx.mcontext.gregs[os.REG_RIP]);
lib/std/event/channel.zig+30-3
...@@ -54,6 +54,10 @@ pub fn Channel(comptime T: type) type {...@@ -54,6 +54,10 @@ pub fn Channel(comptime T: type) type {
54 /// For a zero length buffer, use `[0]T{}`.54 /// For a zero length buffer, use `[0]T{}`.
55 /// TODO https://github.com/ziglang/zig/issues/276555 /// TODO https://github.com/ziglang/zig/issues/2765
56 pub fn init(self: *SelfChannel, buffer: []T) void {56 pub fn init(self: *SelfChannel, buffer: []T) void {
57 // The ring buffer implementation only works with power of 2 buffer sizes
58 // because of relying on subtracting across zero. For example (0 -% 1) % 10 == 5
59 assert(buffer.len == 0 or @popCount(usize, buffer.len) == 1);
60
57 self.* = SelfChannel{61 self.* = SelfChannel{
58 .buffer_len = 0,62 .buffer_len = 0,
59 .buffer_nodes = buffer,63 .buffer_nodes = buffer,
...@@ -184,11 +188,11 @@ pub fn Channel(comptime T: type) type {...@@ -184,11 +188,11 @@ pub fn Channel(comptime T: type) type {
184 const get_node = &self.getters.get().?.data;188 const get_node = &self.getters.get().?.data;
185 switch (get_node.data) {189 switch (get_node.data) {
186 GetNode.Data.Normal => |info| {190 GetNode.Data.Normal => |info| {
187 info.ptr.* = self.buffer_nodes[self.buffer_index -% self.buffer_len];191 info.ptr.* = self.buffer_nodes[(self.buffer_index -% self.buffer_len) % self.buffer_nodes.len];
188 },192 },
189 GetNode.Data.OrNull => |info| {193 GetNode.Data.OrNull => |info| {
190 _ = self.or_null_queue.remove(info.or_null);194 _ = self.or_null_queue.remove(info.or_null);
191 info.ptr.* = self.buffer_nodes[self.buffer_index -% self.buffer_len];195 info.ptr.* = self.buffer_nodes[(self.buffer_index -% self.buffer_len) % self.buffer_nodes.len];
192 },196 },
193 }197 }
194 global_event_loop.onNextTick(get_node.tick_node);198 global_event_loop.onNextTick(get_node.tick_node);
...@@ -222,7 +226,7 @@ pub fn Channel(comptime T: type) type {...@@ -222,7 +226,7 @@ pub fn Channel(comptime T: type) type {
222 while (self.buffer_len != self.buffer_nodes.len and put_count != 0) {226 while (self.buffer_len != self.buffer_nodes.len and put_count != 0) {
223 const put_node = &self.putters.get().?.data;227 const put_node = &self.putters.get().?.data;
224228
225 self.buffer_nodes[self.buffer_index] = put_node.data;229 self.buffer_nodes[self.buffer_index % self.buffer_nodes.len] = put_node.data;
226 global_event_loop.onNextTick(put_node.tick_node);230 global_event_loop.onNextTick(put_node.tick_node);
227 self.buffer_index +%= 1;231 self.buffer_index +%= 1;
228 self.buffer_len += 1;232 self.buffer_len += 1;
...@@ -283,6 +287,29 @@ test "std.event.Channel" {...@@ -283,6 +287,29 @@ test "std.event.Channel" {
283 await putter;287 await putter;
284}288}
285289
290test "std.event.Channel wraparound" {
291
292 // TODO provide a way to run tests in evented I/O mode
293 if (!std.io.is_async) return error.SkipZigTest;
294
295 const channel_size = 2;
296
297 var buf : [channel_size]i32 = undefined;
298 var channel: Channel(i32) = undefined;
299 channel.init(&buf);
300 defer channel.deinit();
301
302 // add items to channel and pull them out until
303 // the buffer wraps around, make sure it doesn't crash.
304 var result : i32 = undefined;
305 channel.put(5);
306 testing.expectEqual(@as(i32, 5), channel.get());
307 channel.put(6);
308 testing.expectEqual(@as(i32, 6), channel.get());
309 channel.put(7);
310 testing.expectEqual(@as(i32, 7), channel.get());
311}
312
286async fn testChannelGetter(channel: *Channel(i32)) void {313async fn testChannelGetter(channel: *Channel(i32)) void {
287 const value1 = channel.get();314 const value1 = channel.get();
288 testing.expect(value1 == 1234);315 testing.expect(value1 == 1234);
lib/std/event/fs.zig+15-13
...@@ -735,24 +735,26 @@ pub fn Watch(comptime V: type) type {...@@ -735,24 +735,26 @@ pub fn Watch(comptime V: type) type {
735 allocator: *Allocator,735 allocator: *Allocator,
736736
737 const OsData = switch (builtin.os) {737 const OsData = switch (builtin.os) {
738 .macosx, .freebsd, .netbsd, .dragonfly => struct {738 // TODO https://github.com/ziglang/zig/issues/3778
739 file_table: FileTable,739 .macosx, .freebsd, .netbsd, .dragonfly => KqOsData,
740 table_lock: event.Lock,
741
742 const FileTable = std.StringHashMap(*Put);
743 const Put = struct {
744 putter_frame: @Frame(kqPutEvents),
745 cancelled: bool = false,
746 value: V,
747 };
748 },
749
750 .linux => LinuxOsData,740 .linux => LinuxOsData,
751 .windows => WindowsOsData,741 .windows => WindowsOsData,
752742
753 else => @compileError("Unsupported OS"),743 else => @compileError("Unsupported OS"),
754 };744 };
755745
746 const KqOsData = struct {
747 file_table: FileTable,
748 table_lock: event.Lock,
749
750 const FileTable = std.StringHashMap(*Put);
751 const Put = struct {
752 putter_frame: @Frame(kqPutEvents),
753 cancelled: bool = false,
754 value: V,
755 };
756 };
757
756 const WindowsOsData = struct {758 const WindowsOsData = struct {
757 table_lock: event.Lock,759 table_lock: event.Lock,
758 dir_table: DirTable,760 dir_table: DirTable,
...@@ -1291,7 +1293,7 @@ pub fn Watch(comptime V: type) type {...@@ -1291,7 +1293,7 @@ pub fn Watch(comptime V: type) type {
1291 os.linux.EINVAL => unreachable,1293 os.linux.EINVAL => unreachable,
1292 os.linux.EFAULT => unreachable,1294 os.linux.EFAULT => unreachable,
1293 os.linux.EAGAIN => {1295 os.linux.EAGAIN => {
1294 global_event_loop.linuxWaitFd(self.os_data.inotify_fd, os.linux.EPOLLET | os.linux.EPOLLIN);1296 global_event_loop.linuxWaitFd(self.os_data.inotify_fd, os.linux.EPOLLET | os.linux.EPOLLIN | os.EPOLLONESHOT);
1295 },1297 },
1296 else => unreachable,1298 else => unreachable,
1297 }1299 }
lib/std/fs.zig+229-49
...@@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File;...@@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File;
1313
14pub const symLink = os.symlink;14pub const symLink = os.symlink;
15pub const symLinkC = os.symlinkC;15pub const symLinkC = os.symlinkC;
16pub const deleteFile = os.unlink;
17pub const deleteFileC = os.unlinkC;
18pub const rename = os.rename;16pub const rename = os.rename;
19pub const renameC = os.renameC;17pub const renameC = os.renameC;
20pub const renameW = os.renameW;18pub const renameW = os.renameW;
...@@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {...@@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
88/// If any of the directories do not exist for dest_path, they are created.86/// If any of the directories do not exist for dest_path, they are created.
89/// TODO https://github.com/ziglang/zig/issues/288587/// TODO https://github.com/ziglang/zig/issues/2885
90pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {88pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus {
91 var src_file = try File.openRead(source_path);89 const my_cwd = cwd();
90
91 var src_file = try my_cwd.openFile(source_path, .{});
92 defer src_file.close();92 defer src_file.close();
9393
94 const src_stat = try src_file.stat();94 const src_stat = try src_file.stat();
95 check_dest_stat: {95 check_dest_stat: {
96 const dest_stat = blk: {96 const dest_stat = blk: {
97 var dest_file = File.openRead(dest_path) catch |err| switch (err) {97 var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) {
98 error.FileNotFound => break :check_dest_stat,98 error.FileNotFound => break :check_dest_stat,
99 else => |e| return e,99 else => |e| return e,
100 };100 };
...@@ -157,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil...@@ -157,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil
157/// in the same directory as dest_path.157/// in the same directory as dest_path.
158/// Destination file will have the same mode as the source file.158/// Destination file will have the same mode as the source file.
159pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {159pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
160 var in_file = try File.openRead(source_path);160 var in_file = try cwd().openFile(source_path, .{});
161 defer in_file.close();161 defer in_file.close();
162162
163 const mode = try in_file.mode();163 const mode = try in_file.mode();
...@@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {...@@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
180/// merged and readily available,180/// merged and readily available,
181/// there is a possibility of power loss or application termination leaving temporary files present181/// there is a possibility of power loss or application termination leaving temporary files present
182pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {182pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void {
183 var in_file = try File.openRead(source_path);183 var in_file = try cwd().openFile(source_path, .{});
184 defer in_file.close();184 defer in_file.close();
185185
186 var atomic_file = try AtomicFile.init(dest_path, mode);186 var atomic_file = try AtomicFile.init(dest_path, mode);
...@@ -206,8 +206,6 @@ pub const AtomicFile = struct {...@@ -206,8 +206,6 @@ pub const AtomicFile = struct {
206206
207 /// dest_path must remain valid for the lifetime of AtomicFile207 /// dest_path must remain valid for the lifetime of AtomicFile
208 /// call finish to atomically replace dest_path with contents208 /// call finish to atomically replace dest_path with contents
209 /// TODO once we have null terminated pointers, use the
210 /// openWriteNoClobberN function
211 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {209 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
212 const dirname = path.dirname(dest_path);210 const dirname = path.dirname(dest_path);
213 var rand_buf: [12]u8 = undefined;211 var rand_buf: [12]u8 = undefined;
...@@ -224,15 +222,19 @@ pub const AtomicFile = struct {...@@ -224,15 +222,19 @@ pub const AtomicFile = struct {
224222
225 tmp_path_buf[tmp_path_len] = 0;223 tmp_path_buf[tmp_path_len] = 0;
226224
225 const my_cwd = cwd();
226
227 while (true) {227 while (true) {
228 try crypto.randomBytes(rand_buf[0..]);228 try crypto.randomBytes(rand_buf[0..]);
229 b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], &rand_buf);229 b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], &rand_buf);
230230
231 const file = File.openWriteNoClobberC(@ptrCast([*:0]u8, &tmp_path_buf), mode) catch |err| switch (err) {231 // TODO https://github.com/ziglang/zig/issues/3770 to clean up this @ptrCast
232 const file = my_cwd.createFileC(
233 @ptrCast([*:0]u8, &tmp_path_buf),
234 .{ .mode = mode, .exclusive = true },
235 ) catch |err| switch (err) {
232 error.PathAlreadyExists => continue,236 error.PathAlreadyExists => continue,
233 // TODO zig should figure out that this error set does not include PathAlreadyExists since237 else => |e| return e,
234 // it is handled in the above switch
235 else => return err,
236 };238 };
237239
238 return AtomicFile{240 return AtomicFile{
...@@ -248,7 +250,7 @@ pub const AtomicFile = struct {...@@ -248,7 +250,7 @@ pub const AtomicFile = struct {
248 pub fn deinit(self: *AtomicFile) void {250 pub fn deinit(self: *AtomicFile) void {
249 if (!self.finished) {251 if (!self.finished) {
250 self.file.close();252 self.file.close();
251 deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {};253 cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {};
252 self.finished = true;254 self.finished = true;
253 }255 }
254 }256 }
...@@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void {...@@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void {
350 CannotDeleteRootDirectory,352 CannotDeleteRootDirectory,
351 }.CannotDeleteRootDirectory;353 }.CannotDeleteRootDirectory;
352354
353 var dir = try Dir.cwd().openDirList(dirname);355 var dir = try cwd().openDirList(dirname);
354 defer dir.close();356 defer dir.close();
355357
356 return dir.deleteTree(path.basename(full_path));358 return dir.deleteTree(path.basename(full_path));
357 } else {359 } else {
358 return Dir.cwd().deleteTree(full_path);360 return cwd().deleteTree(full_path);
359 }361 }
360}362}
361363
...@@ -657,17 +659,6 @@ pub const Dir = struct {...@@ -657,17 +659,6 @@ pub const Dir = struct {
657 }659 }
658 }660 }
659661
660 /// Returns an handle to the current working directory that is open for traversal.
661 /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
662 /// On POSIX targets, this function is comptime-callable.
663 pub fn cwd() Dir {
664 if (builtin.os == .windows) {
665 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
666 } else {
667 return Dir{ .fd = os.AT_FDCWD };
668 }
669 }
670
671 pub const OpenError = error{662 pub const OpenError = error{
672 FileNotFound,663 FileNotFound,
673 NotDir,664 NotDir,
...@@ -683,12 +674,12 @@ pub const Dir = struct {...@@ -683,12 +674,12 @@ pub const Dir = struct {
683 DeviceBusy,674 DeviceBusy,
684 } || os.UnexpectedError;675 } || os.UnexpectedError;
685676
686 /// Deprecated; call `Dir.cwd().openDirList` directly.677 /// Deprecated; call `cwd().openDirList` directly.
687 pub fn open(dir_path: []const u8) OpenError!Dir {678 pub fn open(dir_path: []const u8) OpenError!Dir {
688 return cwd().openDirList(dir_path);679 return cwd().openDirList(dir_path);
689 }680 }
690681
691 /// Deprecated; call `Dir.cwd().openDirListC` directly.682 /// Deprecated; call `cwd().openDirListC` directly.
692 pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir {683 pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir {
693 return cwd().openDirListC(dir_path_c);684 return cwd().openDirListC(dir_path_c);
694 }685 }
...@@ -698,29 +689,110 @@ pub const Dir = struct {...@@ -698,29 +689,110 @@ pub const Dir = struct {
698 self.* = undefined;689 self.* = undefined;
699 }690 }
700691
701 /// Call `File.close` on the result when done.692 /// Opens a file for reading or writing, without attempting to create a new file.
702 pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {693 /// Call `File.close` to release the resource.
694 /// Asserts that the path parameter has no null bytes.
695 pub fn openFile(self: Dir, sub_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
696 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
703 if (builtin.os == .windows) {697 if (builtin.os == .windows) {
704 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);698 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
705 return self.openReadW(&path_w);699 return self.openFileW(&path_w, flags);
706 }700 }
707 const path_c = try os.toPosixPath(sub_path);701 const path_c = try os.toPosixPath(sub_path);
708 return self.openReadC(&path_c);702 return self.openFileC(&path_c, flags);
709 }703 }
710704
711 /// Call `File.close` on the result when done.705 /// Same as `openFile` but the path parameter is null-terminated.
712 pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File {706 pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
713 if (builtin.os == .windows) {707 if (builtin.os == .windows) {
714 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);708 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
715 return self.openReadW(&path_w);709 return self.openFileW(&path_w, flags);
716 }710 }
717 const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;711 const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
718 const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;712 const os_flags = O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read)
719 const fd = try os.openatC(self.fd, sub_path, flags, 0);713 @as(u32, os.O_RDWR)
720 return File.openHandle(fd);714 else if (flags.write)
715 @as(u32, os.O_WRONLY)
716 else
717 @as(u32, os.O_RDONLY);
718 const fd = try os.openatC(self.fd, sub_path, os_flags, 0);
719 return File{ .handle = fd };
720 }
721
722 /// Same as `openFile` but Windows-only and the path parameter is
723 /// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
724 pub fn openFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File {
725 const w = os.windows;
726 const access_mask = w.SYNCHRONIZE |
727 (if (flags.read) @as(u32, w.GENERIC_READ) else 0) |
728 (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0);
729 return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN);
721 }730 }
722731
723 pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File {732 /// Creates, opens, or overwrites a file with write access.
733 /// Call `File.close` on the result when done.
734 /// Asserts that the path parameter has no null bytes.
735 pub fn createFile(self: Dir, sub_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
736 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
737 if (builtin.os == .windows) {
738 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
739 return self.createFileW(&path_w, flags);
740 }
741 const path_c = try os.toPosixPath(sub_path);
742 return self.createFileC(&path_c, flags);
743 }
744
745 /// Same as `createFile` but the path parameter is null-terminated.
746 pub fn createFileC(self: Dir, sub_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
747 if (builtin.os == .windows) {
748 const path_w = try os.windows.cStrToPrefixedFileW(sub_path_c);
749 return self.createFileW(&path_w, flags);
750 }
751 const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
752 const os_flags = O_LARGEFILE | os.O_CREAT | os.O_CLOEXEC |
753 (if (flags.truncate) @as(u32, os.O_TRUNC) else 0) |
754 (if (flags.read) @as(u32, os.O_RDWR) else os.O_WRONLY) |
755 (if (flags.exclusive) @as(u32, os.O_EXCL) else 0);
756 const fd = try os.openatC(self.fd, sub_path_c, os_flags, flags.mode);
757 return File{ .handle = fd };
758 }
759
760 /// Same as `createFile` but Windows-only and the path parameter is
761 /// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
762 pub fn createFileW(self: Dir, sub_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
763 const w = os.windows;
764 const access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE |
765 (if (flags.read) @as(u32, w.GENERIC_READ) else 0);
766 const creation = if (flags.exclusive)
767 @as(u32, w.FILE_CREATE)
768 else if (flags.truncate)
769 @as(u32, w.FILE_OVERWRITE_IF)
770 else
771 @as(u32, w.FILE_OPEN_IF);
772 return self.openFileWindows(sub_path_w, access_mask, creation);
773 }
774
775 /// Deprecated; call `openFile` directly.
776 pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {
777 return self.openFile(sub_path, .{});
778 }
779
780 /// Deprecated; call `openFileC` directly.
781 pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File {
782 return self.openFileC(sub_path, .{});
783 }
784
785 /// Deprecated; call `openFileW` directly.
786 pub fn openReadW(self: Dir, sub_path: [*:0]const u16) File.OpenError!File {
787 return self.openFileW(sub_path, .{});
788 }
789
790 pub fn openFileWindows(
791 self: Dir,
792 sub_path_w: [*:0]const u16,
793 access_mask: os.windows.ACCESS_MASK,
794 creation: os.windows.ULONG,
795 ) File.OpenError!File {
724 const w = os.windows;796 const w = os.windows;
725797
726 var result = File{ .handle = undefined };798 var result = File{ .handle = undefined };
...@@ -750,13 +822,13 @@ pub const Dir = struct {...@@ -750,13 +822,13 @@ pub const Dir = struct {
750 var io: w.IO_STATUS_BLOCK = undefined;822 var io: w.IO_STATUS_BLOCK = undefined;
751 const rc = w.ntdll.NtCreateFile(823 const rc = w.ntdll.NtCreateFile(
752 &result.handle,824 &result.handle,
753 w.GENERIC_READ | w.SYNCHRONIZE,825 access_mask,
754 &attr,826 &attr,
755 &io,827 &io,
756 null,828 null,
757 w.FILE_ATTRIBUTE_NORMAL,829 w.FILE_ATTRIBUTE_NORMAL,
758 w.FILE_SHARE_READ,830 w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
759 w.FILE_OPEN,831 creation,
760 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,832 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
761 null,833 null,
762 0,834 0,
...@@ -771,6 +843,7 @@ pub const Dir = struct {...@@ -771,6 +843,7 @@ pub const Dir = struct {
771 w.STATUS.ACCESS_DENIED => return error.AccessDenied,843 w.STATUS.ACCESS_DENIED => return error.AccessDenied,
772 w.STATUS.PIPE_BUSY => return error.PipeBusy,844 w.STATUS.PIPE_BUSY => return error.PipeBusy,
773 w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable,845 w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable,
846 w.STATUS.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
774 else => return w.unexpectedStatus(rc),847 else => return w.unexpectedStatus(rc),
775 }848 }
776 }849 }
...@@ -790,7 +863,10 @@ pub const Dir = struct {...@@ -790,7 +863,10 @@ pub const Dir = struct {
790 /// list the contents of a directory, open it with `openDirList`.863 /// list the contents of a directory, open it with `openDirList`.
791 ///864 ///
792 /// Call `close` on the result when done.865 /// Call `close` on the result when done.
866 ///
867 /// Asserts that the path parameter has no null bytes.
793 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {868 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {
869 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
794 if (builtin.os == .windows) {870 if (builtin.os == .windows) {
795 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);871 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
796 return self.openDirTraverseW(&sub_path_w);872 return self.openDirTraverseW(&sub_path_w);
...@@ -805,7 +881,10 @@ pub const Dir = struct {...@@ -805,7 +881,10 @@ pub const Dir = struct {
805 /// same and may be more efficient.881 /// same and may be more efficient.
806 ///882 ///
807 /// Call `close` on the result when done.883 /// Call `close` on the result when done.
884 ///
885 /// Asserts that the path parameter has no null bytes.
808 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {886 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {
887 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
809 if (builtin.os == .windows) {888 if (builtin.os == .windows) {
810 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);889 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
811 return self.openDirListW(&sub_path_w);890 return self.openDirListW(&sub_path_w);
...@@ -920,9 +999,12 @@ pub const Dir = struct {...@@ -920,9 +999,12 @@ pub const Dir = struct {
920 pub const DeleteFileError = os.UnlinkError;999 pub const DeleteFileError = os.UnlinkError;
9211000
922 /// Delete a file name and possibly the file it refers to, based on an open directory handle.1001 /// Delete a file name and possibly the file it refers to, based on an open directory handle.
1002 /// Asserts that the path parameter has no null bytes.
923 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {1003 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
924 const sub_path_c = try os.toPosixPath(sub_path);1004 os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
925 return self.deleteFileC(&sub_path_c);1005 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1006 else => |e| return e,
1007 };
926 }1008 }
9271009
928 /// Same as `deleteFile` except the parameter is null-terminated.1010 /// Same as `deleteFile` except the parameter is null-terminated.
...@@ -933,6 +1015,14 @@ pub const Dir = struct {...@@ -933,6 +1015,14 @@ pub const Dir = struct {
933 };1015 };
934 }1016 }
9351017
1018 /// Same as `deleteFile` except the parameter is WTF-16 encoded.
1019 pub fn deleteFileW(self: Dir, sub_path_w: [*:0]const u16) DeleteFileError!void {
1020 os.unlinkatW(self.fd, sub_path_w, 0) catch |err| switch (err) {
1021 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1022 else => |e| return e,
1023 };
1024 }
1025
936 pub const DeleteDirError = error{1026 pub const DeleteDirError = error{
937 DirNotEmpty,1027 DirNotEmpty,
938 FileNotFound,1028 FileNotFound,
...@@ -951,7 +1041,9 @@ pub const Dir = struct {...@@ -951,7 +1041,9 @@ pub const Dir = struct {
9511041
952 /// Returns `error.DirNotEmpty` if the directory is not empty.1042 /// Returns `error.DirNotEmpty` if the directory is not empty.
953 /// To delete a directory recursively, see `deleteTree`.1043 /// To delete a directory recursively, see `deleteTree`.
1044 /// Asserts that the path parameter has no null bytes.
954 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {1045 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
1046 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
955 if (builtin.os == .windows) {1047 if (builtin.os == .windows) {
956 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);1048 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
957 return self.deleteDirW(&sub_path_w);1049 return self.deleteDirW(&sub_path_w);
...@@ -979,7 +1071,9 @@ pub const Dir = struct {...@@ -979,7 +1071,9 @@ pub const Dir = struct {
9791071
980 /// Read value of a symbolic link.1072 /// Read value of a symbolic link.
981 /// The return value is a slice of `buffer`, from index `0`.1073 /// The return value is a slice of `buffer`, from index `0`.
1074 /// Asserts that the path parameter has no null bytes.
982 pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {1075 pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
1076 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
983 const sub_path_c = try os.toPosixPath(sub_path);1077 const sub_path_c = try os.toPosixPath(sub_path);
984 return self.readLinkC(&sub_path_c, buffer);1078 return self.readLinkC(&sub_path_c, buffer);
985 }1079 }
...@@ -1190,8 +1284,94 @@ pub const Dir = struct {...@@ -1190,8 +1284,94 @@ pub const Dir = struct {
1190 }1284 }
1191 }1285 }
1192 }1286 }
1287
1288 /// Writes content to the file system, creating a new file if it does not exist, truncating
1289 /// if it already exists.
1290 pub fn writeFile(self: Dir, sub_path: []const u8, data: []const u8) !void {
1291 var file = try self.createFile(sub_path, .{});
1292 defer file.close();
1293 try file.write(data);
1294 }
1193};1295};
11941296
1297/// Returns an handle to the current working directory that is open for traversal.
1298/// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior.
1299/// On POSIX targets, this function is comptime-callable.
1300pub fn cwd() Dir {
1301 if (builtin.os == .windows) {
1302 return Dir{ .fd = os.windows.peb().ProcessParameters.CurrentDirectory.Handle };
1303 } else {
1304 return Dir{ .fd = os.AT_FDCWD };
1305 }
1306}
1307
1308/// Opens a file for reading or writing, without attempting to create a new file, based on an absolute path.
1309/// Call `File.close` to release the resource.
1310/// Asserts that the path is absolute. See `Dir.openFile` for a function that
1311/// operates on both absolute and relative paths.
1312/// Asserts that the path parameter has no null bytes. See `openFileAbsoluteC` for a function
1313/// that accepts a null-terminated path.
1314pub fn openFileAbsolute(absolute_path: []const u8, flags: File.OpenFlags) File.OpenError!File {
1315 assert(path.isAbsolute(absolute_path));
1316 return cwd().openFile(absolute_path, flags);
1317}
1318
1319/// Same as `openFileAbsolute` but the path parameter is null-terminated.
1320pub fn openFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
1321 assert(path.isAbsoluteC(absolute_path_c));
1322 return cwd().openFileC(absolute_path_c, flags);
1323}
1324
1325/// Same as `openFileAbsolute` but the path parameter is WTF-16 encoded.
1326pub fn openFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.OpenFlags) File.OpenError!File {
1327 assert(path.isAbsoluteW(absolute_path_w));
1328 return cwd().openFileW(absolute_path_w, flags);
1329}
1330
1331/// Creates, opens, or overwrites a file with write access, based on an absolute path.
1332/// Call `File.close` to release the resource.
1333/// Asserts that the path is absolute. See `Dir.createFile` for a function that
1334/// operates on both absolute and relative paths.
1335/// Asserts that the path parameter has no null bytes. See `createFileAbsoluteC` for a function
1336/// that accepts a null-terminated path.
1337pub fn createFileAbsolute(absolute_path: []const u8, flags: File.CreateFlags) File.OpenError!File {
1338 assert(path.isAbsolute(absolute_path));
1339 return cwd().createFile(absolute_path, flags);
1340}
1341
1342/// Same as `createFileAbsolute` but the path parameter is null-terminated.
1343pub fn createFileAbsoluteC(absolute_path_c: [*:0]const u8, flags: File.CreateFlags) File.OpenError!File {
1344 assert(path.isAbsoluteC(absolute_path_c));
1345 return cwd().createFileC(absolute_path_c, flags);
1346}
1347
1348/// Same as `createFileAbsolute` but the path parameter is WTF-16 encoded.
1349pub fn createFileAbsoluteW(absolute_path_w: [*:0]const u16, flags: File.CreateFlags) File.OpenError!File {
1350 assert(path.isAbsoluteW(absolute_path_w));
1351 return cwd().createFileW(absolute_path_w, flags);
1352}
1353
1354/// Delete a file name and possibly the file it refers to, based on an absolute path.
1355/// Asserts that the path is absolute. See `Dir.deleteFile` for a function that
1356/// operates on both absolute and relative paths.
1357/// Asserts that the path parameter has no null bytes.
1358pub fn deleteFileAbsolute(absolute_path: []const u8) DeleteFileError!void {
1359 assert(path.isAbsolute(absolute_path));
1360 return cwd().deleteFile(absolute_path);
1361}
1362
1363/// Same as `deleteFileAbsolute` except the parameter is null-terminated.
1364pub fn deleteFileAbsoluteC(absolute_path_c: [*:0]const u8) DeleteFileError!void {
1365 assert(path.isAbsoluteC(absolute_path_c));
1366 return cwd().deleteFileC(absolute_path_c);
1367}
1368
1369/// Same as `deleteFileAbsolute` except the parameter is WTF-16 encoded.
1370pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void {
1371 assert(path.isAbsoluteW(absolute_path_w));
1372 return cwd().deleteFileW(absolute_path_w);
1373}
1374
1195pub const Walker = struct {1375pub const Walker = struct {
1196 stack: std.ArrayList(StackItem),1376 stack: std.ArrayList(StackItem),
1197 name_buffer: std.Buffer,1377 name_buffer: std.Buffer,
...@@ -1264,7 +1444,7 @@ pub const Walker = struct {...@@ -1264,7 +1444,7 @@ pub const Walker = struct {
1264pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {1444pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
1265 assert(!mem.endsWith(u8, dir_path, path.sep_str));1445 assert(!mem.endsWith(u8, dir_path, path.sep_str));
12661446
1267 var dir = try Dir.cwd().openDirList(dir_path);1447 var dir = try cwd().openDirList(dir_path);
1268 errdefer dir.close();1448 errdefer dir.close();
12691449
1270 var name_buffer = try std.Buffer.init(allocator, dir_path);1450 var name_buffer = try std.Buffer.init(allocator, dir_path);
...@@ -1298,18 +1478,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE...@@ -1298,18 +1478,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE
12981478
1299pub fn openSelfExe() OpenSelfExeError!File {1479pub fn openSelfExe() OpenSelfExeError!File {
1300 if (builtin.os == .linux) {1480 if (builtin.os == .linux) {
1301 return File.openReadC("/proc/self/exe");1481 return openFileAbsoluteC("/proc/self/exe", .{});
1302 }1482 }
1303 if (builtin.os == .windows) {1483 if (builtin.os == .windows) {
1304 const wide_slice = selfExePathW();1484 const wide_slice = selfExePathW();
1305 const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);1485 const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice);
1306 return Dir.cwd().openReadW(&prefixed_path_w);1486 return cwd().openReadW(&prefixed_path_w);
1307 }1487 }
1308 var buf: [MAX_PATH_BYTES]u8 = undefined;1488 var buf: [MAX_PATH_BYTES]u8 = undefined;
1309 const self_exe_path = try selfExePath(&buf);1489 const self_exe_path = try selfExePath(&buf);
1310 buf[self_exe_path.len] = 0;1490 buf[self_exe_path.len] = 0;
1311 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/37311491 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
1312 return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr));1492 return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{});
1313}1493}
13141494
1315test "openSelfExe" {1495test "openSelfExe" {
lib/std/fs/file.zig+56-73
...@@ -25,105 +25,87 @@ pub const File = struct {...@@ -25,105 +25,87 @@ pub const File = struct {
2525
26 pub const OpenError = windows.CreateFileError || os.OpenError;26 pub const OpenError = windows.CreateFileError || os.OpenError;
2727
28 /// Deprecated; call `std.fs.Dir.openRead` directly.28 /// TODO https://github.com/ziglang/zig/issues/3802
29 pub const OpenFlags = struct {
30 read: bool = true,
31 write: bool = false,
32 };
33
34 /// TODO https://github.com/ziglang/zig/issues/3802
35 pub const CreateFlags = struct {
36 /// Whether the file will be created with read access.
37 read: bool = false,
38
39 /// If the file already exists, and is a regular file, and the access
40 /// mode allows writing, it will be truncated to length 0.
41 truncate: bool = true,
42
43 /// Ensures that this open call creates the file, otherwise causes
44 /// `error.FileAlreadyExists` to be returned.
45 exclusive: bool = false,
46
47 /// For POSIX systems this is the file system mode the file will
48 /// be created with.
49 mode: Mode = default_mode,
50 };
51
52 /// Deprecated; call `std.fs.Dir.openFile` directly.
29 pub fn openRead(path: []const u8) OpenError!File {53 pub fn openRead(path: []const u8) OpenError!File {
30 return std.fs.Dir.cwd().openRead(path);54 return std.fs.cwd().openFile(path, .{});
31 }55 }
3256
33 /// Deprecated; call `std.fs.Dir.openReadC` directly.57 /// Deprecated; call `std.fs.Dir.openFileC` directly.
34 pub fn openReadC(path_c: [*:0]const u8) OpenError!File {58 pub fn openReadC(path_c: [*:0]const u8) OpenError!File {
35 return std.fs.Dir.cwd().openReadC(path_c);59 return std.fs.cwd().openFileC(path_c, .{});
36 }60 }
3761
38 /// Deprecated; call `std.fs.Dir.openReadW` directly.62 /// Deprecated; call `std.fs.Dir.openFileW` directly.
39 pub fn openReadW(path_w: [*]const u16) OpenError!File {63 pub fn openReadW(path_w: [*]const u16) OpenError!File {
40 return std.fs.Dir.cwd().openReadW(path_w);64 return std.fs.cwd().openFileW(path_w, .{});
41 }65 }
4266
43 /// Calls `openWriteMode` with `default_mode` for the mode.67 /// Deprecated; call `std.fs.Dir.createFile` directly.
44 /// TODO: deprecate this and move it to `std.fs.Dir`.
45 pub fn openWrite(path: []const u8) OpenError!File {68 pub fn openWrite(path: []const u8) OpenError!File {
46 return openWriteMode(path, default_mode);69 return std.fs.cwd().createFile(path, .{});
47 }70 }
4871
49 /// If the path does not exist it will be created.72 /// Deprecated; call `std.fs.Dir.createFile` directly.
50 /// If a file already exists in the destination it will be truncated.
51 /// Call close to clean up.
52 /// TODO: deprecate this and move it to `std.fs.Dir`.
53 pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {73 pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
54 if (builtin.os == .windows) {74 return std.fs.cwd().createFile(path, .{ .mode = file_mode });
55 const path_w = try windows.sliceToPrefixedFileW(path);
56 return openWriteModeW(&path_w, file_mode);
57 }
58 const path_c = try os.toPosixPath(path);
59 return openWriteModeC(&path_c, file_mode);
60 }75 }
6176
62 /// Same as `openWriteMode` except `path` is null-terminated.77 /// Deprecated; call `std.fs.Dir.createFileC` directly.
63 /// TODO: deprecate this and move it to `std.fs.Dir`.78 pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File {
64 pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File {79 return std.fs.cwd().createFileC(path_c, .{ .mode = file_mode });
65 if (builtin.os == .windows) {
66 const path_w = try windows.cStrToPrefixedFileW(path);
67 return openWriteModeW(&path_w, file_mode);
68 }
69 const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
70 const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
71 const fd = try os.openC(path, flags, file_mode);
72 return openHandle(fd);
73 }80 }
7481
75 /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded82 /// Deprecated; call `std.fs.Dir.createFileW` directly.
76 /// TODO: deprecate this and move it to `std.fs.Dir`.
77 pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {83 pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
78 const handle = try windows.CreateFileW(84 return std.fs.cwd().createFileW(path_w, .{ .mode = file_mode });
79 path_w,
80 windows.GENERIC_WRITE,
81 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
82 null,
83 windows.CREATE_ALWAYS,
84 windows.FILE_ATTRIBUTE_NORMAL,
85 null,
86 );
87 return openHandle(handle);
88 }85 }
8986
90 /// If the path does not exist it will be created.87 /// Deprecated; call `std.fs.Dir.createFile` directly.
91 /// If a file already exists in the destination this returns OpenError.PathAlreadyExists
92 /// Call close to clean up.
93 /// TODO: deprecate this and move it to `std.fs.Dir`.
94 pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {88 pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
95 if (builtin.os == .windows) {89 return std.fs.cwd().createFile(path, .{
96 const path_w = try windows.sliceToPrefixedFileW(path);90 .mode = file_mode,
97 return openWriteNoClobberW(&path_w, file_mode);91 .exclusive = true,
98 }92 });
99 const path_c = try os.toPosixPath(path);
100 return openWriteNoClobberC(&path_c, file_mode);
101 }93 }
10294
103 /// TODO: deprecate this and move it to `std.fs.Dir`.95 /// Deprecated; call `std.fs.Dir.createFileC` directly.
104 pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File {96 pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File {
105 if (builtin.os == .windows) {97 return std.fs.cwd().createFileC(path_c, .{
106 const path_w = try windows.cStrToPrefixedFileW(path);98 .mode = file_mode,
107 return openWriteNoClobberW(&path_w, file_mode);99 .exclusive = true,
108 }100 });
109 const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
110 const flags = O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_EXCL;
111 const fd = try os.openC(path, flags, file_mode);
112 return openHandle(fd);
113 }101 }
114102
115 /// TODO: deprecate this and move it to `std.fs.Dir`.103 /// Deprecated; call `std.fs.Dir.createFileW` directly.
116 pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {104 pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
117 const handle = try windows.CreateFileW(105 return std.fs.cwd().createFileW(path_w, .{
118 path_w,106 .mode = file_mode,
119 windows.GENERIC_WRITE,107 .exclusive = true,
120 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,108 });
121 null,
122 windows.CREATE_NEW,
123 windows.FILE_ATTRIBUTE_NORMAL,
124 null,
125 );
126 return openHandle(handle);
127 }109 }
128110
129 pub fn openHandle(handle: os.fd_t) File {111 pub fn openHandle(handle: os.fd_t) File {
...@@ -246,6 +228,7 @@ pub const File = struct {...@@ -246,6 +228,7 @@ pub const File = struct {
246 windows.STATUS.SUCCESS => {},228 windows.STATUS.SUCCESS => {},
247 windows.STATUS.BUFFER_OVERFLOW => {},229 windows.STATUS.BUFFER_OVERFLOW => {},
248 windows.STATUS.INVALID_PARAMETER => unreachable,230 windows.STATUS.INVALID_PARAMETER => unreachable,
231 windows.STATUS.ACCESS_DENIED => return error.AccessDenied,
249 else => return windows.unexpectedStatus(rc),232 else => return windows.unexpectedStatus(rc),
250 }233 }
251 return Stat{234 return Stat{
lib/std/fs/path.zig+32-1
...@@ -130,6 +130,14 @@ test "join" {...@@ -130,6 +130,14 @@ test "join" {
130 testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c");130 testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c");
131}131}
132132
133pub fn isAbsoluteC(path_c: [*:0]const u8) bool {
134 if (builtin.os == .windows) {
135 return isAbsoluteWindowsC(path_c);
136 } else {
137 return isAbsolutePosixC(path_c);
138 }
139}
140
133pub fn isAbsolute(path: []const u8) bool {141pub fn isAbsolute(path: []const u8) bool {
134 if (builtin.os == .windows) {142 if (builtin.os == .windows) {
135 return isAbsoluteWindows(path);143 return isAbsoluteWindows(path);
...@@ -138,7 +146,7 @@ pub fn isAbsolute(path: []const u8) bool {...@@ -138,7 +146,7 @@ pub fn isAbsolute(path: []const u8) bool {
138 }146 }
139}147}
140148
141pub fn isAbsoluteW(path_w: [*]const u16) bool {149pub fn isAbsoluteW(path_w: [*:0]const u16) bool {
142 if (path_w[0] == '/')150 if (path_w[0] == '/')
143 return true;151 return true;
144152
...@@ -176,10 +184,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool {...@@ -176,10 +184,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool {
176 return false;184 return false;
177}185}
178186
187pub fn isAbsoluteWindowsC(path_c: [*:0]const u8) bool {
188 if (path_c[0] == '/')
189 return true;
190
191 if (path_c[0] == '\\') {
192 return true;
193 }
194 if (path_c[0] == 0 or path_c[1] == 0 or path_c[2] == 0) {
195 return false;
196 }
197 if (path_c[1] == ':') {
198 if (path_c[2] == '/')
199 return true;
200 if (path_c[2] == '\\')
201 return true;
202 }
203 return false;
204}
205
179pub fn isAbsolutePosix(path: []const u8) bool {206pub fn isAbsolutePosix(path: []const u8) bool {
180 return path[0] == sep_posix;207 return path[0] == sep_posix;
181}208}
182209
210pub fn isAbsolutePosixC(path_c: [*:0]const u8) bool {
211 return path_c[0] == sep_posix;
212}
213
183test "isAbsoluteWindows" {214test "isAbsoluteWindows" {
184 testIsAbsoluteWindows("/", true);215 testIsAbsoluteWindows("/", true);
185 testIsAbsoluteWindows("//", true);216 testIsAbsoluteWindows("//", true);
lib/std/io.zig+4-7
...@@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream;...@@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream;
61pub const InStream = @import("io/in_stream.zig").InStream;61pub const InStream = @import("io/in_stream.zig").InStream;
62pub const OutStream = @import("io/out_stream.zig").OutStream;62pub const OutStream = @import("io/out_stream.zig").OutStream;
6363
64/// TODO move this to `std.fs` and add a version to `std.fs.Dir`.64/// Deprecated; use `std.fs.Dir.writeFile`.
65pub fn writeFile(path: []const u8, data: []const u8) !void {65pub fn writeFile(path: []const u8, data: []const u8) !void {
66 var file = try File.openWrite(path);66 return fs.cwd().writeFile(path, data);
67 defer file.close();
68 try file.write(data);
69}67}
7068
71/// On success, caller owns returned buffer.69/// Deprecated; use `std.fs.Dir.readFileAlloc`.
72/// This function is deprecated; use `std.fs.Dir.readFileAlloc`.
73pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {70pub fn readFileAlloc(allocator: *mem.Allocator, path: []const u8) ![]u8 {
74 return fs.Dir.cwd().readFileAlloc(allocator, path, math.maxInt(usize));71 return fs.cwd().readFileAlloc(allocator, path, math.maxInt(usize));
75}72}
7673
77pub fn BufferedInStream(comptime Error: type) type {74pub fn BufferedInStream(comptime Error: type) type {
lib/std/io/test.zig+15-13
...@@ -14,12 +14,14 @@ test "write a file, read it, then delete it" {...@@ -14,12 +14,14 @@ test "write a file, read it, then delete it" {
14 var raw_bytes: [200 * 1024]u8 = undefined;14 var raw_bytes: [200 * 1024]u8 = undefined;
15 var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;15 var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;
1616
17 const cwd = fs.cwd();
18
17 var data: [1024]u8 = undefined;19 var data: [1024]u8 = undefined;
18 var prng = DefaultPrng.init(1234);20 var prng = DefaultPrng.init(1234);
19 prng.random.bytes(data[0..]);21 prng.random.bytes(data[0..]);
20 const tmp_file_name = "temp_test_file.txt";22 const tmp_file_name = "temp_test_file.txt";
21 {23 {
22 var file = try File.openWrite(tmp_file_name);24 var file = try cwd.createFile(tmp_file_name, .{});
23 defer file.close();25 defer file.close();
2426
25 var file_out_stream = file.outStream();27 var file_out_stream = file.outStream();
...@@ -32,8 +34,8 @@ test "write a file, read it, then delete it" {...@@ -32,8 +34,8 @@ test "write a file, read it, then delete it" {
32 }34 }
3335
34 {36 {
35 // make sure openWriteNoClobber doesn't harm the file37 // Make sure the exclusive flag is honored.
36 if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| {38 if (cwd.createFile(tmp_file_name, .{ .exclusive = true })) |file| {
37 unreachable;39 unreachable;
38 } else |err| {40 } else |err| {
39 std.debug.assert(err == File.OpenError.PathAlreadyExists);41 std.debug.assert(err == File.OpenError.PathAlreadyExists);
...@@ -41,7 +43,7 @@ test "write a file, read it, then delete it" {...@@ -41,7 +43,7 @@ test "write a file, read it, then delete it" {
41 }43 }
4244
43 {45 {
44 var file = try File.openRead(tmp_file_name);46 var file = try cwd.openFile(tmp_file_name, .{});
45 defer file.close();47 defer file.close();
4648
47 const file_size = try file.getEndPos();49 const file_size = try file.getEndPos();
...@@ -58,7 +60,7 @@ test "write a file, read it, then delete it" {...@@ -58,7 +60,7 @@ test "write a file, read it, then delete it" {
58 expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));60 expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));
59 expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));61 expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
60 }62 }
61 try fs.deleteFile(tmp_file_name);63 try cwd.deleteFile(tmp_file_name);
62}64}
6365
64test "BufferOutStream" {66test "BufferOutStream" {
...@@ -274,7 +276,7 @@ test "BitOutStream" {...@@ -274,7 +276,7 @@ test "BitOutStream" {
274test "BitStreams with File Stream" {276test "BitStreams with File Stream" {
275 const tmp_file_name = "temp_test_file.txt";277 const tmp_file_name = "temp_test_file.txt";
276 {278 {
277 var file = try File.openWrite(tmp_file_name);279 var file = try fs.cwd().createFile(tmp_file_name, .{});
278 defer file.close();280 defer file.close();
279281
280 var file_out = file.outStream();282 var file_out = file.outStream();
...@@ -291,7 +293,7 @@ test "BitStreams with File Stream" {...@@ -291,7 +293,7 @@ test "BitStreams with File Stream" {
291 try bit_stream.flushBits();293 try bit_stream.flushBits();
292 }294 }
293 {295 {
294 var file = try File.openRead(tmp_file_name);296 var file = try fs.cwd().openFile(tmp_file_name, .{});
295 defer file.close();297 defer file.close();
296298
297 var file_in = file.inStream();299 var file_in = file.inStream();
...@@ -316,7 +318,7 @@ test "BitStreams with File Stream" {...@@ -316,7 +318,7 @@ test "BitStreams with File Stream" {
316318
317 expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));319 expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
318 }320 }
319 try fs.deleteFile(tmp_file_name);321 try fs.cwd().deleteFile(tmp_file_name);
320}322}
321323
322fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {324fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
...@@ -599,7 +601,7 @@ test "c out stream" {...@@ -599,7 +601,7 @@ test "c out stream" {
599 const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;601 const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
600 defer {602 defer {
601 _ = std.c.fclose(out_file);603 _ = std.c.fclose(out_file);
602 fs.deleteFileC(filename) catch {};604 fs.cwd().deleteFileC(filename) catch {};
603 }605 }
604606
605 const out_stream = &io.COutStream.init(out_file).stream;607 const out_stream = &io.COutStream.init(out_file).stream;
...@@ -608,10 +610,10 @@ test "c out stream" {...@@ -608,10 +610,10 @@ test "c out stream" {
608610
609test "File seek ops" {611test "File seek ops" {
610 const tmp_file_name = "temp_test_file.txt";612 const tmp_file_name = "temp_test_file.txt";
611 var file = try File.openWrite(tmp_file_name);613 var file = try fs.cwd().createFile(tmp_file_name, .{});
612 defer {614 defer {
613 file.close();615 file.close();
614 fs.deleteFile(tmp_file_name) catch {};616 fs.cwd().deleteFile(tmp_file_name) catch {};
615 }617 }
616618
617 try file.write(&([_]u8{0x55} ** 8192));619 try file.write(&([_]u8{0x55} ** 8192));
...@@ -632,10 +634,10 @@ test "File seek ops" {...@@ -632,10 +634,10 @@ test "File seek ops" {
632634
633test "updateTimes" {635test "updateTimes" {
634 const tmp_file_name = "just_a_temporary_file.txt";636 const tmp_file_name = "just_a_temporary_file.txt";
635 var file = try File.openWrite(tmp_file_name);637 var file = try fs.cwd().createFile(tmp_file_name, .{ .read = true });
636 defer {638 defer {
637 file.close();639 file.close();
638 std.fs.deleteFile(tmp_file_name) catch {};640 std.fs.cwd().deleteFile(tmp_file_name) catch {};
639 }641 }
640 var stat_old = try file.stat();642 var stat_old = try file.stat();
641 // Set atime and mtime to 5s before643 // Set atime and mtime to 5s before
lib/std/math.zig-12
...@@ -25,18 +25,6 @@ pub const ln2 = 0.693147180559945309417232121458176568;...@@ -25,18 +25,6 @@ pub const ln2 = 0.693147180559945309417232121458176568;
25/// ln(10)25/// ln(10)
26pub const ln10 = 2.302585092994045684017991454684364208;26pub const ln10 = 2.302585092994045684017991454684364208;
2727
28/// π/2
29pub const pi_2 = 1.570796326794896619231321691639751442;
30
31/// π/4
32pub const pi_4 = 0.785398163397448309615660845819875721;
33
34/// 1/π
35pub const one_pi = 0.318309886183790671537767526745028724;
36
37/// 2/π
38pub const two_pi = 0.636619772367581343075535053490057448;
39
40/// 2/sqrt(π)28/// 2/sqrt(π)
41pub const two_sqrtpi = 1.128379167095512573896158903121545172;29pub const two_sqrtpi = 1.128379167095512573896158903121545172;
4230
lib/std/mutex.zig+85-47
...@@ -1,13 +1,12 @@...@@ -1,13 +1,12 @@
1const std = @import("std.zig");1const std = @import("std.zig");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const testing = std.testing;3const testing = std.testing;
4const SpinLock = std.SpinLock;4const ResetEvent = std.ResetEvent;
5const ThreadParker = std.ThreadParker;
65
7/// Lock may be held only once. If the same thread6/// Lock may be held only once. If the same thread
8/// tries to acquire the same mutex twice, it deadlocks.7/// tries to acquire the same mutex twice, it deadlocks.
9/// This type supports static initialization and is based off of Golang 1.13 runtime.lock_futex:8/// This type supports static initialization and is based off of Webkit's WTF Lock (via rust parking_lot)
10/// https://github.com/golang/go/blob/master/src/runtime/lock_futex.go9/// https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs
11/// When an application is built in single threaded release mode, all the functions are10/// When an application is built in single threaded release mode, all the functions are
12/// no-ops. In single threaded debug mode, there is deadlock detection.11/// no-ops. In single threaded debug mode, there is deadlock detection.
13pub const Mutex = if (builtin.single_threaded)12pub const Mutex = if (builtin.single_threaded)
...@@ -39,80 +38,119 @@ pub const Mutex = if (builtin.single_threaded)...@@ -39,80 +38,119 @@ pub const Mutex = if (builtin.single_threaded)
39 }38 }
40else39else
41 struct {40 struct {
42 state: State, // TODO: make this an enum41 state: usize,
43 parker: ThreadParker,
4442
45 const State = enum(u32) {43 const MUTEX_LOCK: usize = 1 << 0;
46 Unlocked,44 const QUEUE_LOCK: usize = 1 << 1;
47 Sleeping,45 const QUEUE_MASK: usize = ~(MUTEX_LOCK | QUEUE_LOCK);
48 Locked,46 const QueueNode = std.atomic.Stack(ResetEvent).Node;
49 };
5047
51 /// number of iterations to spin yielding the cpu48 /// number of iterations to spin yielding the cpu
52 const SPIN_CPU = 4;49 const SPIN_CPU = 4;
5350
54 /// number of iterations to perform in the cpu yield loop51 /// number of iterations to spin in the cpu yield loop
55 const SPIN_CPU_COUNT = 30;52 const SPIN_CPU_COUNT = 30;
5653
57 /// number of iterations to spin yielding the thread54 /// number of iterations to spin yielding the thread
58 const SPIN_THREAD = 1;55 const SPIN_THREAD = 1;
5956
60 pub fn init() Mutex {57 pub fn init() Mutex {
61 return Mutex{58 return Mutex{ .state = 0 };
62 .state = .Unlocked,
63 .parker = ThreadParker.init(),
64 };
65 }59 }
6660
67 pub fn deinit(self: *Mutex) void {61 pub fn deinit(self: *Mutex) void {
68 self.parker.deinit();62 self.* = undefined;
69 }63 }
7064
71 pub const Held = struct {65 pub const Held = struct {
72 mutex: *Mutex,66 mutex: *Mutex,
7367
74 pub fn release(self: Held) void {68 pub fn release(self: Held) void {
75 switch (@atomicRmw(State, &self.mutex.state, .Xchg, .Unlocked, .Release)) {69 // since MUTEX_LOCK is the first bit, we can use (.Sub) instead of (.And, ~MUTEX_LOCK).
76 .Locked => {},70 // this is because .Sub may be implemented more efficiently than the latter
77 .Sleeping => self.mutex.parker.unpark(@ptrCast(*const u32, &self.mutex.state)),71 // (e.g. `lock xadd` vs `cmpxchg` loop on x86)
78 .Unlocked => unreachable, // unlocking an unlocked mutex72 const state = @atomicRmw(usize, &self.mutex.state, .Sub, MUTEX_LOCK, .Release);
79 else => unreachable, // should never be anything else73 if ((state & QUEUE_MASK) != 0 and (state & QUEUE_LOCK) == 0) {
74 self.mutex.releaseSlow(state);
80 }75 }
81 }76 }
82 };77 };
8378
84 pub fn acquire(self: *Mutex) Held {79 pub fn acquire(self: *Mutex) Held {
85 // Try and speculatively grab the lock.80 // fast path close to SpinLock fast path
86 // If it fails, the state is either Locked or Sleeping81 if (@cmpxchgWeak(usize, &self.state, 0, MUTEX_LOCK, .Acquire, .Monotonic)) |current_state| {
87 // depending on if theres a thread stuck sleeping below.82 self.acquireSlow(current_state);
88 var state = @atomicRmw(State, &self.state, .Xchg, .Locked, .Acquire);83 }
89 if (state == .Unlocked)84 return Held{ .mutex = self };
90 return Held{ .mutex = self };85 }
9186
87 fn acquireSlow(self: *Mutex, current_state: usize) void {
88 var spin: usize = 0;
89 var state = current_state;
92 while (true) {90 while (true) {
93 // try and acquire the lock using cpu spinning on failure91
94 var spin: usize = 0;92 // try and acquire the lock if unlocked
95 while (spin < SPIN_CPU) : (spin += 1) {93 if ((state & MUTEX_LOCK) == 0) {
96 var value = @atomicLoad(State, &self.state, .Monotonic);94 state = @cmpxchgWeak(usize, &self.state, state, state | MUTEX_LOCK, .Acquire, .Monotonic) orelse return;
97 while (value == .Unlocked)95 continue;
98 value = @cmpxchgWeak(State, &self.state, .Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };96 }
99 SpinLock.yield(SPIN_CPU_COUNT);97
98 // spin only if the waiting queue isn't empty and when it hasn't spun too much already
99 if ((state & QUEUE_MASK) == 0 and spin < SPIN_CPU + SPIN_THREAD) {
100 if (spin < SPIN_CPU) {
101 std.SpinLock.yield(SPIN_CPU_COUNT);
102 } else {
103 std.os.sched_yield() catch std.time.sleep(0);
104 }
105 state = @atomicLoad(usize, &self.state, .Monotonic);
106 continue;
100 }107 }
101108
102 // try and acquire the lock using thread rescheduling on failure109 // thread should block, try and add this event to the waiting queue
103 spin = 0;110 var node = QueueNode{
104 while (spin < SPIN_THREAD) : (spin += 1) {111 .next = @intToPtr(?*QueueNode, state & QUEUE_MASK),
105 var value = @atomicLoad(State, &self.state, .Monotonic);112 .data = ResetEvent.init(),
106 while (value == .Unlocked)113 };
107 value = @cmpxchgWeak(State, &self.state, .Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };114 defer node.data.deinit();
108 std.os.sched_yield() catch std.time.sleep(1);115 const new_state = @ptrToInt(&node) | (state & ~QUEUE_MASK);
116 state = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Monotonic) orelse {
117 // node is in the queue, wait until a `held.release()` wakes us up.
118 _ = node.data.wait(null) catch unreachable;
119 spin = 0;
120 state = @atomicLoad(usize, &self.state, .Monotonic);
121 continue;
122 };
123 }
124 }
125
126 fn releaseSlow(self: *Mutex, current_state: usize) void {
127 // grab the QUEUE_LOCK in order to signal a waiting queue node's event.
128 var state = current_state;
129 while (true) {
130 if ((state & QUEUE_LOCK) != 0 or (state & QUEUE_MASK) == 0)
131 return;
132 state = @cmpxchgWeak(usize, &self.state, state, state | QUEUE_LOCK, .Acquire, .Monotonic) orelse break;
133 }
134
135 while (true) {
136 // barrier needed to observe incoming state changes
137 defer @fence(.Acquire);
138
139 // the mutex is currently locked. try to unset the QUEUE_LOCK and let the locker wake up the next node.
140 // avoids waking up multiple sleeping threads which try to acquire the lock again which increases contention.
141 if ((state & MUTEX_LOCK) != 0) {
142 state = @cmpxchgWeak(usize, &self.state, state, state & ~QUEUE_LOCK, .Release, .Monotonic) orelse return;
143 continue;
109 }144 }
110145
111 // failed to acquire the lock, go to sleep until woken up by `Held.release()`146 // try to pop the top node on the waiting queue stack to wake it up
112 if (@atomicRmw(State, &self.state, .Xchg, .Sleeping, .Acquire) == .Unlocked)147 // while at the same time unsetting the QUEUE_LOCK.
113 return Held{ .mutex = self };148 const node = @intToPtr(*QueueNode, state & QUEUE_MASK);
114 state = .Sleeping;149 const new_state = @ptrToInt(node.next) | (state & MUTEX_LOCK);
115 self.parker.park(@ptrCast(*const u32, &self.state), @enumToInt(State.Sleeping));150 state = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Monotonic) orelse {
151 _ = node.data.set(false);
152 return;
153 };
116 }154 }
117 }155 }
118 };156 };
lib/std/net.zig+2-2
...@@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts(...@@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts(
812 family: os.sa_family_t,812 family: os.sa_family_t,
813 port: u16,813 port: u16,
814) !void {814) !void {
815 const file = fs.File.openReadC("/etc/hosts") catch |err| switch (err) {815 const file = fs.openFileAbsoluteC("/etc/hosts", .{}) catch |err| switch (err) {
816 error.FileNotFound,816 error.FileNotFound,
817 error.NotDir,817 error.NotDir,
818 error.AccessDenied,818 error.AccessDenied,
...@@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {...@@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
1006 };1006 };
1007 errdefer rc.deinit();1007 errdefer rc.deinit();
10081008
1009 const file = fs.File.openReadC("/etc/resolv.conf") catch |err| switch (err) {1009 const file = fs.openFileAbsoluteC("/etc/resolv.conf", .{}) catch |err| switch (err) {
1010 error.FileNotFound,1010 error.FileNotFound,
1011 error.NotDir,1011 error.NotDir,
1012 error.AccessDenied,1012 error.AccessDenied,
lib/std/os.zig+13-6
...@@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e...@@ -798,7 +798,7 @@ pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, e
798 path_buf[search_path.len] = '/';798 path_buf[search_path.len] = '/';
799 mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice);799 mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice);
800 path_buf[search_path.len + file_slice.len + 1] = 0;800 path_buf[search_path.len + file_slice.len + 1] = 0;
801 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731801 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
802 err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp);802 err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp);
803 switch (err) {803 switch (err) {
804 error.AccessDenied => seen_eacces = true,804 error.AccessDenied => seen_eacces = true,
...@@ -834,7 +834,7 @@ pub fn execvpe(...@@ -834,7 +834,7 @@ pub fn execvpe(
834 @memcpy(arg_buf.ptr, arg.ptr, arg.len);834 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
835 arg_buf[arg.len] = 0;835 arg_buf[arg.len] = 0;
836836
837 // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731837 // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3770
838 argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr);838 argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr);
839 }839 }
840 argv_buf[argv_slice.len] = null;840 argv_buf[argv_slice.len] = null;
...@@ -842,7 +842,7 @@ pub fn execvpe(...@@ -842,7 +842,7 @@ pub fn execvpe(
842 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);842 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
843 defer freeNullDelimitedEnvMap(allocator, envp_buf);843 defer freeNullDelimitedEnvMap(allocator, envp_buf);
844844
845 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731845 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
846 const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr);846 const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr);
847847
848 return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr);848 return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr);
...@@ -863,12 +863,12 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std....@@ -863,12 +863,12 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.
863 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);863 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
864 env_buf[env_buf.len - 1] = 0;864 env_buf[env_buf.len - 1] = 0;
865865
866 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731866 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
867 envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr);867 envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr);
868 }868 }
869 assert(i == envp_count);869 assert(i == envp_count);
870 }870 }
871 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731871 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
872 assert(envp_buf[envp_count] == null);872 assert(envp_buf[envp_count] == null);
873 return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count];873 return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count];
874}874}
...@@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{...@@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{
1087};1087};
10881088
1089/// Delete a file name and possibly the file it refers to, based on an open directory handle.1089/// Delete a file name and possibly the file it refers to, based on an open directory handle.
1090/// Asserts that the path parameter has no null bytes.
1090pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {1091pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!void {
1092 if (std.debug.runtime_safety) for (file_path) |byte| assert(byte != 0);
1091 if (builtin.os == .windows) {1093 if (builtin.os == .windows) {
1092 const file_path_w = try windows.sliceToPrefixedFileW(file_path);1094 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
1093 return unlinkatW(dirfd, &file_path_w, flags);1095 return unlinkatW(dirfd, &file_path_w, flags);
...@@ -2026,7 +2028,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 {...@@ -2026,7 +2028,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 {
2026 }2028 }
2027}2029}
20282030
2029pub const FStatError = error{SystemResources} || UnexpectedError;2031pub const FStatError = error{
2032 SystemResources,
2033 AccessDenied,
2034} || UnexpectedError;
20302035
2031pub fn fstat(fd: fd_t) FStatError!Stat {2036pub fn fstat(fd: fd_t) FStatError!Stat {
2032 var stat: Stat = undefined;2037 var stat: Stat = undefined;
...@@ -2036,6 +2041,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {...@@ -2036,6 +2041,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
2036 EINVAL => unreachable,2041 EINVAL => unreachable,
2037 EBADF => unreachable, // Always a race condition.2042 EBADF => unreachable, // Always a race condition.
2038 ENOMEM => return error.SystemResources,2043 ENOMEM => return error.SystemResources,
2044 EACCES => return error.AccessDenied,
2039 else => |err| return unexpectedErrno(err),2045 else => |err| return unexpectedErrno(err),
2040 }2046 }
2041 }2047 }
...@@ -2045,6 +2051,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {...@@ -2045,6 +2051,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
2045 EINVAL => unreachable,2051 EINVAL => unreachable,
2046 EBADF => unreachable, // Always a race condition.2052 EBADF => unreachable, // Always a race condition.
2047 ENOMEM => return error.SystemResources,2053 ENOMEM => return error.SystemResources,
2054 EACCES => return error.AccessDenied,
2048 else => |err| return unexpectedErrno(err),2055 else => |err| return unexpectedErrno(err),
2049 }2056 }
2050}2057}
lib/std/os/bits/linux.zig+1
...@@ -9,6 +9,7 @@ pub usingnamespace switch (builtin.arch) {...@@ -9,6 +9,7 @@ pub usingnamespace switch (builtin.arch) {
9};9};
1010
11pub usingnamespace switch (builtin.arch) {11pub usingnamespace switch (builtin.arch) {
12 .i386 => @import("linux/i386.zig"),
12 .x86_64 => @import("linux/x86_64.zig"),13 .x86_64 => @import("linux/x86_64.zig"),
13 .aarch64 => @import("linux/arm64.zig"),14 .aarch64 => @import("linux/arm64.zig"),
14 .arm => @import("linux/arm-eabi.zig"),15 .arm => @import("linux/arm-eabi.zig"),
lib/std/os/bits/linux/arm-eabi.zig-1
...@@ -466,7 +466,6 @@ pub const MAP_LOCKED = 0x2000;...@@ -466,7 +466,6 @@ pub const MAP_LOCKED = 0x2000;
466/// don't check for reservations466/// don't check for reservations
467pub const MAP_NORESERVE = 0x4000;467pub const MAP_NORESERVE = 0x4000;
468468
469pub const VDSO_USEFUL = true;
470pub const VDSO_CGT_SYM = "__vdso_clock_gettime";469pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
471pub const VDSO_CGT_VER = "LINUX_2.6";470pub const VDSO_CGT_VER = "LINUX_2.6";
472471
lib/std/os/bits/linux/arm64.zig-1
...@@ -358,7 +358,6 @@ pub const MAP_LOCKED = 0x2000;...@@ -358,7 +358,6 @@ pub const MAP_LOCKED = 0x2000;
358/// don't check for reservations358/// don't check for reservations
359pub const MAP_NORESERVE = 0x4000;359pub const MAP_NORESERVE = 0x4000;
360360
361pub const VDSO_USEFUL = true;
362pub const VDSO_CGT_SYM = "__kernel_clock_gettime";361pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
363pub const VDSO_CGT_VER = "LINUX_2.6.39";362pub const VDSO_CGT_VER = "LINUX_2.6.39";
364363
lib/std/os/bits/linux/i386.zig created+642
...@@ -0,0 +1,642 @@
1// i386-specific declarations that are intended to be imported into the POSIX namespace.
2// This does include Linux-only APIs.
3
4const std = @import("../../../std.zig");
5const linux = std.os.linux;
6const socklen_t = linux.socklen_t;
7const iovec = linux.iovec;
8const iovec_const = linux.iovec_const;
9const uid_t = linux.uid_t;
10const gid_t = linux.gid_t;
11const stack_t = linux.stack_t;
12const sigset_t = linux.sigset_t;
13
14pub const SYS_restart_syscall = 0;
15pub const SYS_exit = 1;
16pub const SYS_fork = 2;
17pub const SYS_read = 3;
18pub const SYS_write = 4;
19pub const SYS_open = 5;
20pub const SYS_close = 6;
21pub const SYS_waitpid = 7;
22pub const SYS_creat = 8;
23pub const SYS_link = 9;
24pub const SYS_unlink = 10;
25pub const SYS_execve = 11;
26pub const SYS_chdir = 12;
27pub const SYS_time = 13;
28pub const SYS_mknod = 14;
29pub const SYS_chmod = 15;
30pub const SYS_lchown = 16;
31pub const SYS_break = 17;
32pub const SYS_oldstat = 18;
33pub const SYS_lseek = 19;
34pub const SYS_getpid = 20;
35pub const SYS_mount = 21;
36pub const SYS_umount = 22;
37pub const SYS_setuid = 23;
38pub const SYS_getuid = 24;
39pub const SYS_stime = 25;
40pub const SYS_ptrace = 26;
41pub const SYS_alarm = 27;
42pub const SYS_oldfstat = 28;
43pub const SYS_pause = 29;
44pub const SYS_utime = 30;
45pub const SYS_stty = 31;
46pub const SYS_gtty = 32;
47pub const SYS_access = 33;
48pub const SYS_nice = 34;
49pub const SYS_ftime = 35;
50pub const SYS_sync = 36;
51pub const SYS_kill = 37;
52pub const SYS_rename = 38;
53pub const SYS_mkdir = 39;
54pub const SYS_rmdir = 40;
55pub const SYS_dup = 41;
56pub const SYS_pipe = 42;
57pub const SYS_times = 43;
58pub const SYS_prof = 44;
59pub const SYS_brk = 45;
60pub const SYS_setgid = 46;
61pub const SYS_getgid = 47;
62pub const SYS_signal = 48;
63pub const SYS_geteuid = 49;
64pub const SYS_getegid = 50;
65pub const SYS_acct = 51;
66pub const SYS_umount2 = 52;
67pub const SYS_lock = 53;
68pub const SYS_ioctl = 54;
69pub const SYS_fcntl = 55;
70pub const SYS_mpx = 56;
71pub const SYS_setpgid = 57;
72pub const SYS_ulimit = 58;
73pub const SYS_oldolduname = 59;
74pub const SYS_umask = 60;
75pub const SYS_chroot = 61;
76pub const SYS_ustat = 62;
77pub const SYS_dup2 = 63;
78pub const SYS_getppid = 64;
79pub const SYS_getpgrp = 65;
80pub const SYS_setsid = 66;
81pub const SYS_sigaction = 67;
82pub const SYS_sgetmask = 68;
83pub const SYS_ssetmask = 69;
84pub const SYS_setreuid = 70;
85pub const SYS_setregid = 71;
86pub const SYS_sigsuspend = 72;
87pub const SYS_sigpending = 73;
88pub const SYS_sethostname = 74;
89pub const SYS_setrlimit = 75;
90pub const SYS_getrlimit = 76;
91pub const SYS_getrusage = 77;
92pub const SYS_gettimeofday = 78;
93pub const SYS_settimeofday = 79;
94pub const SYS_getgroups = 80;
95pub const SYS_setgroups = 81;
96pub const SYS_select = 82;
97pub const SYS_symlink = 83;
98pub const SYS_oldlstat = 84;
99pub const SYS_readlink = 85;
100pub const SYS_uselib = 86;
101pub const SYS_swapon = 87;
102pub const SYS_reboot = 88;
103pub const SYS_readdir = 89;
104pub const SYS_mmap = 90;
105pub const SYS_munmap = 91;
106pub const SYS_truncate = 92;
107pub const SYS_ftruncate = 93;
108pub const SYS_fchmod = 94;
109pub const SYS_fchown = 95;
110pub const SYS_getpriority = 96;
111pub const SYS_setpriority = 97;
112pub const SYS_profil = 98;
113pub const SYS_statfs = 99;
114pub const SYS_fstatfs = 100;
115pub const SYS_ioperm = 101;
116pub const SYS_socketcall = 102;
117pub const SYS_syslog = 103;
118pub const SYS_setitimer = 104;
119pub const SYS_getitimer = 105;
120pub const SYS_stat = 106;
121pub const SYS_lstat = 107;
122pub const SYS_fstat = 108;
123pub const SYS_olduname = 109;
124pub const SYS_iopl = 110;
125pub const SYS_vhangup = 111;
126pub const SYS_idle = 112;
127pub const SYS_vm86old = 113;
128pub const SYS_wait4 = 114;
129pub const SYS_swapoff = 115;
130pub const SYS_sysinfo = 116;
131pub const SYS_ipc = 117;
132pub const SYS_fsync = 118;
133pub const SYS_sigreturn = 119;
134pub const SYS_clone = 120;
135pub const SYS_setdomainname = 121;
136pub const SYS_uname = 122;
137pub const SYS_modify_ldt = 123;
138pub const SYS_adjtimex = 124;
139pub const SYS_mprotect = 125;
140pub const SYS_sigprocmask = 126;
141pub const SYS_create_module = 127;
142pub const SYS_init_module = 128;
143pub const SYS_delete_module = 129;
144pub const SYS_get_kernel_syms = 130;
145pub const SYS_quotactl = 131;
146pub const SYS_getpgid = 132;
147pub const SYS_fchdir = 133;
148pub const SYS_bdflush = 134;
149pub const SYS_sysfs = 135;
150pub const SYS_personality = 136;
151pub const SYS_afs_syscall = 137;
152pub const SYS_setfsuid = 138;
153pub const SYS_setfsgid = 139;
154pub const SYS__llseek = 140;
155pub const SYS_getdents = 141;
156pub const SYS__newselect = 142;
157pub const SYS_flock = 143;
158pub const SYS_msync = 144;
159pub const SYS_readv = 145;
160pub const SYS_writev = 146;
161pub const SYS_getsid = 147;
162pub const SYS_fdatasync = 148;
163pub const SYS__sysctl = 149;
164pub const SYS_mlock = 150;
165pub const SYS_munlock = 151;
166pub const SYS_mlockall = 152;
167pub const SYS_munlockall = 153;
168pub const SYS_sched_setparam = 154;
169pub const SYS_sched_getparam = 155;
170pub const SYS_sched_setscheduler = 156;
171pub const SYS_sched_getscheduler = 157;
172pub const SYS_sched_yield = 158;
173pub const SYS_sched_get_priority_max = 159;
174pub const SYS_sched_get_priority_min = 160;
175pub const SYS_sched_rr_get_interval = 161;
176pub const SYS_nanosleep = 162;
177pub const SYS_mremap = 163;
178pub const SYS_setresuid = 164;
179pub const SYS_getresuid = 165;
180pub const SYS_vm86 = 166;
181pub const SYS_query_module = 167;
182pub const SYS_poll = 168;
183pub const SYS_nfsservctl = 169;
184pub const SYS_setresgid = 170;
185pub const SYS_getresgid = 171;
186pub const SYS_prctl = 172;
187pub const SYS_rt_sigreturn = 173;
188pub const SYS_rt_sigaction = 174;
189pub const SYS_rt_sigprocmask = 175;
190pub const SYS_rt_sigpending = 176;
191pub const SYS_rt_sigtimedwait = 177;
192pub const SYS_rt_sigqueueinfo = 178;
193pub const SYS_rt_sigsuspend = 179;
194pub const SYS_pread64 = 180;
195pub const SYS_pwrite64 = 181;
196pub const SYS_chown = 182;
197pub const SYS_getcwd = 183;
198pub const SYS_capget = 184;
199pub const SYS_capset = 185;
200pub const SYS_sigaltstack = 186;
201pub const SYS_sendfile = 187;
202pub const SYS_getpmsg = 188;
203pub const SYS_putpmsg = 189;
204pub const SYS_vfork = 190;
205pub const SYS_ugetrlimit = 191;
206pub const SYS_mmap2 = 192;
207pub const SYS_truncate64 = 193;
208pub const SYS_ftruncate64 = 194;
209pub const SYS_stat64 = 195;
210pub const SYS_lstat64 = 196;
211pub const SYS_fstat64 = 197;
212pub const SYS_lchown32 = 198;
213pub const SYS_getuid32 = 199;
214pub const SYS_getgid32 = 200;
215pub const SYS_geteuid32 = 201;
216pub const SYS_getegid32 = 202;
217pub const SYS_setreuid32 = 203;
218pub const SYS_setregid32 = 204;
219pub const SYS_getgroups32 = 205;
220pub const SYS_setgroups32 = 206;
221pub const SYS_fchown32 = 207;
222pub const SYS_setresuid32 = 208;
223pub const SYS_getresuid32 = 209;
224pub const SYS_setresgid32 = 210;
225pub const SYS_getresgid32 = 211;
226pub const SYS_chown32 = 212;
227pub const SYS_setuid32 = 213;
228pub const SYS_setgid32 = 214;
229pub const SYS_setfsuid32 = 215;
230pub const SYS_setfsgid32 = 216;
231pub const SYS_pivot_root = 217;
232pub const SYS_mincore = 218;
233pub const SYS_madvise = 219;
234pub const SYS_getdents64 = 220;
235pub const SYS_fcntl64 = 221;
236pub const SYS_gettid = 224;
237pub const SYS_readahead = 225;
238pub const SYS_setxattr = 226;
239pub const SYS_lsetxattr = 227;
240pub const SYS_fsetxattr = 228;
241pub const SYS_getxattr = 229;
242pub const SYS_lgetxattr = 230;
243pub const SYS_fgetxattr = 231;
244pub const SYS_listxattr = 232;
245pub const SYS_llistxattr = 233;
246pub const SYS_flistxattr = 234;
247pub const SYS_removexattr = 235;
248pub const SYS_lremovexattr = 236;
249pub const SYS_fremovexattr = 237;
250pub const SYS_tkill = 238;
251pub const SYS_sendfile64 = 239;
252pub const SYS_futex = 240;
253pub const SYS_sched_setaffinity = 241;
254pub const SYS_sched_getaffinity = 242;
255pub const SYS_set_thread_area = 243;
256pub const SYS_get_thread_area = 244;
257pub const SYS_io_setup = 245;
258pub const SYS_io_destroy = 246;
259pub const SYS_io_getevents = 247;
260pub const SYS_io_submit = 248;
261pub const SYS_io_cancel = 249;
262pub const SYS_fadvise64 = 250;
263pub const SYS_exit_group = 252;
264pub const SYS_lookup_dcookie = 253;
265pub const SYS_epoll_create = 254;
266pub const SYS_epoll_ctl = 255;
267pub const SYS_epoll_wait = 256;
268pub const SYS_remap_file_pages = 257;
269pub const SYS_set_tid_address = 258;
270pub const SYS_timer_create = 259;
271pub const SYS_timer_settime = SYS_timer_create + 1;
272pub const SYS_timer_gettime = SYS_timer_create + 2;
273pub const SYS_timer_getoverrun = SYS_timer_create + 3;
274pub const SYS_timer_delete = SYS_timer_create + 4;
275pub const SYS_clock_settime = SYS_timer_create + 5;
276pub const SYS_clock_gettime = SYS_timer_create + 6;
277pub const SYS_clock_getres = SYS_timer_create + 7;
278pub const SYS_clock_nanosleep = SYS_timer_create + 8;
279pub const SYS_statfs64 = 268;
280pub const SYS_fstatfs64 = 269;
281pub const SYS_tgkill = 270;
282pub const SYS_utimes = 271;
283pub const SYS_fadvise64_64 = 272;
284pub const SYS_vserver = 273;
285pub const SYS_mbind = 274;
286pub const SYS_get_mempolicy = 275;
287pub const SYS_set_mempolicy = 276;
288pub const SYS_mq_open = 277;
289pub const SYS_mq_unlink = SYS_mq_open + 1;
290pub const SYS_mq_timedsend = SYS_mq_open + 2;
291pub const SYS_mq_timedreceive = SYS_mq_open + 3;
292pub const SYS_mq_notify = SYS_mq_open + 4;
293pub const SYS_mq_getsetattr = SYS_mq_open + 5;
294pub const SYS_kexec_load = 283;
295pub const SYS_waitid = 284;
296pub const SYS_add_key = 286;
297pub const SYS_request_key = 287;
298pub const SYS_keyctl = 288;
299pub const SYS_ioprio_set = 289;
300pub const SYS_ioprio_get = 290;
301pub const SYS_inotify_init = 291;
302pub const SYS_inotify_add_watch = 292;
303pub const SYS_inotify_rm_watch = 293;
304pub const SYS_migrate_pages = 294;
305pub const SYS_openat = 295;
306pub const SYS_mkdirat = 296;
307pub const SYS_mknodat = 297;
308pub const SYS_fchownat = 298;
309pub const SYS_futimesat = 299;
310pub const SYS_fstatat64 = 300;
311pub const SYS_unlinkat = 301;
312pub const SYS_renameat = 302;
313pub const SYS_linkat = 303;
314pub const SYS_symlinkat = 304;
315pub const SYS_readlinkat = 305;
316pub const SYS_fchmodat = 306;
317pub const SYS_faccessat = 307;
318pub const SYS_pselect6 = 308;
319pub const SYS_ppoll = 309;
320pub const SYS_unshare = 310;
321pub const SYS_set_robust_list = 311;
322pub const SYS_get_robust_list = 312;
323pub const SYS_splice = 313;
324pub const SYS_sync_file_range = 314;
325pub const SYS_tee = 315;
326pub const SYS_vmsplice = 316;
327pub const SYS_move_pages = 317;
328pub const SYS_getcpu = 318;
329pub const SYS_epoll_pwait = 319;
330pub const SYS_utimensat = 320;
331pub const SYS_signalfd = 321;
332pub const SYS_timerfd_create = 322;
333pub const SYS_eventfd = 323;
334pub const SYS_fallocate = 324;
335pub const SYS_timerfd_settime = 325;
336pub const SYS_timerfd_gettime = 326;
337pub const SYS_signalfd4 = 327;
338pub const SYS_eventfd2 = 328;
339pub const SYS_epoll_create1 = 329;
340pub const SYS_dup3 = 330;
341pub const SYS_pipe2 = 331;
342pub const SYS_inotify_init1 = 332;
343pub const SYS_preadv = 333;
344pub const SYS_pwritev = 334;
345pub const SYS_rt_tgsigqueueinfo = 335;
346pub const SYS_perf_event_open = 336;
347pub const SYS_recvmmsg = 337;
348pub const SYS_fanotify_init = 338;
349pub const SYS_fanotify_mark = 339;
350pub const SYS_prlimit64 = 340;
351pub const SYS_name_to_handle_at = 341;
352pub const SYS_open_by_handle_at = 342;
353pub const SYS_clock_adjtime = 343;
354pub const SYS_syncfs = 344;
355pub const SYS_sendmmsg = 345;
356pub const SYS_setns = 346;
357pub const SYS_process_vm_readv = 347;
358pub const SYS_process_vm_writev = 348;
359pub const SYS_kcmp = 349;
360pub const SYS_finit_module = 350;
361pub const SYS_sched_setattr = 351;
362pub const SYS_sched_getattr = 352;
363pub const SYS_renameat2 = 353;
364pub const SYS_seccomp = 354;
365pub const SYS_getrandom = 355;
366pub const SYS_memfd_create = 356;
367pub const SYS_bpf = 357;
368pub const SYS_execveat = 358;
369pub const SYS_socket = 359;
370pub const SYS_socketpair = 360;
371pub const SYS_bind = 361;
372pub const SYS_connect = 362;
373pub const SYS_listen = 363;
374pub const SYS_accept4 = 364;
375pub const SYS_getsockopt = 365;
376pub const SYS_setsockopt = 366;
377pub const SYS_getsockname = 367;
378pub const SYS_getpeername = 368;
379pub const SYS_sendto = 369;
380pub const SYS_sendmsg = 370;
381pub const SYS_recvfrom = 371;
382pub const SYS_recvmsg = 372;
383pub const SYS_shutdown = 373;
384pub const SYS_userfaultfd = 374;
385pub const SYS_membarrier = 375;
386pub const SYS_mlock2 = 376;
387pub const SYS_copy_file_range = 377;
388pub const SYS_preadv2 = 378;
389pub const SYS_pwritev2 = 379;
390pub const SYS_pkey_mprotect = 380;
391pub const SYS_pkey_alloc = 381;
392pub const SYS_pkey_free = 382;
393pub const SYS_statx = 383;
394pub const SYS_arch_prctl = 384;
395pub const SYS_io_pgetevents = 385;
396pub const SYS_rseq = 386;
397pub const SYS_semget = 393;
398pub const SYS_semctl = 394;
399pub const SYS_shmget = 395;
400pub const SYS_shmctl = 396;
401pub const SYS_shmat = 397;
402pub const SYS_shmdt = 398;
403pub const SYS_msgget = 399;
404pub const SYS_msgsnd = 400;
405pub const SYS_msgrcv = 401;
406pub const SYS_msgctl = 402;
407pub const SYS_clock_gettime64 = 403;
408pub const SYS_clock_settime64 = 404;
409pub const SYS_clock_adjtime64 = 405;
410pub const SYS_clock_getres_time64 = 406;
411pub const SYS_clock_nanosleep_time64 = 407;
412pub const SYS_timer_gettime64 = 408;
413pub const SYS_timer_settime64 = 409;
414pub const SYS_timerfd_gettime64 = 410;
415pub const SYS_timerfd_settime64 = 411;
416pub const SYS_utimensat_time64 = 412;
417pub const SYS_pselect6_time64 = 413;
418pub const SYS_ppoll_time64 = 414;
419pub const SYS_io_pgetevents_time64 = 416;
420pub const SYS_recvmmsg_time64 = 417;
421pub const SYS_mq_timedsend_time64 = 418;
422pub const SYS_mq_timedreceive_time64 = 419;
423pub const SYS_semtimedop_time64 = 420;
424pub const SYS_rt_sigtimedwait_time64 = 421;
425pub const SYS_futex_time64 = 422;
426pub const SYS_sched_rr_get_interval_time64 = 423;
427pub const SYS_pidfd_send_signal = 424;
428pub const SYS_io_uring_setup = 425;
429pub const SYS_io_uring_enter = 426;
430pub const SYS_io_uring_register = 427;
431pub const SYS_open_tree = 428;
432pub const SYS_move_mount = 429;
433pub const SYS_fsopen = 430;
434pub const SYS_fsconfig = 431;
435pub const SYS_fsmount = 432;
436pub const SYS_fspick = 433;
437
438pub const O_CREAT = 0o100;
439pub const O_EXCL = 0o200;
440pub const O_NOCTTY = 0o400;
441pub const O_TRUNC = 0o1000;
442pub const O_APPEND = 0o2000;
443pub const O_NONBLOCK = 0o4000;
444pub const O_DSYNC = 0o10000;
445pub const O_SYNC = 0o4010000;
446pub const O_RSYNC = 0o4010000;
447pub const O_DIRECTORY = 0o200000;
448pub const O_NOFOLLOW = 0o400000;
449pub const O_CLOEXEC = 0o2000000;
450
451pub const O_ASYNC = 0o20000;
452pub const O_DIRECT = 0o40000;
453pub const O_LARGEFILE = 0o100000;
454pub const O_NOATIME = 0o1000000;
455pub const O_PATH = 0o10000000;
456pub const O_TMPFILE = 0o20200000;
457pub const O_NDELAY = O_NONBLOCK;
458
459pub const F_DUPFD = 0;
460pub const F_GETFD = 1;
461pub const F_SETFD = 2;
462pub const F_GETFL = 3;
463pub const F_SETFL = 4;
464
465pub const F_SETOWN = 8;
466pub const F_GETOWN = 9;
467pub const F_SETSIG = 10;
468pub const F_GETSIG = 11;
469
470pub const F_GETLK = 12;
471pub const F_SETLK = 13;
472pub const F_SETLKW = 14;
473
474pub const F_SETOWN_EX = 15;
475pub const F_GETOWN_EX = 16;
476
477pub const F_GETOWNER_UIDS = 17;
478
479pub const MAP_NORESERVE = 0x4000;
480pub const MAP_GROWSDOWN = 0x0100;
481pub const MAP_DENYWRITE = 0x0800;
482pub const MAP_EXECUTABLE = 0x1000;
483pub const MAP_LOCKED = 0x2000;
484pub const MAP_32BIT = 0x40;
485
486pub const MMAP2_UNIT = 4096;
487
488pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
489pub const VDSO_CGT_VER = "LINUX_2.6";
490
491pub const msghdr = extern struct {
492 msg_name: ?*sockaddr,
493 msg_namelen: socklen_t,
494 msg_iov: [*]iovec,
495 msg_iovlen: i32,
496 msg_control: ?*c_void,
497 msg_controllen: socklen_t,
498 msg_flags: i32,
499};
500
501pub const msghdr_const = extern struct {
502 msg_name: ?*const sockaddr,
503 msg_namelen: socklen_t,
504 msg_iov: [*]iovec_const,
505 msg_iovlen: i32,
506 msg_control: ?*c_void,
507 msg_controllen: socklen_t,
508 msg_flags: i32,
509};
510
511pub const blksize_t = i32;
512pub const nlink_t = u32;
513pub const time_t = isize;
514pub const mode_t = u32;
515pub const off_t = i64;
516pub const ino_t = u64;
517pub const dev_t = u64;
518pub const blkcnt_t = i64;
519
520/// Renamed to Stat to not conflict with the stat function.
521/// atime, mtime, and ctime have functions to return `timespec`,
522/// because although this is a POSIX API, the layout and names of
523/// the structs are inconsistent across operating systems, and
524/// in C, macros are used to hide the differences. Here we use
525/// methods to accomplish this.
526pub const Stat = extern struct {
527 dev: dev_t,
528 __dev_padding: u32,
529 __ino_truncated: u32,
530 mode: mode_t,
531 nlink: nlink_t,
532 uid: uid_t,
533 gid: gid_t,
534 rdev: dev_t,
535 __rdev_padding: u32,
536 size: off_t,
537 blksize: blksize_t,
538 blocks: blkcnt_t,
539 atim: timespec,
540 mtim: timespec,
541 ctim: timespec,
542 ino: ino_t,
543
544 pub fn atime(self: Stat) timespec {
545 return self.atim;
546 }
547
548 pub fn mtime(self: Stat) timespec {
549 return self.mtim;
550 }
551
552 pub fn ctime(self: Stat) timespec {
553 return self.ctim;
554 }
555};
556
557pub const timespec = extern struct {
558 tv_sec: i32,
559 tv_nsec: i32,
560};
561
562pub const timeval = extern struct {
563 tv_sec: i32,
564 tv_usec: i32,
565};
566
567pub const timezone = extern struct {
568 tz_minuteswest: i32,
569 tz_dsttime: i32,
570};
571
572pub const mcontext_t = extern struct {
573 gregs: [19]usize,
574 fpregs: [*]u8,
575 oldmask: usize,
576 cr2: usize,
577};
578
579pub const REG_GS = 0;
580pub const REG_FS = 1;
581pub const REG_ES = 2;
582pub const REG_DS = 3;
583pub const REG_EDI = 4;
584pub const REG_ESI = 5;
585pub const REG_EBP = 6;
586pub const REG_ESP = 7;
587pub const REG_EBX = 8;
588pub const REG_EDX = 9;
589pub const REG_ECX = 10;
590pub const REG_EAX = 11;
591pub const REG_TRAPNO = 12;
592pub const REG_ERR = 13;
593pub const REG_EIP = 14;
594pub const REG_CS = 15;
595pub const REG_EFL = 16;
596pub const REG_UESP = 17;
597pub const REG_SS = 18;
598
599pub const ucontext_t = extern struct {
600 flags: usize,
601 link: *ucontext_t,
602 stack: stack_t,
603 mcontext: mcontext_t,
604 sigmask: sigset_t,
605 regspace: [64]u64,
606};
607
608pub const Elf_Symndx = u32;
609
610pub const user_desc = packed struct {
611 entry_number: u32,
612 base_addr: u32,
613 limit: u32,
614 seg_32bit: u1,
615 contents: u2,
616 read_exec_only: u1,
617 limit_in_pages: u1,
618 seg_not_present: u1,
619 useable: u1,
620};
621
622// socketcall() call numbers
623pub const SC_socket = 1;
624pub const SC_bind = 2;
625pub const SC_connect = 3;
626pub const SC_listen = 4;
627pub const SC_accept = 5;
628pub const SC_getsockname = 6;
629pub const SC_getpeername = 7;
630pub const SC_socketpair = 8;
631pub const SC_send = 9;
632pub const SC_recv = 10;
633pub const SC_sendto = 11;
634pub const SC_recvfrom = 12;
635pub const SC_shutdown = 13;
636pub const SC_setsockopt = 14;
637pub const SC_getsockopt = 15;
638pub const SC_sendmsg = 16;
639pub const SC_recvmsg = 17;
640pub const SC_accept4 = 18;
641pub const SC_recvmmsg = 19;
642pub const SC_sendmmsg = 20;
lib/std/os/bits/linux/mipsel.zig-1
...@@ -454,7 +454,6 @@ pub const SO_PEERSEC = 30;...@@ -454,7 +454,6 @@ pub const SO_PEERSEC = 30;
454pub const SO_SNDBUFFORCE = 31;454pub const SO_SNDBUFFORCE = 31;
455pub const SO_RCVBUFFORCE = 33;455pub const SO_RCVBUFFORCE = 33;
456456
457pub const VDSO_USEFUL = true;
458pub const VDSO_CGT_SYM = "__kernel_clock_gettime";457pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
459pub const VDSO_CGT_VER = "LINUX_2.6.39";458pub const VDSO_CGT_VER = "LINUX_2.6.39";
460459
lib/std/os/bits/linux/x86_64.zig-1
...@@ -420,7 +420,6 @@ pub const MAP_LOCKED = 0x2000;...@@ -420,7 +420,6 @@ pub const MAP_LOCKED = 0x2000;
420/// don't check for reservations420/// don't check for reservations
421pub const MAP_NORESERVE = 0x4000;421pub const MAP_NORESERVE = 0x4000;
422422
423pub const VDSO_USEFUL = true;
424pub const VDSO_CGT_SYM = "__vdso_clock_gettime";423pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
425pub const VDSO_CGT_VER = "LINUX_2.6";424pub const VDSO_CGT_VER = "LINUX_2.6";
426pub const VDSO_GETCPU_SYM = "__vdso_getcpu";425pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
lib/std/os/linux.zig+49
...@@ -14,6 +14,7 @@ const vdso = @import("linux/vdso.zig");...@@ -14,6 +14,7 @@ const vdso = @import("linux/vdso.zig");
14const dl = @import("../dynamic_library.zig");14const dl = @import("../dynamic_library.zig");
1515
16pub usingnamespace switch (builtin.arch) {16pub usingnamespace switch (builtin.arch) {
17 .i386 => @import("linux/i386.zig"),
17 .x86_64 => @import("linux/x86_64.zig"),18 .x86_64 => @import("linux/x86_64.zig"),
18 .aarch64 => @import("linux/arm64.zig"),19 .aarch64 => @import("linux/arm64.zig"),
19 .arm => @import("linux/arm-eabi.zig"),20 .arm => @import("linux/arm-eabi.zig"),
...@@ -743,26 +744,44 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool {...@@ -743,26 +744,44 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool {
743}744}
744745
745pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {746pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
747 if (builtin.arch == .i386) {
748 return socketcall(SC_getsockname, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) });
749 }
746 return syscall3(SYS_getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));750 return syscall3(SYS_getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));
747}751}
748752
749pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {753pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
754 if (builtin.arch == .i386) {
755 return socketcall(SC_getpeername, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len) });
756 }
750 return syscall3(SYS_getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));757 return syscall3(SYS_getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));
751}758}
752759
753pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {760pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
761 if (builtin.arch == .i386) {
762 return socketcall(SC_socket, &[3]usize{ domain, socket_type, protocol });
763 }
754 return syscall3(SYS_socket, domain, socket_type, protocol);764 return syscall3(SYS_socket, domain, socket_type, protocol);
755}765}
756766
757pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {767pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
768 if (builtin.arch == .i386) {
769 return socketcall(SC_setsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen) });
770 }
758 return syscall5(SYS_setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));771 return syscall5(SYS_setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
759}772}
760773
761pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {774pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
775 if (builtin.arch == .i386) {
776 return socketcall(SC_getsockopt, &[5]usize{ @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen) });
777 }
762 return syscall5(SYS_getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));778 return syscall5(SYS_getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
763}779}
764780
765pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {781pub fn sendmsg(fd: i32, msg: *msghdr_const, flags: u32) usize {
782 if (builtin.arch == .i386) {
783 return socketcall(SC_sendmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });
784 }
766 return syscall3(SYS_sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);785 return syscall3(SYS_sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);
767}786}
768787
...@@ -807,42 +826,72 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize...@@ -807,42 +826,72 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
807}826}
808827
809pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {828pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
829 if (builtin.arch == .i386) {
830 return socketcall(SC_connect, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len });
831 }
810 return syscall3(SYS_connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len);832 return syscall3(SYS_connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len);
811}833}
812834
813pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {835pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
836 if (builtin.arch == .i386) {
837 return socketcall(SC_recvmsg, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags });
838 }
814 return syscall3(SYS_recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);839 return syscall3(SYS_recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);
815}840}
816841
817pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {842pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
843 if (builtin.arch == .i386) {
844 return socketcall(SC_recvfrom, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen) });
845 }
818 return syscall6(SYS_recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));846 return syscall6(SYS_recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
819}847}
820848
821pub fn shutdown(fd: i32, how: i32) usize {849pub fn shutdown(fd: i32, how: i32) usize {
850 if (builtin.arch == .i386) {
851 return socketcall(SC_shutdown, &[2]usize{ @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)) });
852 }
822 return syscall2(SYS_shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)));853 return syscall2(SYS_shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)));
823}854}
824855
825pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {856pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
857 if (builtin.arch == .i386) {
858 return socketcall(SC_bind, &[3]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len) });
859 }
826 return syscall3(SYS_bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len));860 return syscall3(SYS_bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len));
827}861}
828862
829pub fn listen(fd: i32, backlog: u32) usize {863pub fn listen(fd: i32, backlog: u32) usize {
864 if (builtin.arch == .i386) {
865 return socketcall(SC_listen, &[2]usize{ @bitCast(usize, @as(isize, fd)), backlog });
866 }
830 return syscall2(SYS_listen, @bitCast(usize, @as(isize, fd)), backlog);867 return syscall2(SYS_listen, @bitCast(usize, @as(isize, fd)), backlog);
831}868}
832869
833pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {870pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
871 if (builtin.arch == .i386) {
872 return socketcall(SC_sendto, &[6]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen) });
873 }
834 return syscall6(SYS_sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));874 return syscall6(SYS_sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
835}875}
836876
837pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {877pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
878 if (builtin.arch == .i386) {
879 return socketcall(SC_socketpair, &[4]usize{ @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]) });
880 }
838 return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));881 return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
839}882}
840883
841pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {884pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
885 if (builtin.arch == .i386) {
886 return socketcall(SC_accept, &[4]usize{ fd, addr, len, 0 });
887 }
842 return accept4(fd, addr, len, 0);888 return accept4(fd, addr, len, 0);
843}889}
844890
845pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {891pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
892 if (builtin.arch == .i386) {
893 return socketcall(SC_accept4, &[4]usize{ @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags });
894 }
846 return syscall4(SYS_accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags);895 return syscall4(SYS_accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags);
847}896}
848897
lib/std/os/linux/i386.zig created+119
...@@ -0,0 +1,119 @@
1usingnamespace @import("../bits.zig");
2
3pub fn syscall0(number: usize) usize {
4 return asm volatile ("int $0x80"
5 : [ret] "={eax}" (-> usize)
6 : [number] "{eax}" (number)
7 : "memory"
8 );
9}
10
11pub fn syscall1(number: usize, arg1: usize) usize {
12 return asm volatile ("int $0x80"
13 : [ret] "={eax}" (-> usize)
14 : [number] "{eax}" (number),
15 [arg1] "{ebx}" (arg1)
16 : "memory"
17 );
18}
19
20pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
21 return asm volatile ("int $0x80"
22 : [ret] "={eax}" (-> usize)
23 : [number] "{eax}" (number),
24 [arg1] "{ebx}" (arg1),
25 [arg2] "{ecx}" (arg2)
26 : "memory"
27 );
28}
29
30pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
31 return asm volatile ("int $0x80"
32 : [ret] "={eax}" (-> usize)
33 : [number] "{eax}" (number),
34 [arg1] "{ebx}" (arg1),
35 [arg2] "{ecx}" (arg2),
36 [arg3] "{edx}" (arg3)
37 : "memory"
38 );
39}
40
41pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
42 return asm volatile ("int $0x80"
43 : [ret] "={eax}" (-> usize)
44 : [number] "{eax}" (number),
45 [arg1] "{ebx}" (arg1),
46 [arg2] "{ecx}" (arg2),
47 [arg3] "{edx}" (arg3),
48 [arg4] "{esi}" (arg4)
49 : "memory"
50 );
51}
52
53pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
54 return asm volatile ("int $0x80"
55 : [ret] "={eax}" (-> usize)
56 : [number] "{eax}" (number),
57 [arg1] "{ebx}" (arg1),
58 [arg2] "{ecx}" (arg2),
59 [arg3] "{edx}" (arg3),
60 [arg4] "{esi}" (arg4),
61 [arg5] "{edi}" (arg5)
62 : "memory"
63 );
64}
65
66pub fn syscall6(
67 number: usize,
68 arg1: usize,
69 arg2: usize,
70 arg3: usize,
71 arg4: usize,
72 arg5: usize,
73 arg6: usize,
74) usize {
75 return asm volatile (
76 \\ push %%ebp
77 \\ mov %[arg6], %%ebp
78 \\ int $0x80
79 \\ pop %%ebp
80 : [ret] "={eax}" (-> usize)
81 : [number] "{eax}" (number),
82 [arg1] "{ebx}" (arg1),
83 [arg2] "{ecx}" (arg2),
84 [arg3] "{edx}" (arg3),
85 [arg4] "{esi}" (arg4),
86 [arg5] "{edi}" (arg5),
87 [arg6] "rm" (arg6)
88 : "memory"
89 );
90}
91
92pub fn socketcall(call: usize, args: [*]usize) usize {
93 return asm volatile ("int $0x80"
94 : [ret] "={eax}" (-> usize)
95 : [number] "{eax}" (@as(usize, SYS_socketcall)),
96 [arg1] "{ebx}" (call),
97 [arg2] "{ecx}" (@ptrToInt(args))
98 : "memory"
99 );
100}
101
102/// This matches the libc clone function.
103pub extern fn clone(func: extern fn (arg: usize) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
104
105pub nakedcc fn restore() void {
106 return asm volatile ("int $0x80"
107 :
108 : [number] "{eax}" (@as(usize, SYS_sigreturn))
109 : "memory"
110 );
111}
112
113pub nakedcc fn restore_rt() void {
114 return asm volatile ("int $0x80"
115 :
116 : [number] "{eax}" (@as(usize, SYS_rt_sigreturn))
117 : "memory"
118 );
119}
lib/std/os/linux/test.zig+3-4
...@@ -4,6 +4,7 @@ const linux = std.os.linux;...@@ -4,6 +4,7 @@ const linux = std.os.linux;
4const mem = std.mem;4const mem = std.mem;
5const elf = std.elf;5const elf = std.elf;
6const expect = std.testing.expect;6const expect = std.testing.expect;
7const fs = std.fs;
78
8test "getpid" {9test "getpid" {
9 expect(linux.getpid() != 0);10 expect(linux.getpid() != 0);
...@@ -45,14 +46,12 @@ test "timer" {...@@ -45,14 +46,12 @@ test "timer" {
45 err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1);46 err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1);
46}47}
4748
48const File = std.fs.File;
49
50test "statx" {49test "statx" {
51 const tmp_file_name = "just_a_temporary_file.txt";50 const tmp_file_name = "just_a_temporary_file.txt";
52 var file = try File.openWrite(tmp_file_name);51 var file = try fs.cwd().createFile(tmp_file_name, .{});
53 defer {52 defer {
54 file.close();53 file.close();
55 std.fs.deleteFile(tmp_file_name) catch {};54 fs.cwd().deleteFile(tmp_file_name) catch {};
56 }55 }
5756
58 var statx_buf: linux.Statx = undefined;57 var statx_buf: linux.Statx = undefined;
lib/std/os/linux/tls.zig+27
...@@ -109,12 +109,38 @@ const TLSImage = struct {...@@ -109,12 +109,38 @@ const TLSImage = struct {
109 tcb_offset: usize,109 tcb_offset: usize,
110 dtv_offset: usize,110 dtv_offset: usize,
111 data_offset: usize,111 data_offset: usize,
112 // Only used on the i386 architecture
113 gdt_entry_number: usize,
112};114};
113115
114pub var tls_image: ?TLSImage = null;116pub var tls_image: ?TLSImage = null;
115117
116pub fn setThreadPointer(addr: usize) void {118pub fn setThreadPointer(addr: usize) void {
117 switch (builtin.arch) {119 switch (builtin.arch) {
120 .i386 => {
121 var user_desc = std.os.linux.user_desc{
122 .entry_number = tls_image.?.gdt_entry_number,
123 .base_addr = addr,
124 .limit = 0xfffff,
125 .seg_32bit = 1,
126 .contents = 0, // Data
127 .read_exec_only = 0,
128 .limit_in_pages = 1,
129 .seg_not_present = 0,
130 .useable = 1,
131 };
132 const rc = std.os.linux.syscall1(std.os.linux.SYS_set_thread_area, @ptrToInt(&user_desc));
133 assert(rc == 0);
134
135 const gdt_entry_number = user_desc.entry_number;
136 // We have to keep track of our slot as it's also needed for clone()
137 tls_image.?.gdt_entry_number = gdt_entry_number;
138 // Update the %gs selector
139 asm volatile ("movl %[gs_val], %%gs"
140 :
141 : [gs_val] "r" (gdt_entry_number << 3 | 3)
142 );
143 },
118 .x86_64 => {144 .x86_64 => {
119 const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, std.os.linux.ARCH_SET_FS, addr);145 const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, std.os.linux.ARCH_SET_FS, addr);
120 assert(rc == 0);146 assert(rc == 0);
...@@ -238,6 +264,7 @@ pub fn initTLS() ?*elf.Phdr {...@@ -238,6 +264,7 @@ pub fn initTLS() ?*elf.Phdr {
238 .tcb_offset = tcb_offset,264 .tcb_offset = tcb_offset,
239 .dtv_offset = dtv_offset,265 .dtv_offset = dtv_offset,
240 .data_offset = data_offset,266 .data_offset = data_offset,
267 .gdt_entry_number = @bitCast(usize, @as(isize, -1)),
241 };268 };
242 }269 }
243270
lib/std/os/test.zig+2-2
...@@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" {...@@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" {
20 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");20 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
21 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");21 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
22 try fs.deleteTree("os_test_tmp");22 try fs.deleteTree("os_test_tmp");
23 if (fs.Dir.cwd().openDirTraverse("os_test_tmp")) |dir| {23 if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| {
24 @panic("expected error");24 @panic("expected error");
25 } else |err| {25 } else |err| {
26 expect(err == error.FileNotFound);26 expect(err == error.FileNotFound);
...@@ -111,7 +111,7 @@ test "AtomicFile" {...@@ -111,7 +111,7 @@ test "AtomicFile" {
111 const content = try io.readFileAlloc(allocator, test_out_file);111 const content = try io.readFileAlloc(allocator, test_out_file);
112 expect(mem.eql(u8, content, test_content));112 expect(mem.eql(u8, content, test_content));
113113
114 try fs.deleteFile(test_out_file);114 try fs.cwd().deleteFile(test_out_file);
115}115}
116116
117test "thread local storage" {117test "thread local storage" {
lib/std/os/wasi.zig+2-2
...@@ -12,8 +12,8 @@ comptime {...@@ -12,8 +12,8 @@ comptime {
12 assert(@alignOf(u16) == 2);12 assert(@alignOf(u16) == 2);
13 assert(@alignOf(i32) == 4);13 assert(@alignOf(i32) == 4);
14 assert(@alignOf(u32) == 4);14 assert(@alignOf(u32) == 4);
15 assert(@alignOf(i64) == 8);15 // assert(@alignOf(i64) == 8);
16 assert(@alignOf(u64) == 8);16 // assert(@alignOf(u64) == 8);
17}17}
1818
19pub const iovec_t = iovec;19pub const iovec_t = iovec;
lib/std/parker.zig deleted-180
...@@ -1,180 +0,0 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");
3const time = std.time;
4const testing = std.testing;
5const assert = std.debug.assert;
6const SpinLock = std.SpinLock;
7const linux = std.os.linux;
8const windows = std.os.windows;
9
10pub const ThreadParker = switch (builtin.os) {
11 .linux => if (builtin.link_libc) PosixParker else LinuxParker,
12 .windows => WindowsParker,
13 else => if (builtin.link_libc) PosixParker else SpinParker,
14};
15
16const SpinParker = struct {
17 pub fn init() SpinParker {
18 return SpinParker{};
19 }
20 pub fn deinit(self: *SpinParker) void {}
21
22 pub fn unpark(self: *SpinParker, ptr: *const u32) void {}
23
24 pub fn park(self: *SpinParker, ptr: *const u32, expected: u32) void {
25 var backoff = SpinLock.Backoff.init();
26 while (@atomicLoad(u32, ptr, .Acquire) == expected)
27 backoff.yield();
28 }
29};
30
31const LinuxParker = struct {
32 pub fn init() LinuxParker {
33 return LinuxParker{};
34 }
35 pub fn deinit(self: *LinuxParker) void {}
36
37 pub fn unpark(self: *LinuxParker, ptr: *const u32) void {
38 const rc = linux.futex_wake(@ptrCast(*const i32, ptr), linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1);
39 assert(linux.getErrno(rc) == 0);
40 }
41
42 pub fn park(self: *LinuxParker, ptr: *const u32, expected: u32) void {
43 const value = @intCast(i32, expected);
44 while (@atomicLoad(u32, ptr, .Acquire) == expected) {
45 const rc = linux.futex_wait(@ptrCast(*const i32, ptr), linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, value, null);
46 switch (linux.getErrno(rc)) {
47 0, linux.EAGAIN => return,
48 linux.EINTR => continue,
49 linux.EINVAL => unreachable,
50 else => continue,
51 }
52 }
53 }
54};
55
56const WindowsParker = struct {
57 waiters: u32,
58
59 pub fn init() WindowsParker {
60 return WindowsParker{ .waiters = 0 };
61 }
62 pub fn deinit(self: *WindowsParker) void {}
63
64 pub fn unpark(self: *WindowsParker, ptr: *const u32) void {
65 const key = @ptrCast(*const c_void, ptr);
66 const handle = getEventHandle() orelse return;
67
68 var waiting = @atomicLoad(u32, &self.waiters, .Monotonic);
69 while (waiting != 0) {
70 waiting = @cmpxchgWeak(u32, &self.waiters, waiting, waiting - 1, .Acquire, .Monotonic) orelse {
71 const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null);
72 assert(rc == 0);
73 return;
74 };
75 }
76 }
77
78 pub fn park(self: *WindowsParker, ptr: *const u32, expected: u32) void {
79 var spin = SpinLock.Backoff.init();
80 const ev_handle = getEventHandle();
81 const key = @ptrCast(*const c_void, ptr);
82
83 while (@atomicLoad(u32, ptr, .Monotonic) == expected) {
84 if (ev_handle) |handle| {
85 _ = @atomicRmw(u32, &self.waiters, .Add, 1, .Release);
86 const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, null);
87 assert(rc == 0);
88 } else {
89 spin.yield();
90 }
91 }
92 }
93
94 var event_handle = std.lazyInit(windows.HANDLE);
95
96 fn getEventHandle() ?windows.HANDLE {
97 if (event_handle.get()) |handle_ptr|
98 return handle_ptr.*;
99 defer event_handle.resolve();
100
101 const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE;
102 if (windows.ntdll.NtCreateKeyedEvent(&event_handle.data, access_mask, null, 0) != 0)
103 return null;
104 return event_handle.data;
105 }
106};
107
108const PosixParker = struct {
109 cond: c.pthread_cond_t,
110 mutex: c.pthread_mutex_t,
111
112 const c = std.c;
113
114 pub fn init() PosixParker {
115 return PosixParker{
116 .cond = c.PTHREAD_COND_INITIALIZER,
117 .mutex = c.PTHREAD_MUTEX_INITIALIZER,
118 };
119 }
120
121 pub fn deinit(self: *PosixParker) void {
122 // On dragonfly, the destroy functions return EINVAL if they were initialized statically.
123 const retm = c.pthread_mutex_destroy(&self.mutex);
124 assert(retm == 0 or retm == (if (builtin.os == .dragonfly) os.EINVAL else 0));
125 const retc = c.pthread_cond_destroy(&self.cond);
126 assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0));
127 }
128
129 pub fn unpark(self: *PosixParker, ptr: *const u32) void {
130 assert(c.pthread_mutex_lock(&self.mutex) == 0);
131 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
132 assert(c.pthread_cond_signal(&self.cond) == 0);
133 }
134
135 pub fn park(self: *PosixParker, ptr: *const u32, expected: u32) void {
136 assert(c.pthread_mutex_lock(&self.mutex) == 0);
137 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
138 while (@atomicLoad(u32, ptr, .Acquire) == expected)
139 assert(c.pthread_cond_wait(&self.cond, &self.mutex) == 0);
140 }
141};
142
143test "std.ThreadParker" {
144 if (builtin.single_threaded)
145 return error.SkipZigTest;
146
147 const Context = struct {
148 parker: ThreadParker,
149 data: u32,
150
151 fn receiver(self: *@This()) void {
152 self.parker.park(&self.data, 0); // receives 1
153 assert(@atomicRmw(u32, &self.data, .Xchg, 2, .SeqCst) == 1); // sends 2
154 self.parker.unpark(&self.data); // wakes up waiters on 2
155 self.parker.park(&self.data, 2); // receives 3
156 assert(@atomicRmw(u32, &self.data, .Xchg, 4, .SeqCst) == 3); // sends 4
157 self.parker.unpark(&self.data); // wakes up waiters on 4
158 }
159
160 fn sender(self: *@This()) void {
161 assert(@atomicRmw(u32, &self.data, .Xchg, 1, .SeqCst) == 0); // sends 1
162 self.parker.unpark(&self.data); // wakes up waiters on 1
163 self.parker.park(&self.data, 1); // receives 2
164 assert(@atomicRmw(u32, &self.data, .Xchg, 3, .SeqCst) == 2); // sends 3
165 self.parker.unpark(&self.data); // wakes up waiters on 3
166 self.parker.park(&self.data, 3); // receives 4
167 }
168 };
169
170 var context = Context{
171 .parker = ThreadParker.init(),
172 .data = 0,
173 };
174 defer context.parker.deinit();
175
176 var receiver = try std.Thread.spawn(&context, Context.receiver);
177 defer receiver.wait();
178
179 context.sender();
180}
lib/std/pdb.zig+2-1
...@@ -6,6 +6,7 @@ const mem = std.mem;...@@ -6,6 +6,7 @@ const mem = std.mem;
6const os = std.os;6const os = std.os;
7const warn = std.debug.warn;7const warn = std.debug.warn;
8const coff = std.coff;8const coff = std.coff;
9const fs = std.fs;
9const File = std.fs.File;10const File = std.fs.File;
1011
11const ArrayList = std.ArrayList;12const ArrayList = std.ArrayList;
...@@ -469,7 +470,7 @@ pub const Pdb = struct {...@@ -469,7 +470,7 @@ pub const Pdb = struct {
469 msf: Msf,470 msf: Msf,
470471
471 pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {472 pub fn openFile(self: *Pdb, coff_ptr: *coff.Coff, file_name: []u8) !void {
472 self.in_file = try File.openRead(file_name);473 self.in_file = try fs.cwd().openFile(file_name, .{});
473 self.allocator = coff_ptr.allocator;474 self.allocator = coff_ptr.allocator;
474 self.coff = coff_ptr;475 self.coff = coff_ptr;
475476
lib/std/reset_event.zig created+433
...@@ -0,0 +1,433 @@
1const std = @import("std.zig");
2const builtin = @import("builtin");
3const testing = std.testing;
4const assert = std.debug.assert;
5const Backoff = std.SpinLock.Backoff;
6const c = std.c;
7const os = std.os;
8const time = std.time;
9const linux = os.linux;
10const windows = os.windows;
11
12/// A resource object which supports blocking until signaled.
13/// Once finished, the `deinit()` method should be called for correctness.
14pub const ResetEvent = struct {
15 os_event: OsEvent,
16
17 pub fn init() ResetEvent {
18 return ResetEvent{ .os_event = OsEvent.init() };
19 }
20
21 pub fn deinit(self: *ResetEvent) void {
22 self.os_event.deinit();
23 self.* = undefined;
24 }
25
26 /// Returns whether or not the event is currenetly set
27 pub fn isSet(self: *ResetEvent) bool {
28 return self.os_event.isSet();
29 }
30
31 /// Sets the event if not already set and
32 /// wakes up AT LEAST one thread waiting the event.
33 /// Returns whether or not a thread was woken up.
34 pub fn set(self: *ResetEvent, auto_reset: bool) bool {
35 return self.os_event.set(auto_reset);
36 }
37
38 /// Resets the event to its original, unset state.
39 /// Returns whether or not the event was currently set before un-setting.
40 pub fn reset(self: *ResetEvent) bool {
41 return self.os_event.reset();
42 }
43
44 const WaitError = error{
45 /// The thread blocked longer than the maximum time specified.
46 TimedOut,
47 };
48
49 /// Wait for the event to be set by blocking the current thread.
50 /// Optionally provided timeout in nanoseconds which throws an
51 /// `error.TimedOut` if the thread blocked AT LEAST longer than specified.
52 /// Returns whether or not the thread blocked from the event being unset at the time of calling.
53 pub fn wait(self: *ResetEvent, timeout_ns: ?u64) WaitError!bool {
54 return self.os_event.wait(timeout_ns);
55 }
56};
57
58const OsEvent = if (builtin.single_threaded) DebugEvent else switch (builtin.os) {
59 .windows => WindowsEvent,
60 .linux => if (builtin.link_libc) PosixEvent else LinuxEvent,
61 else => if (builtin.link_libc) PosixEvent else SpinEvent,
62};
63
64const DebugEvent = struct {
65 is_set: @typeOf(set_init),
66
67 const set_init = if (std.debug.runtime_safety) false else {};
68
69 pub fn init() DebugEvent {
70 return DebugEvent{ .is_set = set_init };
71 }
72
73 pub fn deinit(self: *DebugEvent) void {
74 self.* = undefined;
75 }
76
77 pub fn isSet(self: *DebugEvent) bool {
78 if (!std.debug.runtime_safety)
79 return true;
80 return self.is_set;
81 }
82
83 pub fn set(self: *DebugEvent, auto_reset: bool) bool {
84 if (std.debug.runtime_safety)
85 self.is_set = !auto_reset;
86 return false;
87 }
88
89 pub fn reset(self: *DebugEvent) bool {
90 if (!std.debug.runtime_safety)
91 return false;
92 const was_set = self.is_set;
93 self.is_set = false;
94 return was_set;
95 }
96
97 pub fn wait(self: *DebugEvent, timeout: ?u64) ResetEvent.WaitError!bool {
98 if (std.debug.runtime_safety and !self.is_set)
99 @panic("deadlock detected");
100 return ResetEvent.WaitError.TimedOut;
101 }
102};
103
104fn AtomicEvent(comptime FutexImpl: type) type {
105 return struct {
106 state: u32,
107
108 const IS_SET: u32 = 1 << 0;
109 const WAIT_MASK = ~IS_SET;
110
111 pub const Self = @This();
112 pub const Futex = FutexImpl;
113
114 pub fn init() Self {
115 return Self{ .state = 0 };
116 }
117
118 pub fn deinit(self: *Self) void {
119 self.* = undefined;
120 }
121
122 pub fn isSet(self: *const Self) bool {
123 const state = @atomicLoad(u32, &self.state, .Acquire);
124 return (state & IS_SET) != 0;
125 }
126
127 pub fn reset(self: *Self) bool {
128 const old_state = @atomicRmw(u32, &self.state, .Xchg, 0, .Monotonic);
129 return (old_state & IS_SET) != 0;
130 }
131
132 pub fn set(self: *Self, auto_reset: bool) bool {
133 const new_state = if (auto_reset) 0 else IS_SET;
134 const old_state = @atomicRmw(u32, &self.state, .Xchg, new_state, .Release);
135 if ((old_state & WAIT_MASK) == 0) {
136 return false;
137 }
138
139 Futex.wake(&self.state);
140 return true;
141 }
142
143 pub fn wait(self: *Self, timeout: ?u64) ResetEvent.WaitError!bool {
144 var dummy_value: u32 = undefined;
145 const wait_token = @truncate(u32, @ptrToInt(&dummy_value));
146
147 var state = @atomicLoad(u32, &self.state, .Monotonic);
148 while (true) {
149 if ((state & IS_SET) != 0)
150 return false;
151 state = @cmpxchgWeak(u32, &self.state, state, wait_token, .Acquire, .Monotonic) orelse break;
152 }
153
154 try Futex.wait(&self.state, wait_token, timeout);
155 return true;
156 }
157 };
158}
159
160const SpinEvent = AtomicEvent(struct {
161 fn wake(ptr: *const u32) void {}
162
163 fn wait(ptr: *const u32, expected: u32, timeout: ?u64) ResetEvent.WaitError!void {
164 // TODO: handle platforms where time.Timer.start() fails
165 var spin = Backoff.init();
166 var timer = if (timeout == null) null else time.Timer.start() catch unreachable;
167 while (@atomicLoad(u32, ptr, .Acquire) == expected) {
168 spin.yield();
169 if (timeout) |timeout_ns| {
170 if (timer.?.read() > timeout_ns)
171 return ResetEvent.WaitError.TimedOut;
172 }
173 }
174 }
175});
176
177const LinuxEvent = AtomicEvent(struct {
178 fn wake(ptr: *const u32) void {
179 const key = @ptrCast(*const i32, ptr);
180 const rc = linux.futex_wake(key, linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG, 1);
181 assert(linux.getErrno(rc) == 0);
182 }
183
184 fn wait(ptr: *const u32, expected: u32, timeout: ?u64) ResetEvent.WaitError!void {
185 var ts: linux.timespec = undefined;
186 var ts_ptr: ?*linux.timespec = null;
187 if (timeout) |timeout_ns| {
188 ts_ptr = &ts;
189 ts.tv_sec = @intCast(isize, timeout_ns / time.ns_per_s);
190 ts.tv_nsec = @intCast(isize, timeout_ns % time.ns_per_s);
191 }
192
193 const key = @ptrCast(*const i32, ptr);
194 const key_expect = @bitCast(i32, expected);
195 while (@atomicLoad(i32, key, .Acquire) == key_expect) {
196 const rc = linux.futex_wait(key, linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG, key_expect, ts_ptr);
197 switch (linux.getErrno(rc)) {
198 0, linux.EAGAIN => break,
199 linux.EINTR => continue,
200 linux.ETIMEDOUT => return ResetEvent.WaitError.TimedOut,
201 else => unreachable,
202 }
203 }
204 }
205});
206
207const WindowsEvent = AtomicEvent(struct {
208 fn wake(ptr: *const u32) void {
209 if (getEventHandle()) |handle| {
210 const key = @ptrCast(*const c_void, ptr);
211 const rc = windows.ntdll.NtReleaseKeyedEvent(handle, key, windows.FALSE, null);
212 assert(rc == 0);
213 }
214 }
215
216 fn wait(ptr: *const u32, expected: u32, timeout: ?u64) ResetEvent.WaitError!void {
217 // fallback to spinlock if NT Keyed Events arent available
218 const handle = getEventHandle() orelse {
219 return SpinEvent.Futex.wait(ptr, expected, timeout);
220 };
221
222 // NT uses timeouts in units of 100ns with negative value being relative
223 var timeout_ptr: ?*windows.LARGE_INTEGER = null;
224 var timeout_value: windows.LARGE_INTEGER = undefined;
225 if (timeout) |timeout_ns| {
226 timeout_ptr = &timeout_value;
227 timeout_value = -@intCast(windows.LARGE_INTEGER, timeout_ns / 100);
228 }
229
230 // NtWaitForKeyedEvent doesnt have spurious wake-ups
231 if (@atomicLoad(u32, ptr, .Acquire) == expected) {
232 const key = @ptrCast(*const c_void, ptr);
233 const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, timeout_ptr);
234 switch (rc) {
235 0 => {},
236 windows.WAIT_TIMEOUT => return ResetEvent.WaitError.TimedOut,
237 else => unreachable,
238 }
239 }
240 }
241
242 var keyed_state = State.Uninitialized;
243 var keyed_handle: ?windows.HANDLE = null;
244
245 const State = enum(u8) {
246 Uninitialized,
247 Intializing,
248 Initialized,
249 };
250
251 fn getEventHandle() ?windows.HANDLE {
252 var spin = Backoff.init();
253 var state = @atomicLoad(State, &keyed_state, .Monotonic);
254
255 while (true) {
256 switch (state) {
257 .Initialized => {
258 return keyed_handle;
259 },
260 .Intializing => {
261 spin.yield();
262 state = @atomicLoad(State, &keyed_state, .Acquire);
263 },
264 .Uninitialized => state = @cmpxchgWeak(State, &keyed_state, state, .Intializing, .Acquire, .Monotonic) orelse {
265 var handle: windows.HANDLE = undefined;
266 const access_mask = windows.GENERIC_READ | windows.GENERIC_WRITE;
267 if (windows.ntdll.NtCreateKeyedEvent(&handle, access_mask, null, 0) == 0)
268 keyed_handle = handle;
269 @atomicStore(State, &keyed_state, .Initialized, .Release);
270 return keyed_handle;
271 },
272 }
273 }
274 }
275});
276
277const PosixEvent = struct {
278 state: u32,
279 cond: c.pthread_cond_t,
280 mutex: c.pthread_mutex_t,
281
282 const IS_SET: u32 = 1;
283
284 pub fn init() PosixEvent {
285 return PosixEvent{
286 .state = .0,
287 .cond = c.PTHREAD_COND_INITIALIZER,
288 .mutex = c.PTHREAD_MUTEX_INITIALIZER,
289 };
290 }
291
292 pub fn deinit(self: *PosixEvent) void {
293 // On dragonfly, the destroy functions return EINVAL if they were initialized statically.
294 const retm = c.pthread_mutex_destroy(&self.mutex);
295 assert(retm == 0 or retm == (if (builtin.os == .dragonfly) os.EINVAL else 0));
296 const retc = c.pthread_cond_destroy(&self.cond);
297 assert(retc == 0 or retc == (if (builtin.os == .dragonfly) os.EINVAL else 0));
298 }
299
300 pub fn isSet(self: *PosixEvent) bool {
301 assert(c.pthread_mutex_lock(&self.mutex) == 0);
302 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
303
304 return self.state == IS_SET;
305 }
306
307 pub fn reset(self: *PosixEvent) bool {
308 assert(c.pthread_mutex_lock(&self.mutex) == 0);
309 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
310
311 const was_set = self.state == IS_SET;
312 self.state = 0;
313 return was_set;
314 }
315
316 pub fn set(self: *PosixEvent, auto_reset: bool) bool {
317 assert(c.pthread_mutex_lock(&self.mutex) == 0);
318 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
319
320 const had_waiter = self.state > IS_SET;
321 self.state = if (auto_reset) 0 else IS_SET;
322 if (had_waiter) {
323 assert(c.pthread_cond_signal(&self.cond) == 0);
324 }
325 return had_waiter;
326 }
327
328 pub fn wait(self: *PosixEvent, timeout: ?u64) ResetEvent.WaitError!bool {
329 assert(c.pthread_mutex_lock(&self.mutex) == 0);
330 defer assert(c.pthread_mutex_unlock(&self.mutex) == 0);
331
332 if (self.state == IS_SET)
333 return false;
334
335 var ts: os.timespec = undefined;
336 if (timeout) |timeout_ns| {
337 var timeout_abs = timeout_ns;
338 if (comptime std.Target.current.isDarwin()) {
339 var tv: os.darwin.timeval = undefined;
340 assert(os.darwin.gettimeofday(&tv, null) == 0);
341 timeout_abs += @intCast(u64, tv.tv_sec) * time.second;
342 timeout_abs += @intCast(u64, tv.tv_usec) * time.microsecond;
343 } else {
344 os.clock_gettime(os.CLOCK_REALTIME, &ts) catch unreachable;
345 timeout_abs += @intCast(u64, ts.tv_sec) * time.second;
346 timeout_abs += @intCast(u64, ts.tv_nsec);
347 }
348 ts.tv_sec = @intCast(@typeOf(ts.tv_sec), @divFloor(timeout_abs, time.second));
349 ts.tv_nsec = @intCast(@typeOf(ts.tv_nsec), @mod(timeout_abs, time.second));
350 }
351
352 var dummy_value: u32 = undefined;
353 var wait_token = @truncate(u32, @ptrToInt(&dummy_value));
354 self.state = wait_token;
355
356 while (self.state == wait_token) {
357 const rc = switch (timeout == null) {
358 true => c.pthread_cond_wait(&self.cond, &self.mutex),
359 else => c.pthread_cond_timedwait(&self.cond, &self.mutex, &ts),
360 };
361 // TODO: rc appears to be the positive error code making os.errno() always return 0 on linux
362 switch (std.math.max(@as(c_int, os.errno(rc)), rc)) {
363 0 => {},
364 os.ETIMEDOUT => return ResetEvent.WaitError.TimedOut,
365 os.EINVAL => unreachable,
366 os.EPERM => unreachable,
367 else => unreachable,
368 }
369 }
370 return true;
371 }
372};
373
374test "std.ResetEvent" {
375 // TODO
376 if (builtin.single_threaded)
377 return error.SkipZigTest;
378
379 var event = ResetEvent.init();
380 defer event.deinit();
381
382 // test event setting
383 testing.expect(event.isSet() == false);
384 testing.expect(event.set(false) == false);
385 testing.expect(event.isSet() == true);
386
387 // test event resetting
388 testing.expect(event.reset() == true);
389 testing.expect(event.isSet() == false);
390 testing.expect(event.reset() == false);
391
392 // test cross thread signaling
393 const Context = struct {
394 event: ResetEvent,
395 value: u128,
396
397 fn receiver(self: *@This()) void {
398 // wait for the sender to notify us with updated value
399 assert(self.value == 0);
400 assert((self.event.wait(1 * time.second) catch unreachable) == true);
401 assert(self.value == 1);
402
403 // wait for sender to sleep, then notify it of new value
404 time.sleep(50 * time.millisecond);
405 self.value = 2;
406 assert(self.event.set(false) == true);
407 }
408
409 fn sender(self: *@This()) !void {
410 // wait for the receiver() to start wait()'ing
411 time.sleep(50 * time.millisecond);
412
413 // update value to 1 and notify the receiver()
414 assert(self.value == 0);
415 self.value = 1;
416 assert(self.event.set(true) == true);
417
418 // wait for the receiver to update the value & notify us
419 assert((try self.event.wait(1 * time.second)) == true);
420 assert(self.value == 2);
421 }
422 };
423
424 _ = event.reset();
425 var context = Context{
426 .event = event,
427 .value = 0,
428 };
429
430 var receiver = try std.Thread.spawn(&context, Context.receiver);
431 defer receiver.wait();
432 try context.sender();
433}
\ No newline at end of file
lib/std/special/c.zig+43
...@@ -197,6 +197,49 @@ extern fn __stack_chk_fail() noreturn {...@@ -197,6 +197,49 @@ extern fn __stack_chk_fail() noreturn {
197// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.197// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.
198nakedcc fn clone() void {198nakedcc fn clone() void {
199 switch (builtin.arch) {199 switch (builtin.arch) {
200 .i386 => {
201 // __clone(func, stack, flags, arg, ptid, tls, ctid)
202 // +8, +12, +16, +20, +24, +28, +32
203 // syscall(SYS_clone, flags, stack, ptid, tls, ctid)
204 // eax, ebx, ecx, edx, esi, edi
205 asm volatile (
206 \\ push %%ebp
207 \\ mov %%esp,%%ebp
208 \\ push %%ebx
209 \\ push %%esi
210 \\ push %%edi
211 \\ // Setup the arguments
212 \\ mov 16(%%ebp),%%ebx
213 \\ mov 12(%%ebp),%%ecx
214 \\ and $-16,%%ecx
215 \\ sub $20,%%ecx
216 \\ mov 20(%%ebp),%%eax
217 \\ mov %%eax,4(%%ecx)
218 \\ mov 8(%%ebp),%%eax
219 \\ mov %%eax,0(%%ecx)
220 \\ mov 24(%%ebp),%%edx
221 \\ mov 28(%%ebp),%%esi
222 \\ mov 32(%%ebp),%%edi
223 \\ mov $120,%%eax
224 \\ int $128
225 \\ test %%eax,%%eax
226 \\ jnz 1f
227 \\ pop %%eax
228 \\ xor %%ebp,%%ebp
229 \\ call *%%eax
230 \\ mov %%eax,%%ebx
231 \\ xor %%eax,%%eax
232 \\ inc %%eax
233 \\ int $128
234 \\ hlt
235 \\1:
236 \\ pop %%edi
237 \\ pop %%esi
238 \\ pop %%ebx
239 \\ pop %%ebp
240 \\ ret
241 );
242 },
200 .x86_64 => {243 .x86_64 => {
201 asm volatile (244 asm volatile (
202 \\ xor %%eax,%%eax245 \\ xor %%eax,%%eax
lib/std/std.zig+1-1
...@@ -16,6 +16,7 @@ pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;...@@ -16,6 +16,7 @@ pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;
16pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;16pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;
17pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;17pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
18pub const Progress = @import("progress.zig").Progress;18pub const Progress = @import("progress.zig").Progress;
19pub const ResetEvent = @import("reset_event.zig").ResetEvent;
19pub const SegmentedList = @import("segmented_list.zig").SegmentedList;20pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
20pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;21pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
21pub const SpinLock = @import("spinlock.zig").SpinLock;22pub const SpinLock = @import("spinlock.zig").SpinLock;
...@@ -23,7 +24,6 @@ pub const StringHashMap = @import("hash_map.zig").StringHashMap;...@@ -23,7 +24,6 @@ pub const StringHashMap = @import("hash_map.zig").StringHashMap;
23pub const TailQueue = @import("linked_list.zig").TailQueue;24pub const TailQueue = @import("linked_list.zig").TailQueue;
24pub const Target = @import("target.zig").Target;25pub const Target = @import("target.zig").Target;
25pub const Thread = @import("thread.zig").Thread;26pub const Thread = @import("thread.zig").Thread;
26pub const ThreadParker = @import("parker.zig").ThreadParker;
2727
28pub const atomic = @import("atomic.zig");28pub const atomic = @import("atomic.zig");
29pub const base64 = @import("base64.zig");29pub const base64 = @import("base64.zig");
lib/std/testing.zig+33-1
...@@ -89,7 +89,26 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -89,7 +89,26 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
89 if (union_info.tag_type == null) {89 if (union_info.tag_type == null) {
90 @compileError("Unable to compare untagged union values");90 @compileError("Unable to compare untagged union values");
91 }91 }
92 @compileError("TODO implement testing.expectEqual for tagged unions");92
93 const TagType = @TagType(@typeOf(expected));
94
95 const expectedTag = @as(TagType, expected);
96 const actualTag = @as(TagType, actual);
97
98 expectEqual(expectedTag, actualTag);
99
100 // we only reach this loop if the tags are equal
101 inline for (std.meta.fields(@typeOf(actual))) |fld| {
102 if (std.mem.eql(u8, fld.name, @tagName(actualTag))) {
103 expectEqual(@field(expected, fld.name), @field(actual, fld.name));
104 return;
105 }
106 }
107
108 // we iterate over *all* union fields
109 // => we should never get here as the loop above is
110 // including all possible values.
111 unreachable;
93 },112 },
94113
95 .Optional => {114 .Optional => {
...@@ -124,6 +143,19 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {...@@ -124,6 +143,19 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
124 }143 }
125}144}
126145
146test "expectEqual.union(enum)"
147{
148 const T = union(enum) {
149 a: i32,
150 b: f32,
151 };
152
153 const a10 = T { .a = 10 };
154 const a20 = T { .a = 20 };
155
156 expectEqual(a10, a10);
157}
158
127/// This function is intended to be used only in tests. When the two slices are not159/// This function is intended to be used only in tests. When the two slices are not
128/// equal, prints diagnostics to stderr to show exactly how they are not equal,160/// equal, prints diagnostics to stderr to show exactly how they are not equal,
129/// then aborts.161/// then aborts.
lib/std/thread.zig+29-2
...@@ -314,11 +314,38 @@ pub const Thread = struct {...@@ -314,11 +314,38 @@ pub const Thread = struct {
314 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |314 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
315 os.CLONE_DETACHED;315 os.CLONE_DETACHED;
316 var newtls: usize = undefined;316 var newtls: usize = undefined;
317 // This structure is only needed when targeting i386
318 var user_desc: if (builtin.arch == .i386) os.linux.user_desc else void = undefined;
319
317 if (os.linux.tls.tls_image) |tls_img| {320 if (os.linux.tls.tls_image) |tls_img| {
318 newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset);321 if (builtin.arch == .i386) {
322 user_desc = os.linux.user_desc{
323 .entry_number = tls_img.gdt_entry_number,
324 .base_addr = os.linux.tls.copyTLS(mmap_addr + tls_start_offset),
325 .limit = 0xfffff,
326 .seg_32bit = 1,
327 .contents = 0, // Data
328 .read_exec_only = 0,
329 .limit_in_pages = 1,
330 .seg_not_present = 0,
331 .useable = 1,
332 };
333 newtls = @ptrToInt(&user_desc);
334 } else {
335 newtls = os.linux.tls.copyTLS(mmap_addr + tls_start_offset);
336 }
319 flags |= os.CLONE_SETTLS;337 flags |= os.CLONE_SETTLS;
320 }338 }
321 const rc = os.linux.clone(MainFuncs.linuxThreadMain, mmap_addr + stack_end_offset, flags, arg, &thread_ptr.data.handle, newtls, &thread_ptr.data.handle);339
340 const rc = os.linux.clone(
341 MainFuncs.linuxThreadMain,
342 mmap_addr + stack_end_offset,
343 flags,
344 arg,
345 &thread_ptr.data.handle,
346 newtls,
347 &thread_ptr.data.handle,
348 );
322 switch (os.errno(rc)) {349 switch (os.errno(rc)) {
323 0 => return thread_ptr,350 0 => return thread_ptr,
324 os.EAGAIN => return error.ThreadQuotaExceeded,351 os.EAGAIN => return error.ThreadQuotaExceeded,
src-self-hosted/codegen.zig+15-15
...@@ -25,10 +25,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -25,10 +25,10 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
2525
26 const context = llvm_handle.node.data;26 const context = llvm_handle.node.data;
2727
28 const module = llvm.ModuleCreateWithNameInContext(comp.name.ptr(), context) orelse return error.OutOfMemory;28 const module = llvm.ModuleCreateWithNameInContext(comp.name.toSliceConst(), context) orelse return error.OutOfMemory;
29 defer llvm.DisposeModule(module);29 defer llvm.DisposeModule(module);
3030
31 llvm.SetTarget(module, comp.llvm_triple.ptr());31 llvm.SetTarget(module, comp.llvm_triple.toSliceConst());
32 llvm.SetDataLayout(module, comp.target_layout_str);32 llvm.SetDataLayout(module, comp.target_layout_str);
3333
34 if (util.getObjectFormat(comp.target) == .coff) {34 if (util.getObjectFormat(comp.target) == .coff) {
...@@ -48,23 +48,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -48,23 +48,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
48 const producer = try std.Buffer.allocPrint(48 const producer = try std.Buffer.allocPrint(
49 &code.arena.allocator,49 &code.arena.allocator,
50 "zig {}.{}.{}",50 "zig {}.{}.{}",
51 u32(c.ZIG_VERSION_MAJOR),51 @as(u32, c.ZIG_VERSION_MAJOR),
52 u32(c.ZIG_VERSION_MINOR),52 @as(u32, c.ZIG_VERSION_MINOR),
53 u32(c.ZIG_VERSION_PATCH),53 @as(u32, c.ZIG_VERSION_PATCH),
54 );54 );
55 const flags = "";55 const flags = "";
56 const runtime_version = 0;56 const runtime_version = 0;
57 const compile_unit_file = llvm.CreateFile(57 const compile_unit_file = llvm.CreateFile(
58 dibuilder,58 dibuilder,
59 comp.name.ptr(),59 comp.name.toSliceConst(),
60 comp.root_package.root_src_dir.ptr(),60 comp.root_package.root_src_dir.toSliceConst(),
61 ) orelse return error.OutOfMemory;61 ) orelse return error.OutOfMemory;
62 const is_optimized = comp.build_mode != .Debug;62 const is_optimized = comp.build_mode != .Debug;
63 const compile_unit = llvm.CreateCompileUnit(63 const compile_unit = llvm.CreateCompileUnit(
64 dibuilder,64 dibuilder,
65 DW.LANG_C99,65 DW.LANG_C99,
66 compile_unit_file,66 compile_unit_file,
67 producer.ptr(),67 producer.toSliceConst(),
68 is_optimized,68 is_optimized,
69 flags,69 flags,
70 runtime_version,70 runtime_version,
...@@ -99,7 +99,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -99,7 +99,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
9999
100 // verify the llvm module when safety is on100 // verify the llvm module when safety is on
101 if (std.debug.runtime_safety) {101 if (std.debug.runtime_safety) {
102 var error_ptr: ?[*]u8 = null;102 var error_ptr: ?[*:0]u8 = null;
103 _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr);103 _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr);
104 }104 }
105105
...@@ -108,12 +108,12 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -108,12 +108,12 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
108 const is_small = comp.build_mode == .ReleaseSmall;108 const is_small = comp.build_mode == .ReleaseSmall;
109 const is_debug = comp.build_mode == .Debug;109 const is_debug = comp.build_mode == .Debug;
110110
111 var err_msg: [*]u8 = undefined;111 var err_msg: [*:0]u8 = undefined;
112 // TODO integrate this with evented I/O112 // TODO integrate this with evented I/O
113 if (llvm.TargetMachineEmitToFile(113 if (llvm.TargetMachineEmitToFile(
114 comp.target_machine,114 comp.target_machine,
115 module,115 module,
116 output_path.ptr(),116 output_path.toSliceConst(),
117 llvm.EmitBinary,117 llvm.EmitBinary,
118 &err_msg,118 &err_msg,
119 is_debug,119 is_debug,
...@@ -154,7 +154,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)...@@ -154,7 +154,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
154 const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context);154 const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context);
155 const llvm_fn = llvm.AddFunction(155 const llvm_fn = llvm.AddFunction(
156 ofile.module,156 ofile.module,
157 fn_val.symbol_name.ptr(),157 fn_val.symbol_name.toSliceConst(),
158 llvm_fn_type,158 llvm_fn_type,
159 ) orelse return error.OutOfMemory;159 ) orelse return error.OutOfMemory;
160160
...@@ -379,7 +379,7 @@ fn renderLoadUntyped(...@@ -379,7 +379,7 @@ fn renderLoadUntyped(
379 ptr: *llvm.Value,379 ptr: *llvm.Value,
380 alignment: Type.Pointer.Align,380 alignment: Type.Pointer.Align,
381 vol: Type.Pointer.Vol,381 vol: Type.Pointer.Vol,
382 name: [*]const u8,382 name: [*:0]const u8,
383) !*llvm.Value {383) !*llvm.Value {
384 const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;384 const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
385 switch (vol) {385 switch (vol) {
...@@ -390,7 +390,7 @@ fn renderLoadUntyped(...@@ -390,7 +390,7 @@ fn renderLoadUntyped(
390 return result;390 return result;
391}391}
392392
393fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*]const u8) !*llvm.Value {393fn renderLoad(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Pointer, name: [*:0]const u8) !*llvm.Value {
394 return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);394 return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
395}395}
396396
...@@ -438,7 +438,7 @@ pub fn renderAlloca(...@@ -438,7 +438,7 @@ pub fn renderAlloca(
438) !*llvm.Value {438) !*llvm.Value {
439 const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);439 const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
440 const name_with_null = try std.cstr.addNullByte(ofile.arena, name);440 const name_with_null = try std.cstr.addNullByte(ofile.arena, name);
441 const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, name_with_null.ptr) orelse return error.OutOfMemory;441 const result = llvm.BuildAlloca(ofile.builder, llvm_var_type, @ptrCast([*:0]const u8, name_with_null.ptr)) orelse return error.OutOfMemory;
442 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type));442 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type));
443 return result;443 return result;
444}444}
src-self-hosted/compilation.zig+127-151
...@@ -93,7 +93,7 @@ pub const ZigCompiler = struct {...@@ -93,7 +93,7 @@ pub const ZigCompiler = struct {
93 return LlvmHandle{ .node = node };93 return LlvmHandle{ .node = node };
94 }94 }
9595
96 pub async fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {96 pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {
97 if (self.native_libc.start()) |ptr| return ptr;97 if (self.native_libc.start()) |ptr| return ptr;
98 try self.native_libc.data.findNative(self.allocator);98 try self.native_libc.data.findNative(self.allocator);
99 self.native_libc.resolve();99 self.native_libc.resolve();
...@@ -133,62 +133,62 @@ pub const Compilation = struct {...@@ -133,62 +133,62 @@ pub const Compilation = struct {
133 zig_std_dir: []const u8,133 zig_std_dir: []const u8,
134134
135 /// lazily created when we need it135 /// lazily created when we need it
136 tmp_dir: event.Future(BuildError![]u8),136 tmp_dir: event.Future(BuildError![]u8) = event.Future(BuildError![]u8).init(),
137137
138 version_major: u32,138 version_major: u32 = 0,
139 version_minor: u32,139 version_minor: u32 = 0,
140 version_patch: u32,140 version_patch: u32 = 0,
141141
142 linker_script: ?[]const u8,142 linker_script: ?[]const u8 = null,
143 out_h_path: ?[]const u8,143 out_h_path: ?[]const u8 = null,
144144
145 is_test: bool,145 is_test: bool = false,
146 each_lib_rpath: bool,146 each_lib_rpath: bool = false,
147 strip: bool,147 strip: bool = false,
148 is_static: bool,148 is_static: bool,
149 linker_rdynamic: bool,149 linker_rdynamic: bool = false,
150150
151 clang_argv: []const []const u8,151 clang_argv: []const []const u8 = [_][]const u8{},
152 lib_dirs: []const []const u8,152 lib_dirs: []const []const u8 = [_][]const u8{},
153 rpath_list: []const []const u8,153 rpath_list: []const []const u8 = [_][]const u8{},
154 assembly_files: []const []const u8,154 assembly_files: []const []const u8 = [_][]const u8{},
155155
156 /// paths that are explicitly provided by the user to link against156 /// paths that are explicitly provided by the user to link against
157 link_objects: []const []const u8,157 link_objects: []const []const u8 = [_][]const u8{},
158158
159 /// functions that have their own objects that we need to link159 /// functions that have their own objects that we need to link
160 /// it uses an optional pointer so that tombstone removals are possible160 /// it uses an optional pointer so that tombstone removals are possible
161 fn_link_set: event.Locked(FnLinkSet),161 fn_link_set: event.Locked(FnLinkSet) = event.Locked(FnLinkSet).init(FnLinkSet.init()),
162162
163 pub const FnLinkSet = std.TailQueue(?*Value.Fn);163 pub const FnLinkSet = std.TailQueue(?*Value.Fn);
164164
165 windows_subsystem_windows: bool,165 windows_subsystem_windows: bool = false,
166 windows_subsystem_console: bool,166 windows_subsystem_console: bool = false,
167167
168 link_libs_list: ArrayList(*LinkLib),168 link_libs_list: ArrayList(*LinkLib),
169 libc_link_lib: ?*LinkLib,169 libc_link_lib: ?*LinkLib = null,
170170
171 err_color: errmsg.Color,171 err_color: errmsg.Color = .Auto,
172172
173 verbose_tokenize: bool,173 verbose_tokenize: bool = false,
174 verbose_ast_tree: bool,174 verbose_ast_tree: bool = false,
175 verbose_ast_fmt: bool,175 verbose_ast_fmt: bool = false,
176 verbose_cimport: bool,176 verbose_cimport: bool = false,
177 verbose_ir: bool,177 verbose_ir: bool = false,
178 verbose_llvm_ir: bool,178 verbose_llvm_ir: bool = false,
179 verbose_link: bool,179 verbose_link: bool = false,
180180
181 darwin_frameworks: []const []const u8,181 darwin_frameworks: []const []const u8 = [_][]const u8{},
182 darwin_version_min: DarwinVersionMin,182 darwin_version_min: DarwinVersionMin = .None,
183183
184 test_filters: []const []const u8,184 test_filters: []const []const u8 = [_][]const u8{},
185 test_name_prefix: ?[]const u8,185 test_name_prefix: ?[]const u8 = null,
186186
187 emit_file_type: Emit,187 emit_file_type: Emit = .Binary,
188188
189 kind: Kind,189 kind: Kind,
190190
191 link_out_file: ?[]const u8,191 link_out_file: ?[]const u8 = null,
192 events: *event.Channel(Event),192 events: *event.Channel(Event),
193193
194 exported_symbol_names: event.Locked(Decl.Table),194 exported_symbol_names: event.Locked(Decl.Table),
...@@ -213,7 +213,7 @@ pub const Compilation = struct {...@@ -213,7 +213,7 @@ pub const Compilation = struct {
213213
214 target_machine: *llvm.TargetMachine,214 target_machine: *llvm.TargetMachine,
215 target_data_ref: *llvm.TargetData,215 target_data_ref: *llvm.TargetData,
216 target_layout_str: [*]u8,216 target_layout_str: [*:0]u8,
217 target_ptr_bits: u32,217 target_ptr_bits: u32,
218218
219 /// for allocating things which have the same lifetime as this Compilation219 /// for allocating things which have the same lifetime as this Compilation
...@@ -222,16 +222,16 @@ pub const Compilation = struct {...@@ -222,16 +222,16 @@ pub const Compilation = struct {
222 root_package: *Package,222 root_package: *Package,
223 std_package: *Package,223 std_package: *Package,
224224
225 override_libc: ?*LibCInstallation,225 override_libc: ?*LibCInstallation = null,
226226
227 /// need to wait on this group before deinitializing227 /// need to wait on this group before deinitializing
228 deinit_group: event.Group(void),228 deinit_group: event.Group(void),
229229
230 // destroy_frame: @Frame(createAsync),230 destroy_frame: *@Frame(createAsync),
231 // main_loop_frame: @Frame(Compilation.mainLoop),231 main_loop_frame: *@Frame(Compilation.mainLoop),
232 main_loop_future: event.Future(void),232 main_loop_future: event.Future(void) = event.Future(void).init(),
233233
234 have_err_ret_tracing: bool,234 have_err_ret_tracing: bool = false,
235235
236 /// not locked because it is read-only236 /// not locked because it is read-only
237 primitive_type_table: TypeTable,237 primitive_type_table: TypeTable,
...@@ -243,7 +243,9 @@ pub const Compilation = struct {...@@ -243,7 +243,9 @@ pub const Compilation = struct {
243243
244 c_int_types: [CInt.list.len]*Type.Int,244 c_int_types: [CInt.list.len]*Type.Int,
245245
246 // fs_watch: *fs.Watch(*Scope.Root),246 fs_watch: *fs.Watch(*Scope.Root),
247
248 cancelled: bool = false,
247249
248 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);250 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
249 const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);251 const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
...@@ -348,7 +350,9 @@ pub const Compilation = struct {...@@ -348,7 +350,9 @@ pub const Compilation = struct {
348 zig_lib_dir: []const u8,350 zig_lib_dir: []const u8,
349 ) !*Compilation {351 ) !*Compilation {
350 var optional_comp: ?*Compilation = null;352 var optional_comp: ?*Compilation = null;
351 var frame = async createAsync(353 var frame = try zig_compiler.allocator.create(@Frame(createAsync));
354 errdefer zig_compiler.allocator.destroy(frame);
355 frame.* = async createAsync(
352 &optional_comp,356 &optional_comp,
353 zig_compiler,357 zig_compiler,
354 name,358 name,
...@@ -359,11 +363,11 @@ pub const Compilation = struct {...@@ -359,11 +363,11 @@ pub const Compilation = struct {
359 is_static,363 is_static,
360 zig_lib_dir,364 zig_lib_dir,
361 );365 );
366 // TODO causes segfault
367 // return optional_comp orelse if (await frame) |_| unreachable else |err| err;
362 if (optional_comp) |comp| {368 if (optional_comp) |comp| {
363 return comp;369 return comp;
364 } else {370 } else if (await frame) |_| unreachable else |err| return err;
365 if (await frame) |_| unreachable else |err| return err;
366 }
367 }371 }
368372
369 async fn createAsync(373 async fn createAsync(
...@@ -389,50 +393,13 @@ pub const Compilation = struct {...@@ -389,50 +393,13 @@ pub const Compilation = struct {
389 .build_mode = build_mode,393 .build_mode = build_mode,
390 .zig_lib_dir = zig_lib_dir,394 .zig_lib_dir = zig_lib_dir,
391 .zig_std_dir = undefined,395 .zig_std_dir = undefined,
392 .tmp_dir = event.Future(BuildError![]u8).init(),396 .destroy_frame = @frame(),
393 // .destroy_frame = @frame(),397 .main_loop_frame = undefined,
394 // .main_loop_frame = undefined,
395 .main_loop_future = event.Future(void).init(),
396398
397 .name = undefined,399 .name = undefined,
398 .llvm_triple = undefined,400 .llvm_triple = undefined,
399
400 .version_major = 0,
401 .version_minor = 0,
402 .version_patch = 0,
403
404 .verbose_tokenize = false,
405 .verbose_ast_tree = false,
406 .verbose_ast_fmt = false,
407 .verbose_cimport = false,
408 .verbose_ir = false,
409 .verbose_llvm_ir = false,
410 .verbose_link = false,
411
412 .linker_script = null,
413 .out_h_path = null,
414 .is_test = false,
415 .each_lib_rpath = false,
416 .strip = false,
417 .is_static = is_static,401 .is_static = is_static,
418 .linker_rdynamic = false,
419 .clang_argv = &[_][]const u8{},
420 .lib_dirs = &[_][]const u8{},
421 .rpath_list = &[_][]const u8{},
422 .assembly_files = &[_][]const u8{},
423 .link_objects = &[_][]const u8{},
424 .fn_link_set = event.Locked(FnLinkSet).init(FnLinkSet.init()),
425 .windows_subsystem_windows = false,
426 .windows_subsystem_console = false,
427 .link_libs_list = undefined,402 .link_libs_list = undefined,
428 .libc_link_lib = null,
429 .err_color = errmsg.Color.Auto,
430 .darwin_frameworks = &[_][]const u8{},
431 .darwin_version_min = DarwinVersionMin.None,
432 .test_filters = &[_][]const u8{},
433 .test_name_prefix = null,
434 .emit_file_type = Emit.Binary,
435 .link_out_file = null,
436 .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)),403 .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)),
437 .prelink_group = event.Group(BuildError!void).init(allocator),404 .prelink_group = event.Group(BuildError!void).init(allocator),
438 .deinit_group = event.Group(void).init(allocator),405 .deinit_group = event.Group(void).init(allocator),
...@@ -462,11 +429,9 @@ pub const Compilation = struct {...@@ -462,11 +429,9 @@ pub const Compilation = struct {
462 .root_package = undefined,429 .root_package = undefined,
463 .std_package = undefined,430 .std_package = undefined,
464431
465 .override_libc = null,
466 .have_err_ret_tracing = false,
467 .primitive_type_table = undefined,432 .primitive_type_table = undefined,
468433
469 // .fs_watch = undefined,434 .fs_watch = undefined,
470 };435 };
471 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());436 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());
472 comp.primitive_type_table = TypeTable.init(comp.arena());437 comp.primitive_type_table = TypeTable.init(comp.arena());
...@@ -538,13 +503,16 @@ pub const Compilation = struct {...@@ -538,13 +503,16 @@ pub const Compilation = struct {
538 comp.root_package = try Package.create(comp.arena(), ".", "");503 comp.root_package = try Package.create(comp.arena(), ".", "");
539 }504 }
540505
541 // comp.fs_watch = try fs.Watch(*Scope.Root).create(16);506 comp.fs_watch = try fs.Watch(*Scope.Root).init(allocator, 16);
542 // defer comp.fs_watch.destroy();507 defer comp.fs_watch.deinit();
543508
544 try comp.initTypes();509 try comp.initTypes();
545 defer comp.primitive_type_table.deinit();510 defer comp.primitive_type_table.deinit();
546511
547 // comp.main_loop_frame = async comp.mainLoop();512 comp.main_loop_frame = try allocator.create(@Frame(mainLoop));
513 defer allocator.destroy(comp.main_loop_frame);
514
515 comp.main_loop_frame.* = async comp.mainLoop();
548 // Set this to indicate that initialization completed successfully.516 // Set this to indicate that initialization completed successfully.
549 // from here on out we must not return an error.517 // from here on out we must not return an error.
550 // This must occur before the first suspend/await.518 // This must occur before the first suspend/await.
...@@ -563,7 +531,7 @@ pub const Compilation = struct {...@@ -563,7 +531,7 @@ pub const Compilation = struct {
563 }531 }
564532
565 /// it does ref the result because it could be an arbitrary integer size533 /// it does ref the result because it could be an arbitrary integer size
566 pub async fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type {534 pub fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type {
567 if (name.len >= 2) {535 if (name.len >= 2) {
568 switch (name[0]) {536 switch (name[0]) {
569 'i', 'u' => blk: {537 'i', 'u' => blk: {
...@@ -757,8 +725,11 @@ pub const Compilation = struct {...@@ -757,8 +725,11 @@ pub const Compilation = struct {
757 }725 }
758726
759 pub fn destroy(self: *Compilation) void {727 pub fn destroy(self: *Compilation) void {
760 // await self.main_loop_frame;728 const allocator = self.gpa();
761 // resume self.destroy_frame;729 self.cancelled = true;
730 await self.main_loop_frame;
731 resume self.destroy_frame;
732 allocator.destroy(self.destroy_frame);
762 }733 }
763734
764 fn start(self: *Compilation) void {735 fn start(self: *Compilation) void {
...@@ -771,7 +742,7 @@ pub const Compilation = struct {...@@ -771,7 +742,7 @@ pub const Compilation = struct {
771742
772 var build_result = self.initialCompile();743 var build_result = self.initialCompile();
773744
774 while (true) {745 while (!self.cancelled) {
775 const link_result = if (build_result) blk: {746 const link_result = if (build_result) blk: {
776 break :blk self.maybeLink();747 break :blk self.maybeLink();
777 } else |err| err;748 } else |err| err;
...@@ -799,47 +770,47 @@ pub const Compilation = struct {...@@ -799,47 +770,47 @@ pub const Compilation = struct {
799 self.events.put(Event{ .Error = err });770 self.events.put(Event{ .Error = err });
800 }771 }
801772
802 // // First, get an item from the watch channel, waiting on the channel.773 // First, get an item from the watch channel, waiting on the channel.
803 // var group = event.Group(BuildError!void).init(self.gpa());774 var group = event.Group(BuildError!void).init(self.gpa());
804 // {775 {
805 // const ev = (self.fs_watch.channel.get()) catch |err| {776 const ev = (self.fs_watch.channel.get()) catch |err| {
806 // build_result = err;777 build_result = err;
807 // continue;778 continue;
808 // };779 };
809 // const root_scope = ev.data;780 const root_scope = ev.data;
810 // group.call(rebuildFile, self, root_scope) catch |err| {781 group.call(rebuildFile, self, root_scope) catch |err| {
811 // build_result = err;782 build_result = err;
812 // continue;783 continue;
813 // };784 };
814 // }785 }
815 // // Next, get all the items from the channel that are buffered up.786 // Next, get all the items from the channel that are buffered up.
816 // while (self.fs_watch.channel.getOrNull()) |ev_or_err| {787 while (self.fs_watch.channel.getOrNull()) |ev_or_err| {
817 // if (ev_or_err) |ev| {788 if (ev_or_err) |ev| {
818 // const root_scope = ev.data;789 const root_scope = ev.data;
819 // group.call(rebuildFile, self, root_scope) catch |err| {790 group.call(rebuildFile, self, root_scope) catch |err| {
820 // build_result = err;791 build_result = err;
821 // continue;792 continue;
822 // };793 };
823 // } else |err| {794 } else |err| {
824 // build_result = err;795 build_result = err;
825 // continue;796 continue;
826 // }797 }
827 // }798 }
828 // build_result = group.wait();799 build_result = group.wait();
829 }800 }
830 }801 }
831802
832 async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) !void {803 async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) BuildError!void {
833 const tree_scope = blk: {804 const tree_scope = blk: {
834 const source_code = "";805 const source_code = fs.readFile(
835 // const source_code = fs.readFile(806 self.gpa(),
836 // root_scope.realpath,807 root_scope.realpath,
837 // max_src_size,808 max_src_size,
838 // ) catch |err| {809 ) catch |err| {
839 // try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err));810 try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err));
840 // return;811 return;
841 // };812 };
842 // errdefer self.gpa().free(source_code);813 errdefer self.gpa().free(source_code);
843814
844 const tree = try std.zig.parse(self.gpa(), source_code);815 const tree = try std.zig.parse(self.gpa(), source_code);
845 errdefer {816 errdefer {
...@@ -877,7 +848,7 @@ pub const Compilation = struct {...@@ -877,7 +848,7 @@ pub const Compilation = struct {
877 try decl_group.wait();848 try decl_group.wait();
878 }849 }
879850
880 async fn rebuildChangedDecls(851 fn rebuildChangedDecls(
881 self: *Compilation,852 self: *Compilation,
882 group: *event.Group(BuildError!void),853 group: *event.Group(BuildError!void),
883 locked_table: *Decl.Table,854 locked_table: *Decl.Table,
...@@ -966,7 +937,7 @@ pub const Compilation = struct {...@@ -966,7 +937,7 @@ pub const Compilation = struct {
966 }937 }
967 }938 }
968939
969 async fn initialCompile(self: *Compilation) !void {940 fn initialCompile(self: *Compilation) !void {
970 if (self.root_src_path) |root_src_path| {941 if (self.root_src_path) |root_src_path| {
971 const root_scope = blk: {942 const root_scope = blk: {
972 // TODO async/await std.fs.realpath943 // TODO async/await std.fs.realpath
...@@ -985,7 +956,7 @@ pub const Compilation = struct {...@@ -985,7 +956,7 @@ pub const Compilation = struct {
985 }956 }
986 }957 }
987958
988 async fn maybeLink(self: *Compilation) !void {959 fn maybeLink(self: *Compilation) !void {
989 (self.prelink_group.wait()) catch |err| switch (err) {960 (self.prelink_group.wait()) catch |err| switch (err) {
990 error.SemanticAnalysisFailed => {},961 error.SemanticAnalysisFailed => {},
991 else => return err,962 else => return err,
...@@ -1169,11 +1140,10 @@ pub const Compilation = struct {...@@ -1169,11 +1140,10 @@ pub const Compilation = struct {
1169 return link_lib;1140 return link_lib;
1170 }1141 }
11711142
1172 /// cancels itself so no need to await or cancel the promise.
1173 async fn startFindingNativeLibC(self: *Compilation) void {1143 async fn startFindingNativeLibC(self: *Compilation) void {
1174 std.event.Loop.instance.?.yield();1144 event.Loop.startCpuBoundOperation();
1175 // we don't care if it fails, we're just trying to kick off the future resolution1145 // we don't care if it fails, we're just trying to kick off the future resolution
1176 _ = (self.zig_compiler.getNativeLibC()) catch return;1146 _ = self.zig_compiler.getNativeLibC() catch return;
1177 }1147 }
11781148
1179 /// General Purpose Allocator. Must free when done.1149 /// General Purpose Allocator. Must free when done.
...@@ -1188,7 +1158,7 @@ pub const Compilation = struct {...@@ -1188,7 +1158,7 @@ pub const Compilation = struct {
11881158
1189 /// If the temporary directory for this compilation has not been created, it creates it.1159 /// If the temporary directory for this compilation has not been created, it creates it.
1190 /// Then it creates a random file name in that dir and returns it.1160 /// Then it creates a random file name in that dir and returns it.
1191 pub async fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer {1161 pub fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer {
1192 const tmp_dir = try self.getTmpDir();1162 const tmp_dir = try self.getTmpDir();
1193 const file_prefix = self.getRandomFileName();1163 const file_prefix = self.getRandomFileName();
11941164
...@@ -1204,14 +1174,14 @@ pub const Compilation = struct {...@@ -1204,14 +1174,14 @@ pub const Compilation = struct {
1204 /// If the temporary directory for this Compilation has not been created, creates it.1174 /// If the temporary directory for this Compilation has not been created, creates it.
1205 /// Then returns it. The directory is unique to this Compilation and cleaned up when1175 /// Then returns it. The directory is unique to this Compilation and cleaned up when
1206 /// the Compilation deinitializes.1176 /// the Compilation deinitializes.
1207 async fn getTmpDir(self: *Compilation) ![]const u8 {1177 fn getTmpDir(self: *Compilation) ![]const u8 {
1208 if (self.tmp_dir.start()) |ptr| return ptr.*;1178 if (self.tmp_dir.start()) |ptr| return ptr.*;
1209 self.tmp_dir.data = self.getTmpDirImpl();1179 self.tmp_dir.data = self.getTmpDirImpl();
1210 self.tmp_dir.resolve();1180 self.tmp_dir.resolve();
1211 return self.tmp_dir.data;1181 return self.tmp_dir.data;
1212 }1182 }
12131183
1214 async fn getTmpDirImpl(self: *Compilation) ![]u8 {1184 fn getTmpDirImpl(self: *Compilation) ![]u8 {
1215 const comp_dir_name = self.getRandomFileName();1185 const comp_dir_name = self.getRandomFileName();
1216 const zig_dir_path = try getZigDir(self.gpa());1186 const zig_dir_path = try getZigDir(self.gpa());
1217 defer self.gpa().free(zig_dir_path);1187 defer self.gpa().free(zig_dir_path);
...@@ -1221,7 +1191,7 @@ pub const Compilation = struct {...@@ -1221,7 +1191,7 @@ pub const Compilation = struct {
1221 return tmp_dir;1191 return tmp_dir;
1222 }1192 }
12231193
1224 async fn getRandomFileName(self: *Compilation) [12]u8 {1194 fn getRandomFileName(self: *Compilation) [12]u8 {
1225 // here we replace the standard +/ with -_ so that it can be used in a file name1195 // here we replace the standard +/ with -_ so that it can be used in a file name
1226 const b64_fs_encoder = std.base64.Base64Encoder.init(1196 const b64_fs_encoder = std.base64.Base64Encoder.init(
1227 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",1197 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
...@@ -1247,20 +1217,23 @@ pub const Compilation = struct {...@@ -1247,20 +1217,23 @@ pub const Compilation = struct {
1247 }1217 }
12481218
1249 /// Returns a value which has been ref()'d once1219 /// Returns a value which has been ref()'d once
1250 async fn analyzeConstValue(1220 fn analyzeConstValue(
1251 comp: *Compilation,1221 comp: *Compilation,
1252 tree_scope: *Scope.AstTree,1222 tree_scope: *Scope.AstTree,
1253 scope: *Scope,1223 scope: *Scope,
1254 node: *ast.Node,1224 node: *ast.Node,
1255 expected_type: *Type,1225 expected_type: *Type,
1256 ) !*Value {1226 ) !*Value {
1257 const analyzed_code = try comp.genAndAnalyzeCode(tree_scope, scope, node, expected_type);1227 var frame = try comp.gpa().create(@Frame(genAndAnalyzeCode));
1228 defer comp.gpa().destroy(frame);
1229 frame.* = async comp.genAndAnalyzeCode(tree_scope, scope, node, expected_type);
1230 const analyzed_code = try await frame;
1258 defer analyzed_code.destroy(comp.gpa());1231 defer analyzed_code.destroy(comp.gpa());
12591232
1260 return analyzed_code.getCompTimeResult(comp);1233 return analyzed_code.getCompTimeResult(comp);
1261 }1234 }
12621235
1263 async fn analyzeTypeExpr(comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, node: *ast.Node) !*Type {1236 fn analyzeTypeExpr(comp: *Compilation, tree_scope: *Scope.AstTree, scope: *Scope, node: *ast.Node) !*Type {
1264 const meta_type = &Type.MetaType.get(comp).base;1237 const meta_type = &Type.MetaType.get(comp).base;
1265 defer meta_type.base.deref(comp);1238 defer meta_type.base.deref(comp);
12661239
...@@ -1291,7 +1264,7 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib...@@ -1291,7 +1264,7 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib
1291}1264}
12921265
1293/// The function that actually does the generation.1266/// The function that actually does the generation.
1294async fn generateDecl(comp: *Compilation, decl: *Decl) !void {1267fn generateDecl(comp: *Compilation, decl: *Decl) !void {
1295 switch (decl.id) {1268 switch (decl.id) {
1296 .Var => @panic("TODO"),1269 .Var => @panic("TODO"),
1297 .Fn => {1270 .Fn => {
...@@ -1302,7 +1275,7 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {...@@ -1302,7 +1275,7 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
1302 }1275 }
1303}1276}
13041277
1305async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {1278fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1306 const tree_scope = fn_decl.base.tree_scope;1279 const tree_scope = fn_decl.base.tree_scope;
13071280
1308 const body_node = fn_decl.fn_proto.body_node orelse return generateDeclFnProto(comp, fn_decl);1281 const body_node = fn_decl.fn_proto.body_node orelse return generateDeclFnProto(comp, fn_decl);
...@@ -1319,7 +1292,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1319,7 +1292,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
13191292
1320 // The Decl.Fn owns the initial 1 reference count1293 // The Decl.Fn owns the initial 1 reference count
1321 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);1294 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
1322 fn_decl.value = Decl.Fn.Val{ .Fn = fn_val };1295 fn_decl.value = .{ .Fn = fn_val };
1323 symbol_name_consumed = true;1296 symbol_name_consumed = true;
13241297
1325 // Define local parameter variables1298 // Define local parameter variables
...@@ -1354,12 +1327,15 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1354,12 +1327,15 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1354 try fn_type.non_key.Normal.variable_list.append(var_scope);1327 try fn_type.non_key.Normal.variable_list.append(var_scope);
1355 }1328 }
13561329
1357 const analyzed_code = try comp.genAndAnalyzeCode(1330 var frame = try comp.gpa().create(@Frame(Compilation.genAndAnalyzeCode));
1331 defer comp.gpa().destroy(frame);
1332 frame.* = async comp.genAndAnalyzeCode(
1358 tree_scope,1333 tree_scope,
1359 fn_val.child_scope,1334 fn_val.child_scope,
1360 body_node,1335 body_node,
1361 fn_type.key.data.Normal.return_type,1336 fn_type.key.data.Normal.return_type,
1362 );1337 );
1338 const analyzed_code = try await frame;
1363 errdefer analyzed_code.destroy(comp.gpa());1339 errdefer analyzed_code.destroy(comp.gpa());
13641340
1365 assert(fn_val.block_scope != null);1341 assert(fn_val.block_scope != null);
...@@ -1386,7 +1362,7 @@ fn getZigDir(allocator: *mem.Allocator) ![]u8 {...@@ -1386,7 +1362,7 @@ fn getZigDir(allocator: *mem.Allocator) ![]u8 {
1386 return std.fs.getAppDataDir(allocator, "zig");1362 return std.fs.getAppDataDir(allocator, "zig");
1387}1363}
13881364
1389async fn analyzeFnType(1365fn analyzeFnType(
1390 comp: *Compilation,1366 comp: *Compilation,
1391 tree_scope: *Scope.AstTree,1367 tree_scope: *Scope.AstTree,
1392 scope: *Scope,1368 scope: *Scope,
...@@ -1448,7 +1424,7 @@ async fn analyzeFnType(...@@ -1448,7 +1424,7 @@ async fn analyzeFnType(
1448 return fn_type;1424 return fn_type;
1449}1425}
14501426
1451async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {1427fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1452 const fn_type = try analyzeFnType(1428 const fn_type = try analyzeFnType(
1453 comp,1429 comp,
1454 fn_decl.base.tree_scope,1430 fn_decl.base.tree_scope,
...@@ -1463,6 +1439,6 @@ async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1463,6 +1439,6 @@ async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
14631439
1464 // The Decl.Fn owns the initial 1 reference count1440 // The Decl.Fn owns the initial 1 reference count
1465 const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name);1441 const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name);
1466 fn_decl.value = Decl.Fn.Val{ .FnProto = fn_proto_val };1442 fn_decl.value = .{ .FnProto = fn_proto_val };
1467 symbol_name_consumed = true;1443 symbol_name_consumed = true;
1468}1444}
src-self-hosted/decl.zig+3-6
...@@ -69,15 +69,12 @@ pub const Decl = struct {...@@ -69,15 +69,12 @@ pub const Decl = struct {
6969
70 pub const Fn = struct {70 pub const Fn = struct {
71 base: Decl,71 base: Decl,
72 value: Val,72 value: union(enum) {
73 fn_proto: *ast.Node.FnProto,
74
75 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous
76 pub const Val = union(enum) {
77 Unresolved,73 Unresolved,
78 Fn: *Value.Fn,74 Fn: *Value.Fn,
79 FnProto: *Value.FnProto,75 FnProto: *Value.FnProto,
80 };76 },
77 fn_proto: *ast.Node.FnProto,
8178
82 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {79 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {
83 return if (self.fn_proto.extern_export_inline_token) |tok_index| x: {80 return if (self.fn_proto.extern_export_inline_token) |tok_index| x: {
src-self-hosted/ir.zig+38-30
...@@ -110,7 +110,7 @@ pub const Inst = struct {...@@ -110,7 +110,7 @@ pub const Inst = struct {
110 unreachable;110 unreachable;
111 }111 }
112112
113 pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {113 pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
114 switch (base.id) {114 switch (base.id) {
115 .Return => return @fieldParentPtr(Return, "base", base).analyze(ira),115 .Return => return @fieldParentPtr(Return, "base", base).analyze(ira),
116 .Const => return @fieldParentPtr(Const, "base", base).analyze(ira),116 .Const => return @fieldParentPtr(Const, "base", base).analyze(ira),
...@@ -422,7 +422,7 @@ pub const Inst = struct {...@@ -422,7 +422,7 @@ pub const Inst = struct {
422 return false;422 return false;
423 }423 }
424424
425 pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst {425 pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
426 const target = try self.params.target.getAsParam();426 const target = try self.params.target.getAsParam();
427427
428 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {428 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
...@@ -472,7 +472,7 @@ pub const Inst = struct {...@@ -472,7 +472,7 @@ pub const Inst = struct {
472 return false;472 return false;
473 }473 }
474474
475 pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {475 pub fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {
476 (ira.irb.comp.resolveDecl(self.params.decl)) catch |err| switch (err) {476 (ira.irb.comp.resolveDecl(self.params.decl)) catch |err| switch (err) {
477 error.OutOfMemory => return error.OutOfMemory,477 error.OutOfMemory => return error.OutOfMemory,
478 else => return error.SemanticAnalysisFailed,478 else => return error.SemanticAnalysisFailed,
...@@ -516,7 +516,7 @@ pub const Inst = struct {...@@ -516,7 +516,7 @@ pub const Inst = struct {
516 return false;516 return false;
517 }517 }
518518
519 pub async fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst {519 pub fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst {
520 switch (self.params.var_scope.data) {520 switch (self.params.var_scope.data) {
521 .Const => @panic("TODO"),521 .Const => @panic("TODO"),
522 .Param => |param| {522 .Param => |param| {
...@@ -563,7 +563,7 @@ pub const Inst = struct {...@@ -563,7 +563,7 @@ pub const Inst = struct {
563 return false;563 return false;
564 }564 }
565565
566 pub async fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst {566 pub fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst {
567 const target = try self.params.target.getAsParam();567 const target = try self.params.target.getAsParam();
568 const target_type = target.getKnownType();568 const target_type = target.getKnownType();
569 if (target_type.id != .Pointer) {569 if (target_type.id != .Pointer) {
...@@ -645,7 +645,7 @@ pub const Inst = struct {...@@ -645,7 +645,7 @@ pub const Inst = struct {
645 return false;645 return false;
646 }646 }
647647
648 pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {648 pub fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {
649 const child_type = try self.params.child_type.getAsConstType(ira);649 const child_type = try self.params.child_type.getAsConstType(ira);
650 // if (child_type->id == TypeTableEntryIdUnreachable) {650 // if (child_type->id == TypeTableEntryIdUnreachable) {
651 // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));651 // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
...@@ -658,7 +658,7 @@ pub const Inst = struct {...@@ -658,7 +658,7 @@ pub const Inst = struct {
658 const amt = try align_inst.getAsConstAlign(ira);658 const amt = try align_inst.getAsConstAlign(ira);
659 break :blk Type.Pointer.Align{ .Override = amt };659 break :blk Type.Pointer.Align{ .Override = amt };
660 } else blk: {660 } else blk: {
661 break :blk Type.Pointer.Align{ .Abi = {} };661 break :blk .Abi;
662 };662 };
663 const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{663 const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
664 .child_type = child_type,664 .child_type = child_type,
...@@ -927,7 +927,7 @@ pub const Variable = struct {...@@ -927,7 +927,7 @@ pub const Variable = struct {
927927
928pub const BasicBlock = struct {928pub const BasicBlock = struct {
929 ref_count: usize,929 ref_count: usize,
930 name_hint: [*]const u8, // must be a C string literal930 name_hint: [*:0]const u8,
931 debug_id: usize,931 debug_id: usize,
932 scope: *Scope,932 scope: *Scope,
933 instruction_list: std.ArrayList(*Inst),933 instruction_list: std.ArrayList(*Inst),
...@@ -1051,7 +1051,7 @@ pub const Builder = struct {...@@ -1051,7 +1051,7 @@ pub const Builder = struct {
1051 }1051 }
10521052
1053 /// No need to clean up resources thanks to the arena allocator.1053 /// No need to clean up resources thanks to the arena allocator.
1054 pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*]const u8) !*BasicBlock {1054 pub fn createBasicBlock(self: *Builder, scope: *Scope, name_hint: [*:0]const u8) !*BasicBlock {
1055 const basic_block = try self.arena().create(BasicBlock);1055 const basic_block = try self.arena().create(BasicBlock);
1056 basic_block.* = BasicBlock{1056 basic_block.* = BasicBlock{
1057 .ref_count = 0,1057 .ref_count = 0,
...@@ -1078,6 +1078,14 @@ pub const Builder = struct {...@@ -1078,6 +1078,14 @@ pub const Builder = struct {
1078 self.current_basic_block = basic_block;1078 self.current_basic_block = basic_block;
1079 }1079 }
10801080
1081 pub fn genNodeRecursive(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
1082 const alloc = irb.comp.gpa();
1083 var frame = try alloc.create(@Frame(genNode));
1084 defer alloc.destroy(frame);
1085 frame.* = async irb.genNode(node, scope, lval);
1086 return await frame;
1087 }
1088
1081 pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {1089 pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
1082 switch (node.id) {1090 switch (node.id) {
1083 .Root => unreachable,1091 .Root => unreachable,
...@@ -1157,7 +1165,7 @@ pub const Builder = struct {...@@ -1157,7 +1165,7 @@ pub const Builder = struct {
1157 },1165 },
1158 .GroupedExpression => {1166 .GroupedExpression => {
1159 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);1167 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
1160 return irb.genNode(grouped_expr.expr, scope, lval);1168 return irb.genNodeRecursive(grouped_expr.expr, scope, lval);
1161 },1169 },
1162 .BuiltinCall => return error.Unimplemented,1170 .BuiltinCall => return error.Unimplemented,
1163 .ErrorSetDecl => return error.Unimplemented,1171 .ErrorSetDecl => return error.Unimplemented,
...@@ -1186,14 +1194,14 @@ pub const Builder = struct {...@@ -1186,14 +1194,14 @@ pub const Builder = struct {
1186 }1194 }
1187 }1195 }
11881196
1189 async fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {1197 fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
1190 const fn_ref = try irb.genNode(suffix_op.lhs, scope, .None);1198 const fn_ref = try irb.genNodeRecursive(suffix_op.lhs.node, scope, .None);
11911199
1192 const args = try irb.arena().alloc(*Inst, call.params.len);1200 const args = try irb.arena().alloc(*Inst, call.params.len);
1193 var it = call.params.iterator(0);1201 var it = call.params.iterator(0);
1194 var i: usize = 0;1202 var i: usize = 0;
1195 while (it.next()) |arg_node_ptr| : (i += 1) {1203 while (it.next()) |arg_node_ptr| : (i += 1) {
1196 args[i] = try irb.genNode(arg_node_ptr.*, scope, .None);1204 args[i] = try irb.genNodeRecursive(arg_node_ptr.*, scope, .None);
1197 }1205 }
11981206
1199 //bool is_async = node->data.fn_call_expr.is_async;1207 //bool is_async = node->data.fn_call_expr.is_async;
...@@ -1214,7 +1222,7 @@ pub const Builder = struct {...@@ -1214,7 +1222,7 @@ pub const Builder = struct {
1214 //return ir_lval_wrap(irb, scope, fn_call, lval);1222 //return ir_lval_wrap(irb, scope, fn_call, lval);
1215 }1223 }
12161224
1217 async fn genPtrType(1225 fn genPtrType(
1218 irb: *Builder,1226 irb: *Builder,
1219 prefix_op: *ast.Node.PrefixOp,1227 prefix_op: *ast.Node.PrefixOp,
1220 ptr_info: ast.Node.PrefixOp.PtrInfo,1228 ptr_info: ast.Node.PrefixOp.PtrInfo,
...@@ -1238,7 +1246,7 @@ pub const Builder = struct {...@@ -1238,7 +1246,7 @@ pub const Builder = struct {
1238 //} else {1246 //} else {
1239 // align_value = nullptr;1247 // align_value = nullptr;
1240 //}1248 //}
1241 const child_type = try irb.genNode(prefix_op.rhs, scope, .None);1249 const child_type = try irb.genNodeRecursive(prefix_op.rhs, scope, .None);
12421250
1243 //uint32_t bit_offset_start = 0;1251 //uint32_t bit_offset_start = 0;
1244 //if (node->data.pointer_type.bit_offset_start != nullptr) {1252 //if (node->data.pointer_type.bit_offset_start != nullptr) {
...@@ -1307,9 +1315,9 @@ pub const Builder = struct {...@@ -1307,9 +1315,9 @@ pub const Builder = struct {
1307 var rest: []const u8 = undefined;1315 var rest: []const u8 = undefined;
1308 if (int_token.len >= 3 and int_token[0] == '0') {1316 if (int_token.len >= 3 and int_token[0] == '0') {
1309 base = switch (int_token[1]) {1317 base = switch (int_token[1]) {
1310 'b' => u8(2),1318 'b' => 2,
1311 'o' => u8(8),1319 'o' => 8,
1312 'x' => u8(16),1320 'x' => 16,
1313 else => unreachable,1321 else => unreachable,
1314 };1322 };
1315 rest = int_token[2..];1323 rest = int_token[2..];
...@@ -1339,7 +1347,7 @@ pub const Builder = struct {...@@ -1339,7 +1347,7 @@ pub const Builder = struct {
1339 return inst;1347 return inst;
1340 }1348 }
13411349
1342 pub async fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst {1350 pub fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst {
1343 const str_token = irb.code.tree_scope.tree.tokenSlice(str_lit.token);1351 const str_token = irb.code.tree_scope.tree.tokenSlice(str_lit.token);
1344 const src_span = Span.token(str_lit.token);1352 const src_span = Span.token(str_lit.token);
13451353
...@@ -1389,7 +1397,7 @@ pub const Builder = struct {...@@ -1389,7 +1397,7 @@ pub const Builder = struct {
1389 }1397 }
1390 }1398 }
13911399
1392 pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {1400 pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
1393 const block_scope = try Scope.Block.create(irb.comp, parent_scope);1401 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
13941402
1395 const outer_block_scope = &block_scope.base;1403 const outer_block_scope = &block_scope.base;
...@@ -1437,7 +1445,7 @@ pub const Builder = struct {...@@ -1437,7 +1445,7 @@ pub const Builder = struct {
1437 child_scope = &defer_child_scope.base;1445 child_scope = &defer_child_scope.base;
1438 continue;1446 continue;
1439 }1447 }
1440 const statement_value = try irb.genNode(statement_node, child_scope, .None);1448 const statement_value = try irb.genNodeRecursive(statement_node, child_scope, .None);
14411449
1442 is_continuation_unreachable = statement_value.isNoReturn();1450 is_continuation_unreachable = statement_value.isNoReturn();
1443 if (is_continuation_unreachable) {1451 if (is_continuation_unreachable) {
...@@ -1499,7 +1507,7 @@ pub const Builder = struct {...@@ -1499,7 +1507,7 @@ pub const Builder = struct {
1499 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);1507 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);
1500 }1508 }
15011509
1502 pub async fn genControlFlowExpr(1510 pub fn genControlFlowExpr(
1503 irb: *Builder,1511 irb: *Builder,
1504 control_flow_expr: *ast.Node.ControlFlowExpression,1512 control_flow_expr: *ast.Node.ControlFlowExpression,
1505 scope: *Scope,1513 scope: *Scope,
...@@ -1533,7 +1541,7 @@ pub const Builder = struct {...@@ -1533,7 +1541,7 @@ pub const Builder = struct {
15331541
1534 const outer_scope = irb.begin_scope.?;1542 const outer_scope = irb.begin_scope.?;
1535 const return_value = if (control_flow_expr.rhs) |rhs| blk: {1543 const return_value = if (control_flow_expr.rhs) |rhs| blk: {
1536 break :blk try irb.genNode(rhs, scope, .None);1544 break :blk try irb.genNodeRecursive(rhs, scope, .None);
1537 } else blk: {1545 } else blk: {
1538 break :blk try irb.buildConstVoid(scope, src_span, true);1546 break :blk try irb.buildConstVoid(scope, src_span, true);
1539 };1547 };
...@@ -1596,7 +1604,7 @@ pub const Builder = struct {...@@ -1596,7 +1604,7 @@ pub const Builder = struct {
1596 }1604 }
1597 }1605 }
15981606
1599 pub async fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst {1607 pub fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst {
1600 const src_span = Span.token(identifier.token);1608 const src_span = Span.token(identifier.token);
1601 const name = irb.code.tree_scope.tree.tokenSlice(identifier.token);1609 const name = irb.code.tree_scope.tree.tokenSlice(identifier.token);
16021610
...@@ -1694,7 +1702,7 @@ pub const Builder = struct {...@@ -1694,7 +1702,7 @@ pub const Builder = struct {
1694 return result;1702 return result;
1695 }1703 }
16961704
1697 async fn genDefersForBlock(1705 fn genDefersForBlock(
1698 irb: *Builder,1706 irb: *Builder,
1699 inner_scope: *Scope,1707 inner_scope: *Scope,
1700 outer_scope: *Scope,1708 outer_scope: *Scope,
...@@ -1712,7 +1720,7 @@ pub const Builder = struct {...@@ -1712,7 +1720,7 @@ pub const Builder = struct {
1712 };1720 };
1713 if (generate) {1721 if (generate) {
1714 const defer_expr_scope = defer_scope.defer_expr_scope;1722 const defer_expr_scope = defer_scope.defer_expr_scope;
1715 const instruction = try irb.genNode(1723 const instruction = try irb.genNodeRecursive(
1716 defer_expr_scope.expr_node,1724 defer_expr_scope.expr_node,
1717 &defer_expr_scope.base,1725 &defer_expr_scope.base,
1718 .None,1726 .None,
...@@ -1797,7 +1805,7 @@ pub const Builder = struct {...@@ -1797,7 +1805,7 @@ pub const Builder = struct {
1797 // Look at the params and ref() other instructions1805 // Look at the params and ref() other instructions
1798 comptime var i = 0;1806 comptime var i = 0;
1799 inline while (i < @memberCount(I.Params)) : (i += 1) {1807 inline while (i < @memberCount(I.Params)) : (i += 1) {
1800 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));1808 const FieldType = comptime @typeOf(@field(@as(I.Params, undefined), @memberName(I.Params, i)));
1801 switch (FieldType) {1809 switch (FieldType) {
1802 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),1810 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
1803 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),1811 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),
...@@ -1909,7 +1917,7 @@ pub const Builder = struct {...@@ -1909,7 +1917,7 @@ pub const Builder = struct {
1909 VarScope: *Scope.Var,1917 VarScope: *Scope.Var,
1910 };1918 };
19111919
1912 async fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident {1920 fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident {
1913 var s = scope;1921 var s = scope;
1914 while (true) {1922 while (true) {
1915 switch (s.id) {1923 switch (s.id) {
...@@ -2519,7 +2527,7 @@ const Analyze = struct {...@@ -2519,7 +2527,7 @@ const Analyze = struct {
2519 }2527 }
2520};2528};
25212529
2522pub async fn gen(2530pub fn gen(
2523 comp: *Compilation,2531 comp: *Compilation,
2524 body_node: *ast.Node,2532 body_node: *ast.Node,
2525 tree_scope: *Scope.AstTree,2533 tree_scope: *Scope.AstTree,
...@@ -2541,7 +2549,7 @@ pub async fn gen(...@@ -2541,7 +2549,7 @@ pub async fn gen(
2541 return irb.finish();2549 return irb.finish();
2542}2550}
25432551
2544pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code {2552pub fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code {
2545 const old_entry_bb = old_code.basic_block_list.at(0);2553 const old_entry_bb = old_code.basic_block_list.at(0);
25462554
2547 var ira = try Analyze.init(comp, old_code.tree_scope, expected_type);2555 var ira = try Analyze.init(comp, old_code.tree_scope, expected_type);
src-self-hosted/libc_installation.zig+3-3
...@@ -143,7 +143,7 @@ pub const LibCInstallation = struct {...@@ -143,7 +143,7 @@ pub const LibCInstallation = struct {
143 }143 }
144144
145 /// Finds the default, native libc.145 /// Finds the default, native libc.
146 pub async fn findNative(self: *LibCInstallation, allocator: *Allocator) !void {146 pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void {
147 self.initEmpty();147 self.initEmpty();
148 var group = event.Group(FindError!void).init(allocator);148 var group = event.Group(FindError!void).init(allocator);
149 errdefer group.wait() catch {};149 errdefer group.wait() catch {};
...@@ -393,14 +393,14 @@ pub const LibCInstallation = struct {...@@ -393,14 +393,14 @@ pub const LibCInstallation = struct {
393};393};
394394
395/// caller owns returned memory395/// caller owns returned memory
396async fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 {396fn ccPrintFileName(allocator: *Allocator, o_file: []const u8, want_dirname: bool) ![]u8 {
397 const cc_exe = std.os.getenv("CC") orelse "cc";397 const cc_exe = std.os.getenv("CC") orelse "cc";
398 const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", o_file);398 const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", o_file);
399 defer allocator.free(arg1);399 defer allocator.free(arg1);
400 const argv = [_][]const u8{ cc_exe, arg1 };400 const argv = [_][]const u8{ cc_exe, arg1 };
401401
402 // TODO This simulates evented I/O for the child process exec402 // TODO This simulates evented I/O for the child process exec
403 std.event.Loop.instance.?.yield();403 event.Loop.startCpuBoundOperation();
404 const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024);404 const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024);
405 const exec_result = if (std.debug.runtime_safety) blk: {405 const exec_result = if (std.debug.runtime_safety) blk: {
406 break :blk errorable_result catch unreachable;406 break :blk errorable_result catch unreachable;
src-self-hosted/link.zig+33-35
...@@ -11,7 +11,7 @@ const util = @import("util.zig");...@@ -11,7 +11,7 @@ const util = @import("util.zig");
11const Context = struct {11const Context = struct {
12 comp: *Compilation,12 comp: *Compilation,
13 arena: std.heap.ArenaAllocator,13 arena: std.heap.ArenaAllocator,
14 args: std.ArrayList([*]const u8),14 args: std.ArrayList([*:0]const u8),
15 link_in_crt: bool,15 link_in_crt: bool,
1616
17 link_err: error{OutOfMemory}!void,17 link_err: error{OutOfMemory}!void,
...@@ -21,7 +21,7 @@ const Context = struct {...@@ -21,7 +21,7 @@ const Context = struct {
21 out_file_path: std.Buffer,21 out_file_path: std.Buffer,
22};22};
2323
24pub async fn link(comp: *Compilation) !void {24pub fn link(comp: *Compilation) !void {
25 var ctx = Context{25 var ctx = Context{
26 .comp = comp,26 .comp = comp,
27 .arena = std.heap.ArenaAllocator.init(comp.gpa()),27 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
...@@ -33,7 +33,7 @@ pub async fn link(comp: *Compilation) !void {...@@ -33,7 +33,7 @@ pub async fn link(comp: *Compilation) !void {
33 .out_file_path = undefined,33 .out_file_path = undefined,
34 };34 };
35 defer ctx.arena.deinit();35 defer ctx.arena.deinit();
36 ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator);36 ctx.args = std.ArrayList([*:0]const u8).init(&ctx.arena.allocator);
37 ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);37 ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);
3838
39 if (comp.link_out_file) |out_file| {39 if (comp.link_out_file) |out_file| {
...@@ -58,7 +58,8 @@ pub async fn link(comp: *Compilation) !void {...@@ -58,7 +58,8 @@ pub async fn link(comp: *Compilation) !void {
58 try ctx.args.append("lld");58 try ctx.args.append("lld");
5959
60 if (comp.haveLibC()) {60 if (comp.haveLibC()) {
61 ctx.libc = ctx.comp.override_libc orelse blk: {61 // TODO https://github.com/ziglang/zig/issues/3190
62 var libc = ctx.comp.override_libc orelse blk: {
62 switch (comp.target) {63 switch (comp.target) {
63 Target.Native => {64 Target.Native => {
64 break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;65 break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;
...@@ -66,6 +67,7 @@ pub async fn link(comp: *Compilation) !void {...@@ -66,6 +67,7 @@ pub async fn link(comp: *Compilation) !void {
66 else => return error.LibCRequiredButNotProvidedOrFound,67 else => return error.LibCRequiredButNotProvidedOrFound,
67 }68 }
68 };69 };
70 ctx.libc = libc;
69 }71 }
7072
71 try constructLinkerArgs(&ctx);73 try constructLinkerArgs(&ctx);
...@@ -171,7 +173,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -171,7 +173,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
171 //}173 //}
172174
173 try ctx.args.append("-o");175 try ctx.args.append("-o");
174 try ctx.args.append(ctx.out_file_path.ptr());176 try ctx.args.append(ctx.out_file_path.toSliceConst());
175177
176 if (ctx.link_in_crt) {178 if (ctx.link_in_crt) {
177 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";179 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
...@@ -214,10 +216,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -214,10 +216,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
214216
215 if (ctx.comp.haveLibC()) {217 if (ctx.comp.haveLibC()) {
216 try ctx.args.append("-L");218 try ctx.args.append("-L");
217 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr);219 // TODO addNullByte should probably return [:0]u8
220 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr));
218221
219 try ctx.args.append("-L");222 try ctx.args.append("-L");
220 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr);223 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr));
221224
222 if (!ctx.comp.is_static) {225 if (!ctx.comp.is_static) {
223 const dl = blk: {226 const dl = blk: {
...@@ -226,7 +229,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -226,7 +229,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
226 return error.LibCMissingDynamicLinker;229 return error.LibCMissingDynamicLinker;
227 };230 };
228 try ctx.args.append("-dynamic-linker");231 try ctx.args.append("-dynamic-linker");
229 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr);232 try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr));
230 }233 }
231 }234 }
232235
...@@ -238,7 +241,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -238,7 +241,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
238 // .o files241 // .o files
239 for (ctx.comp.link_objects) |link_object| {242 for (ctx.comp.link_objects) |link_object| {
240 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);243 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
241 try ctx.args.append(link_obj_with_null.ptr);244 try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr));
242 }245 }
243 try addFnObjects(ctx);246 try addFnObjects(ctx);
244247
...@@ -313,7 +316,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -313,7 +316,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
313fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {316fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
314 const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename });317 const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename });
315 const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);318 const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
316 try ctx.args.append(full_path_with_null.ptr);319 try ctx.args.append(@ptrCast([*:0]const u8, full_path_with_null.ptr));
317}320}
318321
319fn constructLinkerArgsCoff(ctx: *Context) !void {322fn constructLinkerArgsCoff(ctx: *Context) !void {
...@@ -339,12 +342,12 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {...@@ -339,12 +342,12 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
339 const is_library = ctx.comp.kind == .Lib;342 const is_library = ctx.comp.kind == .Lib;
340343
341 const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst());344 const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst());
342 try ctx.args.append(out_arg.ptr);345 try ctx.args.append(@ptrCast([*:0]const u8, out_arg.ptr));
343346
344 if (ctx.comp.haveLibC()) {347 if (ctx.comp.haveLibC()) {
345 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr);348 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr));
346 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr);349 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr));
347 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr);350 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr));
348 }351 }
349352
350 if (ctx.link_in_crt) {353 if (ctx.link_in_crt) {
...@@ -353,17 +356,17 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {...@@ -353,17 +356,17 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
353356
354 if (ctx.comp.is_static) {357 if (ctx.comp.is_static) {
355 const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str);358 const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str);
356 try ctx.args.append(cmt_lib_name.ptr);359 try ctx.args.append(@ptrCast([*:0]const u8, cmt_lib_name.ptr));
357 } else {360 } else {
358 const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str);361 const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str);
359 try ctx.args.append(msvcrt_lib_name.ptr);362 try ctx.args.append(@ptrCast([*:0]const u8, msvcrt_lib_name.ptr));
360 }363 }
361364
362 const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str);365 const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str);
363 try ctx.args.append(vcruntime_lib_name.ptr);366 try ctx.args.append(@ptrCast([*:0]const u8, vcruntime_lib_name.ptr));
364367
365 const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str);368 const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str);
366 try ctx.args.append(crt_lib_name.ptr);369 try ctx.args.append(@ptrCast([*:0]const u8, crt_lib_name.ptr));
367370
368 // Visual C++ 2015 Conformance Changes371 // Visual C++ 2015 Conformance Changes
369 // https://msdn.microsoft.com/en-us/library/bb531344.aspx372 // https://msdn.microsoft.com/en-us/library/bb531344.aspx
...@@ -395,7 +398,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {...@@ -395,7 +398,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
395398
396 for (ctx.comp.link_objects) |link_object| {399 for (ctx.comp.link_objects) |link_object| {
397 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);400 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
398 try ctx.args.append(link_obj_with_null.ptr);401 try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr));
399 }402 }
400 try addFnObjects(ctx);403 try addFnObjects(ctx);
401404
...@@ -504,11 +507,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -504,11 +507,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
504 //}507 //}
505508
506 try ctx.args.append("-arch");509 try ctx.args.append("-arch");
507 const darwin_arch_str = try std.cstr.addNullByte(510 try ctx.args.append(util.getDarwinArchString(ctx.comp.target));
508 &ctx.arena.allocator,
509 ctx.comp.target.getDarwinArchString(),
510 );
511 try ctx.args.append(darwin_arch_str.ptr);
512511
513 const platform = try DarwinPlatform.get(ctx.comp);512 const platform = try DarwinPlatform.get(ctx.comp);
514 switch (platform.kind) {513 switch (platform.kind) {
...@@ -517,7 +516,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -517,7 +516,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
517 .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"),516 .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"),
518 }517 }
519 const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro);518 const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro);
520 try ctx.args.append(ver_str.ptr);519 try ctx.args.append(@ptrCast([*:0]const u8, ver_str.ptr));
521520
522 if (ctx.comp.kind == .Exe) {521 if (ctx.comp.kind == .Exe) {
523 if (ctx.comp.is_static) {522 if (ctx.comp.is_static) {
...@@ -528,7 +527,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -528,7 +527,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
528 }527 }
529528
530 try ctx.args.append("-o");529 try ctx.args.append("-o");
531 try ctx.args.append(ctx.out_file_path.ptr());530 try ctx.args.append(ctx.out_file_path.toSliceConst());
532531
533 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {532 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {
534 // Buf *rpath = g->rpath_list.at(i);533 // Buf *rpath = g->rpath_list.at(i);
...@@ -572,7 +571,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -572,7 +571,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
572571
573 for (ctx.comp.link_objects) |link_object| {572 for (ctx.comp.link_objects) |link_object| {
574 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);573 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
575 try ctx.args.append(link_obj_with_null.ptr);574 try ctx.args.append(@ptrCast([*:0]const u8, link_obj_with_null.ptr));
576 }575 }
577 try addFnObjects(ctx);576 try addFnObjects(ctx);
578577
...@@ -593,10 +592,10 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {...@@ -593,10 +592,10 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
593 } else {592 } else {
594 if (mem.indexOfScalar(u8, lib.name, '/') == null) {593 if (mem.indexOfScalar(u8, lib.name, '/') == null) {
595 const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name);594 const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name);
596 try ctx.args.append(arg.ptr);595 try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
597 } else {596 } else {
598 const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);597 const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
599 try ctx.args.append(arg.ptr);598 try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr));
600 }599 }
601 }600 }
602 }601 }
...@@ -626,20 +625,19 @@ fn constructLinkerArgsWasm(ctx: *Context) void {...@@ -626,20 +625,19 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
626}625}
627626
628fn addFnObjects(ctx: *Context) !void {627fn addFnObjects(ctx: *Context) !void {
629 // at this point it's guaranteed nobody else has this lock, so we circumvent it628 const held = ctx.comp.fn_link_set.acquire();
630 // and avoid having to be an async function629 defer held.release();
631 const fn_link_set = &ctx.comp.fn_link_set.private_data;
632630
633 var it = fn_link_set.first;631 var it = held.value.first;
634 while (it) |node| {632 while (it) |node| {
635 const fn_val = node.data orelse {633 const fn_val = node.data orelse {
636 // handle the tombstone. See Value.Fn.destroy.634 // handle the tombstone. See Value.Fn.destroy.
637 it = node.next;635 it = node.next;
638 fn_link_set.remove(node);636 held.value.remove(node);
639 ctx.comp.gpa().destroy(node);637 ctx.comp.gpa().destroy(node);
640 continue;638 continue;
641 };639 };
642 try ctx.args.append(fn_val.containing_object.ptr());640 try ctx.args.append(fn_val.containing_object.toSliceConst());
643 it = node.next;641 it = node.next;
644 }642 }
645}643}
src-self-hosted/llvm.zig+1-1
...@@ -86,7 +86,7 @@ pub const AddGlobal = LLVMAddGlobal;...@@ -86,7 +86,7 @@ pub const AddGlobal = LLVMAddGlobal;
86extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value;86extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value;
8787
88pub const ConstStringInContext = LLVMConstStringInContext;88pub const ConstStringInContext = LLVMConstStringInContext;
89extern fn LLVMConstStringInContext(C: *Context, Str: [*:0]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;89extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value;
9090
91pub const ConstInt = LLVMConstInt;91pub const ConstInt = LLVMConstInt;
92extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;92extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
src-self-hosted/main.zig+64-73
...@@ -49,14 +49,15 @@ const usage =...@@ -49,14 +49,15 @@ const usage =
4949
50const Command = struct {50const Command = struct {
51 name: []const u8,51 name: []const u8,
52 exec: fn (*Allocator, []const []const u8) anyerror!void,52 exec: async fn (*Allocator, []const []const u8) anyerror!void,
53};53};
5454
55pub fn main() !void {55pub fn main() !void {
56 // This allocator needs to be thread-safe because we use it for the event.Loop56 // This allocator needs to be thread-safe because we use it for the event.Loop
57 // which multiplexes async functions onto kernel threads.57 // which multiplexes async functions onto kernel threads.
58 // libc allocator is guaranteed to have this property.58 // libc allocator is guaranteed to have this property.
59 const allocator = std.heap.c_allocator;59 // TODO https://github.com/ziglang/zig/issues/3783
60 const allocator = std.heap.page_allocator;
6061
61 stdout = &std.io.getStdOut().outStream().stream;62 stdout = &std.io.getStdOut().outStream().stream;
6263
...@@ -118,14 +119,18 @@ pub fn main() !void {...@@ -118,14 +119,18 @@ pub fn main() !void {
118 },119 },
119 };120 };
120121
121 for (commands) |command| {122 inline for (commands) |command| {
122 if (mem.eql(u8, command.name, args[1])) {123 if (mem.eql(u8, command.name, args[1])) {
123 return command.exec(allocator, args[2..]);124 var frame = try allocator.create(@Frame(command.exec));
125 defer allocator.destroy(frame);
126 frame.* = async command.exec(allocator, args[2..]);
127 return await frame;
124 }128 }
125 }129 }
126130
127 try stderr.print("unknown command: {}\n\n", args[1]);131 try stderr.print("unknown command: {}\n\n", args[1]);
128 try stderr.write(usage);132 try stderr.write(usage);
133 process.argsFree(allocator, args);
129 process.exit(1);134 process.exit(1);
130}135}
131136
...@@ -461,13 +466,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -461,13 +466,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
461 comp.link_objects = link_objects;466 comp.link_objects = link_objects;
462467
463 comp.start();468 comp.start();
464 const frame = async processBuildEvents(comp, color);469 processBuildEvents(comp, color);
465}470}
466471
467async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {472fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
468 var count: usize = 0;473 var count: usize = 0;
469 while (true) {474 while (!comp.cancelled) {
470 // TODO directly awaiting async should guarantee memory allocation elision
471 const build_event = comp.events.get();475 const build_event = comp.events.get();
472 count += 1;476 count += 1;
473477
...@@ -545,7 +549,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil...@@ -545,7 +549,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil
545 "Try running `zig libc` to see an example for the native target.\n",549 "Try running `zig libc` to see an example for the native target.\n",
546 libc_paths_file,550 libc_paths_file,
547 @errorName(err),551 @errorName(err),
548 ) catch process.exit(1);552 ) catch {};
549 process.exit(1);553 process.exit(1);
550 };554 };
551}555}
...@@ -567,12 +571,8 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {...@@ -567,12 +571,8 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
567 var zig_compiler = try ZigCompiler.init(allocator);571 var zig_compiler = try ZigCompiler.init(allocator);
568 defer zig_compiler.deinit();572 defer zig_compiler.deinit();
569573
570 const frame = async findLibCAsync(&zig_compiler);
571}
572
573async fn findLibCAsync(zig_compiler: *ZigCompiler) void {
574 const libc = zig_compiler.getNativeLibC() catch |err| {574 const libc = zig_compiler.getNativeLibC() catch |err| {
575 stderr.print("unable to find libc: {}\n", @errorName(err)) catch process.exit(1);575 stderr.print("unable to find libc: {}\n", @errorName(err)) catch {};
576 process.exit(1);576 process.exit(1);
577 };577 };
578 libc.render(stdout) catch process.exit(1);578 libc.render(stdout) catch process.exit(1);
...@@ -644,11 +644,23 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -644,11 +644,23 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
644 process.exit(1);644 process.exit(1);
645 }645 }
646646
647 return asyncFmtMain(647 var fmt = Fmt{
648 allocator,648 .allocator = allocator,
649 &flags,649 .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)),
650 color,650 .any_error = false,
651 );651 .color = color,
652 };
653
654 const check_mode = flags.present("check");
655
656 var group = event.Group(FmtError!void).init(allocator);
657 for (flags.positionals.toSliceConst()) |file_path| {
658 try group.call(fmtPath, &fmt, file_path, check_mode);
659 }
660 try group.wait();
661 if (fmt.any_error) {
662 process.exit(1);
663 }
652}664}
653665
654const FmtError = error{666const FmtError = error{
...@@ -673,30 +685,6 @@ const FmtError = error{...@@ -673,30 +685,6 @@ const FmtError = error{
673 CurrentWorkingDirectoryUnlinked,685 CurrentWorkingDirectoryUnlinked,
674} || fs.File.OpenError;686} || fs.File.OpenError;
675687
676async fn asyncFmtMain(
677 allocator: *Allocator,
678 flags: *const Args,
679 color: errmsg.Color,
680) FmtError!void {
681 var fmt = Fmt{
682 .allocator = allocator,
683 .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)),
684 .any_error = false,
685 .color = color,
686 };
687
688 const check_mode = flags.present("check");
689
690 var group = event.Group(FmtError!void).init(allocator);
691 for (flags.positionals.toSliceConst()) |file_path| {
692 try group.call(fmtPath, &fmt, file_path, check_mode);
693 }
694 try group.wait();
695 if (fmt.any_error) {
696 process.exit(1);
697 }
698}
699
700async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {688async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
701 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);689 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
702 defer fmt.allocator.free(file_path);690 defer fmt.allocator.free(file_path);
...@@ -708,33 +696,34 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro...@@ -708,33 +696,34 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
708 if (try held.value.put(file_path, {})) |_| return;696 if (try held.value.put(file_path, {})) |_| return;
709 }697 }
710698
711 const source_code = "";699 const source_code = event.fs.readFile(
712 // const source_code = event.fs.readFile(700 fmt.allocator,
713 // file_path,701 file_path,
714 // max_src_size,702 max_src_size,
715 // ) catch |err| switch (err) {703 ) catch |err| switch (err) {
716 // error.IsDir, error.AccessDenied => {704 error.IsDir, error.AccessDenied => {
717 // // TODO make event based (and dir.next())705 var dir = try fs.cwd().openDirList(file_path);
718 // var dir = try fs.Dir.cwd().openDirList(file_path);706 defer dir.close();
719 // defer dir.close();707
720708 var group = event.Group(FmtError!void).init(fmt.allocator);
721 // var group = event.Group(FmtError!void).init(fmt.allocator);709 var it = dir.iterate();
722 // while (try dir.next()) |entry| {710 while (try it.next()) |entry| {
723 // if (entry.kind == fs.Dir.Entry.Kind.Directory or mem.endsWith(u8, entry.name, ".zig")) {711 if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
724 // const full_path = try fs.path.join(fmt.allocator, [_][]const u8{ file_path, entry.name });712 const full_path = try fs.path.join(fmt.allocator, [_][]const u8{ file_path, entry.name });
725 // try group.call(fmtPath, fmt, full_path, check_mode);713 @panic("TODO https://github.com/ziglang/zig/issues/3777");
726 // }714 // try group.call(fmtPath, fmt, full_path, check_mode);
727 // }715 }
728 // return group.wait();716 }
729 // },717 return group.wait();
730 // else => {718 },
731 // // TODO lock stderr printing719 else => {
732 // try stderr.print("unable to open '{}': {}\n", file_path, err);720 // TODO lock stderr printing
733 // fmt.any_error = true;721 try stderr.print("unable to open '{}': {}\n", file_path, err);
734 // return;722 fmt.any_error = true;
735 // },723 return;
736 // };724 },
737 // defer fmt.allocator.free(source_code);725 };
726 defer fmt.allocator.free(source_code);
738727
739 const tree = std.zig.parse(fmt.allocator, source_code) catch |err| {728 const tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
740 try stderr.print("error parsing file '{}': {}\n", file_path, err);729 try stderr.print("error parsing file '{}': {}\n", file_path, err);
...@@ -867,10 +856,12 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {...@@ -867,10 +856,12 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
867 .exec = cmdInternalBuildInfo,856 .exec = cmdInternalBuildInfo,
868 }};857 }};
869858
870 for (sub_commands) |sub_command| {859 inline for (sub_commands) |sub_command| {
871 if (mem.eql(u8, sub_command.name, args[0])) {860 if (mem.eql(u8, sub_command.name, args[0])) {
872 try sub_command.exec(allocator, args[1..]);861 var frame = try allocator.create(@Frame(sub_command.exec));
873 return;862 defer allocator.destroy(frame);
863 frame.* = async sub_command.exec(allocator, args[1..]);
864 return await frame;
874 }865 }
875 }866 }
876867
src-self-hosted/stage1.zig+4-4
...@@ -279,7 +279,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void...@@ -279,7 +279,7 @@ fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void
279 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {279 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
280 error.IsDir, error.AccessDenied => {280 error.IsDir, error.AccessDenied => {
281 // TODO make event based (and dir.next())281 // TODO make event based (and dir.next())
282 var dir = try fs.Dir.cwd().openDirList(file_path);282 var dir = try fs.cwd().openDirList(file_path);
283 defer dir.close();283 defer dir.close();
284284
285 var dir_it = dir.iterate();285 var dir_it = dir.iterate();
...@@ -427,11 +427,11 @@ export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextRes...@@ -427,11 +427,11 @@ export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextRes
427 };427 };
428}428}
429429
430export const stage2_DepTokenizer = extern struct {430const stage2_DepTokenizer = extern struct {
431 handle: *DepTokenizer,431 handle: *DepTokenizer,
432};432};
433433
434export const stage2_DepNextResult = extern struct {434const stage2_DepNextResult = extern struct {
435 type_id: TypeId,435 type_id: TypeId,
436436
437 // when type_id == error --> error text437 // when type_id == error --> error text
...@@ -440,7 +440,7 @@ export const stage2_DepNextResult = extern struct {...@@ -440,7 +440,7 @@ export const stage2_DepNextResult = extern struct {
440 // when type_id == prereq --> prereq pathname440 // when type_id == prereq --> prereq pathname
441 textz: [*]const u8,441 textz: [*]const u8,
442442
443 export const TypeId = extern enum {443 const TypeId = extern enum {
444 error_,444 error_,
445 null_,445 null_,
446 target,446 target,
src-self-hosted/test.zig+11-13
...@@ -26,7 +26,8 @@ test "stage2" {...@@ -26,7 +26,8 @@ test "stage2" {
26}26}
2727
28const file1 = "1.zig";28const file1 = "1.zig";
29const allocator = std.heap.c_allocator;29// TODO https://github.com/ziglang/zig/issues/3783
30const allocator = std.heap.page_allocator;
3031
31pub const TestContext = struct {32pub const TestContext = struct {
32 zig_compiler: ZigCompiler,33 zig_compiler: ZigCompiler,
...@@ -94,8 +95,8 @@ pub const TestContext = struct {...@@ -94,8 +95,8 @@ pub const TestContext = struct {
94 &self.zig_compiler,95 &self.zig_compiler,
95 "test",96 "test",
96 file1_path,97 file1_path,
97 Target.Native,98 .Native,
98 Compilation.Kind.Obj,99 .Obj,
99 .Debug,100 .Debug,
100 true, // is_static101 true, // is_static
101 self.zig_lib_dir,102 self.zig_lib_dir,
...@@ -116,7 +117,7 @@ pub const TestContext = struct {...@@ -116,7 +117,7 @@ pub const TestContext = struct {
116 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());117 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
117 const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });118 const file1_path = try std.fs.path.join(allocator, [_][]const u8{ tmp_dir_name, file_index, file1 });
118119
119 const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, (Target{.Native = {}}).exeFileExt());120 const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, (Target{ .Native = {} }).exeFileExt());
120 if (std.fs.path.dirname(file1_path)) |dirname| {121 if (std.fs.path.dirname(file1_path)) |dirname| {
121 try std.fs.makePath(allocator, dirname);122 try std.fs.makePath(allocator, dirname);
122 }123 }
...@@ -128,8 +129,8 @@ pub const TestContext = struct {...@@ -128,8 +129,8 @@ pub const TestContext = struct {
128 &self.zig_compiler,129 &self.zig_compiler,
129 "test",130 "test",
130 file1_path,131 file1_path,
131 Target.Native,132 .Native,
132 Compilation.Kind.Exe,133 .Exe,
133 .Debug,134 .Debug,
134 false,135 false,
135 self.zig_lib_dir,136 self.zig_lib_dir,
...@@ -148,15 +149,12 @@ pub const TestContext = struct {...@@ -148,15 +149,12 @@ pub const TestContext = struct {
148 exe_file: []const u8,149 exe_file: []const u8,
149 expected_output: []const u8,150 expected_output: []const u8,
150 ) anyerror!void {151 ) anyerror!void {
151 // TODO this should not be necessary
152 const exe_file_2 = try std.mem.dupe(allocator, u8, exe_file);
153
154 defer comp.destroy();152 defer comp.destroy();
155 const build_event = comp.events.get();153 const build_event = comp.events.get();
156154
157 switch (build_event) {155 switch (build_event) {
158 .Ok => {156 .Ok => {
159 const argv = [_][]const u8{exe_file_2};157 const argv = [_][]const u8{exe_file};
160 // TODO use event loop158 // TODO use event loop
161 const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);159 const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
162 switch (child.term) {160 switch (child.term) {
...@@ -173,13 +171,13 @@ pub const TestContext = struct {...@@ -173,13 +171,13 @@ pub const TestContext = struct {
173 return error.OutputMismatch;171 return error.OutputMismatch;
174 }172 }
175 },173 },
176 Compilation.Event.Error => |err| return err,174 .Error => @panic("Cannot return error: https://github.com/ziglang/zig/issues/3190"), // |err| return err,
177 Compilation.Event.Fail => |msgs| {175 .Fail => |msgs| {
178 const stderr = std.io.getStdErr();176 const stderr = std.io.getStdErr();
179 try stderr.write("build incorrectly failed:\n");177 try stderr.write("build incorrectly failed:\n");
180 for (msgs) |msg| {178 for (msgs) |msg| {
181 defer msg.destroy();179 defer msg.destroy();
182 try msg.printToFile(stderr, errmsg.Color.Auto);180 try msg.printToFile(stderr, .Auto);
183 }181 }
184 },182 },
185 }183 }
src-self-hosted/type.zig+14-12
...@@ -53,7 +53,7 @@ pub const Type = struct {...@@ -53,7 +53,7 @@ pub const Type = struct {
53 base: *Type,53 base: *Type,
54 allocator: *Allocator,54 allocator: *Allocator,
55 llvm_context: *llvm.Context,55 llvm_context: *llvm.Context,
56 ) (error{OutOfMemory}!*llvm.Type) {56 ) error{OutOfMemory}!*llvm.Type {
57 switch (base.id) {57 switch (base.id) {
58 .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),58 .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
59 .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),59 .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
...@@ -184,7 +184,7 @@ pub const Type = struct {...@@ -184,7 +184,7 @@ pub const Type = struct {
184184
185 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.185 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
186 /// Otherwise, this one will grab one from the pool and then release it.186 /// Otherwise, this one will grab one from the pool and then release it.
187 pub async fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 {187 pub fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 {
188 if (base.abi_alignment.start()) |ptr| return ptr.*;188 if (base.abi_alignment.start()) |ptr| return ptr.*;
189189
190 {190 {
...@@ -200,7 +200,7 @@ pub const Type = struct {...@@ -200,7 +200,7 @@ pub const Type = struct {
200 }200 }
201201
202 /// If you have an llvm conext handy, you can use it here.202 /// If you have an llvm conext handy, you can use it here.
203 pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {203 pub fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
204 if (base.abi_alignment.start()) |ptr| return ptr.*;204 if (base.abi_alignment.start()) |ptr| return ptr.*;
205205
206 base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context);206 base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context);
...@@ -209,7 +209,7 @@ pub const Type = struct {...@@ -209,7 +209,7 @@ pub const Type = struct {
209 }209 }
210210
211 /// Lower level function that does the work. See getAbiAlignment.211 /// Lower level function that does the work. See getAbiAlignment.
212 async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {212 fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {
213 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);213 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
214 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));214 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
215 }215 }
...@@ -367,7 +367,7 @@ pub const Type = struct {...@@ -367,7 +367,7 @@ pub const Type = struct {
367 }367 }
368368
369 /// takes ownership of key.Normal.params on success369 /// takes ownership of key.Normal.params on success
370 pub async fn get(comp: *Compilation, key: Key) !*Fn {370 pub fn get(comp: *Compilation, key: Key) !*Fn {
371 {371 {
372 const held = comp.fn_type_table.acquire();372 const held = comp.fn_type_table.acquire();
373 defer held.release();373 defer held.release();
...@@ -564,7 +564,7 @@ pub const Type = struct {...@@ -564,7 +564,7 @@ pub const Type = struct {
564 return comp.u8_type;564 return comp.u8_type;
565 }565 }
566566
567 pub async fn get(comp: *Compilation, key: Key) !*Int {567 pub fn get(comp: *Compilation, key: Key) !*Int {
568 {568 {
569 const held = comp.int_type_table.acquire();569 const held = comp.int_type_table.acquire();
570 defer held.release();570 defer held.release();
...@@ -606,7 +606,7 @@ pub const Type = struct {...@@ -606,7 +606,7 @@ pub const Type = struct {
606 comp.registerGarbage(Int, &self.garbage_node);606 comp.registerGarbage(Int, &self.garbage_node);
607 }607 }
608608
609 pub async fn gcDestroy(self: *Int, comp: *Compilation) void {609 pub fn gcDestroy(self: *Int, comp: *Compilation) void {
610 {610 {
611 const held = comp.int_type_table.acquire();611 const held = comp.int_type_table.acquire();
612 defer held.release();612 defer held.release();
...@@ -700,7 +700,7 @@ pub const Type = struct {...@@ -700,7 +700,7 @@ pub const Type = struct {
700 comp.registerGarbage(Pointer, &self.garbage_node);700 comp.registerGarbage(Pointer, &self.garbage_node);
701 }701 }
702702
703 pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void {703 pub fn gcDestroy(self: *Pointer, comp: *Compilation) void {
704 {704 {
705 const held = comp.ptr_type_table.acquire();705 const held = comp.ptr_type_table.acquire();
706 defer held.release();706 defer held.release();
...@@ -711,14 +711,14 @@ pub const Type = struct {...@@ -711,14 +711,14 @@ pub const Type = struct {
711 comp.gpa().destroy(self);711 comp.gpa().destroy(self);
712 }712 }
713713
714 pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {714 pub fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
715 switch (self.key.alignment) {715 switch (self.key.alignment) {
716 .Abi => return self.key.child_type.getAbiAlignment(comp),716 .Abi => return self.key.child_type.getAbiAlignment(comp),
717 .Override => |alignment| return alignment,717 .Override => |alignment| return alignment,
718 }718 }
719 }719 }
720720
721 pub async fn get(721 pub fn get(
722 comp: *Compilation,722 comp: *Compilation,
723 key: Key,723 key: Key,
724 ) !*Pointer {724 ) !*Pointer {
...@@ -726,8 +726,10 @@ pub const Type = struct {...@@ -726,8 +726,10 @@ pub const Type = struct {
726 switch (key.alignment) {726 switch (key.alignment) {
727 .Abi => {},727 .Abi => {},
728 .Override => |alignment| {728 .Override => |alignment| {
729 // TODO https://github.com/ziglang/zig/issues/3190
730 var align_spill = alignment;
729 const abi_align = try key.child_type.getAbiAlignment(comp);731 const abi_align = try key.child_type.getAbiAlignment(comp);
730 if (abi_align == alignment) {732 if (abi_align == align_spill) {
731 normal_key.alignment = .Abi;733 normal_key.alignment = .Abi;
732 }734 }
733 },735 },
...@@ -828,7 +830,7 @@ pub const Type = struct {...@@ -828,7 +830,7 @@ pub const Type = struct {
828 comp.gpa().destroy(self);830 comp.gpa().destroy(self);
829 }831 }
830832
831 pub async fn get(comp: *Compilation, key: Key) !*Array {833 pub fn get(comp: *Compilation, key: Key) !*Array {
832 key.elem_type.base.ref();834 key.elem_type.base.ref();
833 errdefer key.elem_type.base.deref(comp);835 errdefer key.elem_type.base.deref(comp);
834836
src-self-hosted/util.zig+12-11
...@@ -32,21 +32,21 @@ pub fn getFloatAbi(self: Target) FloatAbi {...@@ -32,21 +32,21 @@ pub fn getFloatAbi(self: Target) FloatAbi {
32 };32 };
33}33}
3434
35pub fn getObjectFormat(self: Target) Target.ObjectFormat {35pub fn getObjectFormat(target: Target) Target.ObjectFormat {
36 return switch (self) {36 switch (target) {
37 .Native => @import("builtin").object_format,37 .Native => return @import("builtin").object_format,
38 .Cross => {38 .Cross => blk: {
39 if (target.isWindows() or target.isUefi()) {39 if (target.isWindows() or target.isUefi()) {
40 break .coff;40 return .coff;
41 } else if (target.isDarwin()) {41 } else if (target.isDarwin()) {
42 break .macho;42 return .macho;
43 }43 }
44 if (target.isWasm()) {44 if (target.isWasm()) {
45 break .wasm;45 return .wasm;
46 }46 }
47 break .elf;47 return .elf;
48 },48 },
49 };49 }
50}50}
5151
52pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {52pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
...@@ -156,7 +156,7 @@ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {...@@ -156,7 +156,7 @@ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
156 }156 }
157}157}
158158
159pub fn getDarwinArchString(self: Target) []const u8 {159pub fn getDarwinArchString(self: Target) [:0]const u8 {
160 const arch = self.getArch();160 const arch = self.getArch();
161 switch (arch) {161 switch (arch) {
162 .aarch64 => return "arm64",162 .aarch64 => return "arm64",
...@@ -166,7 +166,8 @@ pub fn getDarwinArchString(self: Target) []const u8 {...@@ -166,7 +166,8 @@ pub fn getDarwinArchString(self: Target) []const u8 {
166 .powerpc => return "ppc",166 .powerpc => return "ppc",
167 .powerpc64 => return "ppc64",167 .powerpc64 => return "ppc64",
168 .powerpc64le => return "ppc64le",168 .powerpc64le => return "ppc64le",
169 else => return @tagName(arch),169 // @tagName should be able to return sentinel terminated slice
170 else => @panic("TODO https://github.com/ziglang/zig/issues/3779"), //return @tagName(arch),
170 }171 }
171}172}
172173
src-self-hosted/value.zig+7-7
...@@ -156,7 +156,7 @@ pub const Value = struct {...@@ -156,7 +156,7 @@ pub const Value = struct {
156 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);156 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
157 const llvm_fn = llvm.AddFunction(157 const llvm_fn = llvm.AddFunction(
158 ofile.module,158 ofile.module,
159 self.symbol_name.ptr(),159 self.symbol_name.toSliceConst(),
160 llvm_fn_type,160 llvm_fn_type,
161 ) orelse return error.OutOfMemory;161 ) orelse return error.OutOfMemory;
162162
...@@ -241,7 +241,7 @@ pub const Value = struct {...@@ -241,7 +241,7 @@ pub const Value = struct {
241 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);241 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
242 const llvm_fn = llvm.AddFunction(242 const llvm_fn = llvm.AddFunction(
243 ofile.module,243 ofile.module,
244 self.symbol_name.ptr(),244 self.symbol_name.toSliceConst(),
245 llvm_fn_type,245 llvm_fn_type,
246 ) orelse return error.OutOfMemory;246 ) orelse return error.OutOfMemory;
247247
...@@ -334,7 +334,7 @@ pub const Value = struct {...@@ -334,7 +334,7 @@ pub const Value = struct {
334 field_index: usize,334 field_index: usize,
335 };335 };
336336
337 pub async fn createArrayElemPtr(337 pub fn createArrayElemPtr(
338 comp: *Compilation,338 comp: *Compilation,
339 array_val: *Array,339 array_val: *Array,
340 mut: Type.Pointer.Mut,340 mut: Type.Pointer.Mut,
...@@ -350,7 +350,7 @@ pub const Value = struct {...@@ -350,7 +350,7 @@ pub const Value = struct {
350 .mut = mut,350 .mut = mut,
351 .vol = Type.Pointer.Vol.Non,351 .vol = Type.Pointer.Vol.Non,
352 .size = size,352 .size = size,
353 .alignment = Type.Pointer.Align.Abi,353 .alignment = .Abi,
354 });354 });
355 var ptr_type_consumed = false;355 var ptr_type_consumed = false;
356 errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);356 errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
...@@ -390,13 +390,13 @@ pub const Value = struct {...@@ -390,13 +390,13 @@ pub const Value = struct {
390 const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;390 const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
391 const ptr_bit_count = ofile.comp.target_ptr_bits;391 const ptr_bit_count = ofile.comp.target_ptr_bits;
392 const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;392 const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
393 const indices = [_]*llvm.Value{393 var indices = [_]*llvm.Value{
394 llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,394 llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
395 llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,395 llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
396 };396 };
397 return llvm.ConstInBoundsGEP(397 return llvm.ConstInBoundsGEP(
398 array_llvm_value,398 array_llvm_value,
399 &indices,399 @ptrCast([*]*llvm.Value, &indices),
400 @intCast(c_uint, indices.len),400 @intCast(c_uint, indices.len),
401 ) orelse return error.OutOfMemory;401 ) orelse return error.OutOfMemory;
402 },402 },
...@@ -423,7 +423,7 @@ pub const Value = struct {...@@ -423,7 +423,7 @@ pub const Value = struct {
423 };423 };
424424
425 /// Takes ownership of buffer425 /// Takes ownership of buffer
426 pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {426 pub fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {
427 const u8_type = Type.Int.get_u8(comp);427 const u8_type = Type.Int.get_u8(comp);
428 defer u8_type.base.base.deref(comp);428 defer u8_type.base.base.deref(comp);
429429
src/all_types.hpp+3-1
...@@ -1565,7 +1565,7 @@ struct ZigFn {...@@ -1565,7 +1565,7 @@ struct ZigFn {
1565 // in the case of async functions this is the implicit return type according to the1565 // in the case of async functions this is the implicit return type according to the
1566 // zig source code, not according to zig ir1566 // zig source code, not according to zig ir
1567 ZigType *src_implicit_return_type;1567 ZigType *src_implicit_return_type;
1568 IrExecutable ir_executable;1568 IrExecutable *ir_executable;
1569 IrExecutable analyzed_executable;1569 IrExecutable analyzed_executable;
1570 size_t prealloc_bbc;1570 size_t prealloc_bbc;
1571 size_t prealloc_backward_branch_quota;1571 size_t prealloc_backward_branch_quota;
...@@ -2204,6 +2204,8 @@ struct ZigVar {...@@ -2204,6 +2204,8 @@ struct ZigVar {
2204 bool src_is_const;2204 bool src_is_const;
2205 bool gen_is_const;2205 bool gen_is_const;
2206 bool is_thread_local;2206 bool is_thread_local;
2207 bool is_comptime_memoized;
2208 bool is_comptime_memoized_value;
2207};2209};
22082210
2209struct ErrorTableEntry {2211struct ErrorTableEntry {
src/analyze.cpp+32-9
...@@ -3275,14 +3275,15 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i...@@ -3275,14 +3275,15 @@ static void get_fully_qualified_decl_name(CodeGen *g, Buf *buf, Tld *tld, bool i
3275}3275}
32763276
3277ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {3277ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value) {
3278 ZigFn *fn_entry = allocate<ZigFn>(1);3278 ZigFn *fn_entry = allocate<ZigFn>(1, "ZigFn");
3279 fn_entry->ir_executable = allocate<IrExecutable>(1, "IrExecutablePass1");
32793280
3280 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;3281 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
32813282
3282 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;3283 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
3283 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;3284 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
3284 fn_entry->analyzed_executable.fn_entry = fn_entry;3285 fn_entry->analyzed_executable.fn_entry = fn_entry;
3285 fn_entry->ir_executable.fn_entry = fn_entry;3286 fn_entry->ir_executable->fn_entry = fn_entry;
3286 fn_entry->fn_inline = inline_value;3287 fn_entry->fn_inline = inline_value;
32873288
3288 return fn_entry;3289 return fn_entry;
...@@ -3792,6 +3793,16 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf...@@ -3792,6 +3793,16 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
3792 return variable_entry;3793 return variable_entry;
3793}3794}
37943795
3796static void validate_export_var_type(CodeGen *g, ZigType* type, AstNode *source_node) {
3797 switch (type->id) {
3798 case ZigTypeIdMetaType:
3799 add_node_error(g, source_node, buf_sprintf("cannot export variable of type 'type'"));
3800 break;
3801 default:
3802 break;
3803 }
3804}
3805
3795static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {3806static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
3796 AstNode *source_node = tld_var->base.source_node;3807 AstNode *source_node = tld_var->base.source_node;
3797 AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration;3808 AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration;
...@@ -3881,6 +3892,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {...@@ -3881,6 +3892,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
3881 }3892 }
38823893
3883 if (is_export) {3894 if (is_export) {
3895 validate_export_var_type(g, type, source_node);
3884 add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong);3896 add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong);
3885 }3897 }
38863898
...@@ -4599,7 +4611,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {...@@ -4599,7 +4611,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
4599 assert(!fn_type->data.fn.is_generic);4611 assert(!fn_type->data.fn.is_generic);
4600 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;4612 FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id;
46014613
4602 ZigType *block_return_type = ir_analyze(g, &fn->ir_executable,4614 ZigType *block_return_type = ir_analyze(g, fn->ir_executable,
4603 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);4615 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
4604 fn->src_implicit_return_type = block_return_type;4616 fn->src_implicit_return_type = block_return_type;
46054617
...@@ -4695,7 +4707,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {...@@ -4695,7 +4707,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
4695 assert(!fn_type->data.fn.is_generic);4707 assert(!fn_type->data.fn.is_generic);
46964708
4697 ir_gen_fn(g, fn_table_entry);4709 ir_gen_fn(g, fn_table_entry);
4698 if (fn_table_entry->ir_executable.first_err_trace_msg != nullptr) {4710 if (fn_table_entry->ir_executable->first_err_trace_msg != nullptr) {
4699 fn_table_entry->anal_state = FnAnalStateInvalid;4711 fn_table_entry->anal_state = FnAnalStateInvalid;
4700 return;4712 return;
4701 }4713 }
...@@ -4703,7 +4715,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {...@@ -4703,7 +4715,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
4703 fprintf(stderr, "\n");4715 fprintf(stderr, "\n");
4704 ast_render(stderr, fn_table_entry->body_node, 4);4716 ast_render(stderr, fn_table_entry->body_node, 4);
4705 fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name));4717 fprintf(stderr, "\nfn %s() { // (IR)\n", buf_ptr(&fn_table_entry->symbol_name));
4706 ir_print(g, stderr, &fn_table_entry->ir_executable, 4, IrPassSrc);4718 ir_print(g, stderr, fn_table_entry->ir_executable, 4, IrPassSrc);
4707 fprintf(stderr, "}\n");4719 fprintf(stderr, "}\n");
4708 }4720 }
47094721
...@@ -6442,20 +6454,31 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {...@@ -6442,20 +6454,31 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
6442}6454}
64436455
6444bool ir_get_var_is_comptime(ZigVar *var) {6456bool ir_get_var_is_comptime(ZigVar *var) {
6457 if (var->is_comptime_memoized)
6458 return var->is_comptime_memoized_value;
6459
6460 var->is_comptime_memoized = true;
6461
6445 // The is_comptime field can be left null, which means not comptime.6462 // The is_comptime field can be left null, which means not comptime.
6446 if (var->is_comptime == nullptr)6463 if (var->is_comptime == nullptr) {
6447 return false;6464 var->is_comptime_memoized_value = false;
6465 return var->is_comptime_memoized_value;
6466 }
6448 // When the is_comptime field references an instruction that has to get analyzed, this6467 // When the is_comptime field references an instruction that has to get analyzed, this
6449 // is the value.6468 // is the value.
6450 if (var->is_comptime->child != nullptr) {6469 if (var->is_comptime->child != nullptr) {
6451 assert(var->is_comptime->child->value->type->id == ZigTypeIdBool);6470 assert(var->is_comptime->child->value->type->id == ZigTypeIdBool);
6452 return var->is_comptime->child->value->data.x_bool;6471 var->is_comptime_memoized_value = var->is_comptime->child->value->data.x_bool;
6472 var->is_comptime = nullptr;
6473 return var->is_comptime_memoized_value;
6453 }6474 }
6454 // As an optimization, is_comptime values which are constant are allowed6475 // As an optimization, is_comptime values which are constant are allowed
6455 // to be omitted from analysis. In this case, there is no child instruction6476 // to be omitted from analysis. In this case, there is no child instruction
6456 // and we simply look at the unanalyzed const parent instruction.6477 // and we simply look at the unanalyzed const parent instruction.
6457 assert(var->is_comptime->value->type->id == ZigTypeIdBool);6478 assert(var->is_comptime->value->type->id == ZigTypeIdBool);
6458 return var->is_comptime->value->data.x_bool;6479 var->is_comptime_memoized_value = var->is_comptime->value->data.x_bool;
6480 var->is_comptime = nullptr;
6481 return var->is_comptime_memoized_value;
6459}6482}
64606483
6461bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {6484bool const_values_equal_ptr(ZigValue *a, ZigValue *b) {
src/codegen.cpp+174-127
...@@ -9563,7 +9563,11 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e...@@ -9563,7 +9563,11 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, ZigType *type_e
9563 case ZigTypeIdVoid:9563 case ZigTypeIdVoid:
9564 case ZigTypeIdUnreachable:9564 case ZigTypeIdUnreachable:
9565 case ZigTypeIdBool:9565 case ZigTypeIdBool:
9566 g->c_want_stdbool = true;
9567 return;
9566 case ZigTypeIdInt:9568 case ZigTypeIdInt:
9569 g->c_want_stdint = true;
9570 return;
9567 case ZigTypeIdFloat:9571 case ZigTypeIdFloat:
9568 return;9572 return;
9569 case ZigTypeIdOpaque:9573 case ZigTypeIdOpaque:
...@@ -9644,7 +9648,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -9644,7 +9648,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
9644 break;9648 break;
9645 case ZigTypeIdBool:9649 case ZigTypeIdBool:
9646 buf_init_from_str(out_buf, "bool");9650 buf_init_from_str(out_buf, "bool");
9647 g->c_want_stdbool = true;
9648 break;9651 break;
9649 case ZigTypeIdUnreachable:9652 case ZigTypeIdUnreachable:
9650 buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void");9653 buf_init_from_str(out_buf, "__attribute__((__noreturn__)) void");
...@@ -9668,7 +9671,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu...@@ -9668,7 +9671,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
9668 }9671 }
9669 break;9672 break;
9670 case ZigTypeIdInt:9673 case ZigTypeIdInt:
9671 g->c_want_stdint = true;
9672 buf_resize(out_buf, 0);9674 buf_resize(out_buf, 0);
9673 buf_appendf(out_buf, "%sint%" PRIu32 "_t",9675 buf_appendf(out_buf, "%sint%" PRIu32 "_t",
9674 type_entry->data.integral.is_signed ? "" : "u",9676 type_entry->data.integral.is_signed ? "" : "u",
...@@ -9780,113 +9782,7 @@ static Buf *preprocessor_mangle(Buf *src) {...@@ -9780,113 +9782,7 @@ static Buf *preprocessor_mangle(Buf *src) {
9780 return result;9782 return result;
9781}9783}
97829784
9783static void gen_h_file(CodeGen *g) {9785static void gen_h_file_types(CodeGen* g, GenH* gen_h, Buf* out_buf) {
9784 GenH gen_h_data = {0};
9785 GenH *gen_h = &gen_h_data;
9786
9787 assert(!g->is_test_build);
9788 assert(!g->disable_gen_h);
9789
9790 Buf *out_h_path = buf_sprintf("%s" OS_SEP "%s.h", buf_ptr(g->output_dir), buf_ptr(g->root_out_name));
9791
9792 FILE *out_h = fopen(buf_ptr(out_h_path), "wb");
9793 if (!out_h)
9794 zig_panic("unable to open %s: %s\n", buf_ptr(out_h_path), strerror(errno));
9795
9796 Buf *export_macro = nullptr;
9797 if (g->is_dynamic) {
9798 export_macro = preprocessor_mangle(buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)));
9799 buf_upcase(export_macro);
9800 }
9801
9802 Buf *extern_c_macro = preprocessor_mangle(buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name)));
9803 buf_upcase(extern_c_macro);
9804
9805 Buf h_buf = BUF_INIT;
9806 buf_resize(&h_buf, 0);
9807 for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
9808 ZigFn *fn_table_entry = g->fn_defs.at(fn_def_i);
9809
9810 if (fn_table_entry->export_list.length == 0)
9811 continue;
9812
9813 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
9814
9815 Buf return_type_c = BUF_INIT;
9816 get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c);
9817
9818 Buf *symbol_name;
9819 if (fn_table_entry->export_list.length == 0) {
9820 symbol_name = &fn_table_entry->symbol_name;
9821 } else {
9822 GlobalExport *fn_export = &fn_table_entry->export_list.items[0];
9823 symbol_name = &fn_export->name;
9824 }
9825
9826 buf_appendf(&h_buf, "%s %s %s(",
9827 buf_ptr(g->is_dynamic ? export_macro : extern_c_macro),
9828 buf_ptr(&return_type_c),
9829 buf_ptr(symbol_name));
9830
9831 Buf param_type_c = BUF_INIT;
9832 if (fn_type_id->param_count > 0) {
9833 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
9834 FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i];
9835 AstNode *param_decl_node = get_param_decl_node(fn_table_entry, param_i);
9836 Buf *param_name = param_decl_node->data.param_decl.name;
9837
9838 const char *comma_str = (param_i == 0) ? "" : ", ";
9839 const char *restrict_str = param_info->is_noalias ? "restrict" : "";
9840 get_c_type(g, gen_h, param_info->type, &param_type_c);
9841
9842 if (param_info->type->id == ZigTypeIdArray) {
9843 // Arrays decay to pointers
9844 buf_appendf(&h_buf, "%s%s%s %s[]", comma_str, buf_ptr(&param_type_c),
9845 restrict_str, buf_ptr(param_name));
9846 } else {
9847 buf_appendf(&h_buf, "%s%s%s %s", comma_str, buf_ptr(&param_type_c),
9848 restrict_str, buf_ptr(param_name));
9849 }
9850 }
9851 buf_appendf(&h_buf, ")");
9852 } else {
9853 buf_appendf(&h_buf, "void)");
9854 }
9855
9856 buf_appendf(&h_buf, ";\n");
9857
9858 }
9859
9860 Buf *ifdef_dance_name = preprocessor_mangle(buf_sprintf("%s_H", buf_ptr(g->root_out_name)));
9861 buf_upcase(ifdef_dance_name);
9862
9863 fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));
9864 fprintf(out_h, "#define %s\n\n", buf_ptr(ifdef_dance_name));
9865
9866 if (g->c_want_stdbool)
9867 fprintf(out_h, "#include <stdbool.h>\n");
9868 if (g->c_want_stdint)
9869 fprintf(out_h, "#include <stdint.h>\n");
9870
9871 fprintf(out_h, "\n");
9872
9873 fprintf(out_h, "#ifdef __cplusplus\n");
9874 fprintf(out_h, "#define %s extern \"C\"\n", buf_ptr(extern_c_macro));
9875 fprintf(out_h, "#else\n");
9876 fprintf(out_h, "#define %s\n", buf_ptr(extern_c_macro));
9877 fprintf(out_h, "#endif\n");
9878 fprintf(out_h, "\n");
9879
9880 if (g->is_dynamic) {
9881 fprintf(out_h, "#if defined(_WIN32)\n");
9882 fprintf(out_h, "#define %s %s __declspec(dllimport)\n", buf_ptr(export_macro), buf_ptr(extern_c_macro));
9883 fprintf(out_h, "#else\n");
9884 fprintf(out_h, "#define %s %s __attribute__((visibility (\"default\")))\n",
9885 buf_ptr(export_macro), buf_ptr(extern_c_macro));
9886 fprintf(out_h, "#endif\n");
9887 fprintf(out_h, "\n");
9888 }
9889
9890 for (size_t type_i = 0; type_i < gen_h->types_to_declare.length; type_i += 1) {9786 for (size_t type_i = 0; type_i < gen_h->types_to_declare.length; type_i += 1) {
9891 ZigType *type_entry = gen_h->types_to_declare.at(type_i);9787 ZigType *type_entry = gen_h->types_to_declare.at(type_i);
9892 switch (type_entry->id) {9788 switch (type_entry->id) {
...@@ -9917,25 +9813,25 @@ static void gen_h_file(CodeGen *g) {...@@ -9917,25 +9813,25 @@ static void gen_h_file(CodeGen *g) {
99179813
9918 case ZigTypeIdEnum:9814 case ZigTypeIdEnum:
9919 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {9815 if (type_entry->data.enumeration.layout == ContainerLayoutExtern) {
9920 fprintf(out_h, "enum %s {\n", buf_ptr(type_h_name(type_entry)));9816 buf_appendf(out_buf, "enum %s {\n", buf_ptr(type_h_name(type_entry)));
9921 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {9817 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
9922 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];9818 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
9923 Buf *value_buf = buf_alloc();9819 Buf *value_buf = buf_alloc();
9924 bigint_append_buf(value_buf, &enum_field->value, 10);9820 bigint_append_buf(value_buf, &enum_field->value, 10);
9925 fprintf(out_h, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf));9821 buf_appendf(out_buf, " %s = %s", buf_ptr(enum_field->name), buf_ptr(value_buf));
9926 if (field_i != type_entry->data.enumeration.src_field_count - 1) {9822 if (field_i != type_entry->data.enumeration.src_field_count - 1) {
9927 fprintf(out_h, ",");9823 buf_appendf(out_buf, ",");
9928 }9824 }
9929 fprintf(out_h, "\n");9825 buf_appendf(out_buf, "\n");
9930 }9826 }
9931 fprintf(out_h, "};\n\n");9827 buf_appendf(out_buf, "};\n\n");
9932 } else {9828 } else {
9933 fprintf(out_h, "enum %s;\n", buf_ptr(type_h_name(type_entry)));9829 buf_appendf(out_buf, "enum %s;\n\n", buf_ptr(type_h_name(type_entry)));
9934 }9830 }
9935 break;9831 break;
9936 case ZigTypeIdStruct:9832 case ZigTypeIdStruct:
9937 if (type_entry->data.structure.layout == ContainerLayoutExtern) {9833 if (type_entry->data.structure.layout == ContainerLayoutExtern) {
9938 fprintf(out_h, "struct %s {\n", buf_ptr(type_h_name(type_entry)));9834 buf_appendf(out_buf, "struct %s {\n", buf_ptr(type_h_name(type_entry)));
9939 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {9835 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
9940 TypeStructField *struct_field = type_entry->data.structure.fields[field_i];9836 TypeStructField *struct_field = type_entry->data.structure.fields[field_i];
99419837
...@@ -9943,43 +9839,194 @@ static void gen_h_file(CodeGen *g) {...@@ -9943,43 +9839,194 @@ static void gen_h_file(CodeGen *g) {
9943 get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);9839 get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);
99449840
9945 if (struct_field->type_entry->id == ZigTypeIdArray) {9841 if (struct_field->type_entry->id == ZigTypeIdArray) {
9946 fprintf(out_h, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf),9842 buf_appendf(out_buf, " %s %s[%" ZIG_PRI_u64 "];\n", buf_ptr(type_name_buf),
9947 buf_ptr(struct_field->name),9843 buf_ptr(struct_field->name),
9948 struct_field->type_entry->data.array.len);9844 struct_field->type_entry->data.array.len);
9949 } else {9845 } else {
9950 fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name));9846 buf_appendf(out_buf, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(struct_field->name));
9951 }9847 }
99529848
9953 }9849 }
9954 fprintf(out_h, "};\n\n");9850 buf_appendf(out_buf, "};\n\n");
9955 } else {9851 } else {
9956 fprintf(out_h, "struct %s;\n", buf_ptr(type_h_name(type_entry)));9852 buf_appendf(out_buf, "struct %s;\n\n", buf_ptr(type_h_name(type_entry)));
9957 }9853 }
9958 break;9854 break;
9959 case ZigTypeIdUnion:9855 case ZigTypeIdUnion:
9960 if (type_entry->data.unionation.layout == ContainerLayoutExtern) {9856 if (type_entry->data.unionation.layout == ContainerLayoutExtern) {
9961 fprintf(out_h, "union %s {\n", buf_ptr(type_h_name(type_entry)));9857 buf_appendf(out_buf, "union %s {\n", buf_ptr(type_h_name(type_entry)));
9962 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {9858 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
9963 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];9859 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
99649860
9965 Buf *type_name_buf = buf_alloc();9861 Buf *type_name_buf = buf_alloc();
9966 get_c_type(g, gen_h, union_field->type_entry, type_name_buf);9862 get_c_type(g, gen_h, union_field->type_entry, type_name_buf);
9967 fprintf(out_h, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name));9863 buf_appendf(out_buf, " %s %s;\n", buf_ptr(type_name_buf), buf_ptr(union_field->name));
9968 }9864 }
9969 fprintf(out_h, "};\n\n");9865 buf_appendf(out_buf, "};\n\n");
9970 } else {9866 } else {
9971 fprintf(out_h, "union %s;\n", buf_ptr(type_h_name(type_entry)));9867 buf_appendf(out_buf, "union %s;\n\n", buf_ptr(type_h_name(type_entry)));
9972 }9868 }
9973 break;9869 break;
9974 case ZigTypeIdOpaque:9870 case ZigTypeIdOpaque:
9975 fprintf(out_h, "struct %s;\n\n", buf_ptr(type_h_name(type_entry)));9871 buf_appendf(out_buf, "struct %s;\n\n", buf_ptr(type_h_name(type_entry)));
9976 break;9872 break;
9977 }9873 }
9978 }9874 }
9875}
9876
9877static void gen_h_file_functions(CodeGen* g, GenH* gen_h, Buf* out_buf, Buf* export_macro) {
9878 for (size_t fn_def_i = 0; fn_def_i < g->fn_defs.length; fn_def_i += 1) {
9879 ZigFn *fn_table_entry = g->fn_defs.at(fn_def_i);
9880
9881 if (fn_table_entry->export_list.length == 0)
9882 continue;
9883
9884 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
9885
9886 Buf return_type_c = BUF_INIT;
9887 get_c_type(g, gen_h, fn_type_id->return_type, &return_type_c);
9888
9889 Buf *symbol_name;
9890 if (fn_table_entry->export_list.length == 0) {
9891 symbol_name = &fn_table_entry->symbol_name;
9892 } else {
9893 GlobalExport *fn_export = &fn_table_entry->export_list.items[0];
9894 symbol_name = &fn_export->name;
9895 }
9896
9897 if (export_macro != nullptr) {
9898 buf_appendf(out_buf, "%s %s %s(",
9899 buf_ptr(export_macro),
9900 buf_ptr(&return_type_c),
9901 buf_ptr(symbol_name));
9902 } else {
9903 buf_appendf(out_buf, "%s %s(",
9904 buf_ptr(&return_type_c),
9905 buf_ptr(symbol_name));
9906 }
9907
9908 Buf param_type_c = BUF_INIT;
9909 if (fn_type_id->param_count > 0) {
9910 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
9911 FnTypeParamInfo *param_info = &fn_type_id->param_info[param_i];
9912 AstNode *param_decl_node = get_param_decl_node(fn_table_entry, param_i);
9913 Buf *param_name = param_decl_node->data.param_decl.name;
9914
9915 const char *comma_str = (param_i == 0) ? "" : ", ";
9916 const char *restrict_str = param_info->is_noalias ? "restrict" : "";
9917 get_c_type(g, gen_h, param_info->type, &param_type_c);
9918
9919 if (param_info->type->id == ZigTypeIdArray) {
9920 // Arrays decay to pointers
9921 buf_appendf(out_buf, "%s%s%s %s[]", comma_str, buf_ptr(&param_type_c),
9922 restrict_str, buf_ptr(param_name));
9923 } else {
9924 buf_appendf(out_buf, "%s%s%s %s", comma_str, buf_ptr(&param_type_c),
9925 restrict_str, buf_ptr(param_name));
9926 }
9927 }
9928 buf_appendf(out_buf, ")");
9929 } else {
9930 buf_appendf(out_buf, "void)");
9931 }
9932
9933 buf_appendf(out_buf, ";\n");
9934 }
9935}
9936
9937static void gen_h_file_variables(CodeGen* g, GenH* gen_h, Buf* h_buf, Buf* export_macro) {
9938 for (size_t exp_var_i = 0; exp_var_i < g->global_vars.length; exp_var_i += 1) {
9939 ZigVar* var = g->global_vars.at(exp_var_i)->var;
9940 if (var->export_list.length == 0)
9941 continue;
9942
9943 Buf var_type_c = BUF_INIT;
9944 get_c_type(g, gen_h, var->var_type, &var_type_c);
9945
9946 if (export_macro != nullptr) {
9947 buf_appendf(h_buf, "extern %s %s %s;\n",
9948 buf_ptr(export_macro),
9949 buf_ptr(&var_type_c),
9950 var->name);
9951 } else {
9952 buf_appendf(h_buf, "extern %s %s;\n",
9953 buf_ptr(&var_type_c),
9954 var->name);
9955 }
9956 }
9957}
9958
9959static void gen_h_file(CodeGen *g) {
9960 GenH gen_h_data = {0};
9961 GenH *gen_h = &gen_h_data;
9962
9963 assert(!g->is_test_build);
9964 assert(!g->disable_gen_h);
9965
9966 Buf *out_h_path = buf_sprintf("%s" OS_SEP "%s.h", buf_ptr(g->output_dir), buf_ptr(g->root_out_name));
9967
9968 FILE *out_h = fopen(buf_ptr(out_h_path), "wb");
9969 if (!out_h)
9970 zig_panic("unable to open %s: %s\n", buf_ptr(out_h_path), strerror(errno));
9971
9972 Buf *export_macro = nullptr;
9973 if (g->is_dynamic) {
9974 export_macro = preprocessor_mangle(buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)));
9975 buf_upcase(export_macro);
9976 }
9977
9978 Buf fns_buf = BUF_INIT;
9979 buf_resize(&fns_buf, 0);
9980 gen_h_file_functions(g, gen_h, &fns_buf, export_macro);
9981
9982 Buf vars_buf = BUF_INIT;
9983 buf_resize(&vars_buf, 0);
9984 gen_h_file_variables(g, gen_h, &vars_buf, export_macro);
9985
9986 // Types will be populated by exported functions and variables so it has to run last.
9987 Buf types_buf = BUF_INIT;
9988 buf_resize(&types_buf, 0);
9989 gen_h_file_types(g, gen_h, &types_buf);
9990
9991 Buf *ifdef_dance_name = preprocessor_mangle(buf_sprintf("%s_H", buf_ptr(g->root_out_name)));
9992 buf_upcase(ifdef_dance_name);
9993
9994 fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));
9995 fprintf(out_h, "#define %s\n\n", buf_ptr(ifdef_dance_name));
9996
9997 if (g->c_want_stdbool)
9998 fprintf(out_h, "#include <stdbool.h>\n");
9999 if (g->c_want_stdint)
10000 fprintf(out_h, "#include <stdint.h>\n");
10001
10002 fprintf(out_h, "\n");
10003
10004 if (g->is_dynamic) {
10005 fprintf(out_h, "#if defined(_WIN32)\n");
10006 fprintf(out_h, "#define %s __declspec(dllimport)\n", buf_ptr(export_macro));
10007 fprintf(out_h, "#else\n");
10008 fprintf(out_h, "#define %s __attribute__((visibility (\"default\")))\n",
10009 buf_ptr(export_macro));
10010 fprintf(out_h, "#endif\n");
10011 fprintf(out_h, "\n");
10012 }
10013
10014 fprintf(out_h, "%s", buf_ptr(&types_buf));
10015
10016 fprintf(out_h, "#ifdef __cplusplus\n");
10017 fprintf(out_h, "extern \"C\" {\n");
10018 fprintf(out_h, "#endif\n");
10019 fprintf(out_h, "\n");
10020
10021 fprintf(out_h, "%s\n", buf_ptr(&fns_buf));
10022
10023 fprintf(out_h, "#ifdef __cplusplus\n");
10024 fprintf(out_h, "} // extern \"C\"\n");
10025 fprintf(out_h, "#endif\n\n");
997910026
9980 fprintf(out_h, "%s", buf_ptr(&h_buf));10027 fprintf(out_h, "%s\n", buf_ptr(&vars_buf));
998110028
9982 fprintf(out_h, "\n#endif\n");10029 fprintf(out_h, "#endif // %s\n", buf_ptr(ifdef_dance_name));
998310030
9984 if (fclose(out_h))10031 if (fclose(out_h))
9985 zig_panic("unable to close h file: %s", strerror(errno));10032 zig_panic("unable to close h file: %s", strerror(errno));
src/ir.cpp+456-30
...@@ -41,6 +41,7 @@ struct IrAnalyze {...@@ -41,6 +41,7 @@ struct IrAnalyze {
41 ZigList<IrInstruction *> src_implicit_return_type_list;41 ZigList<IrInstruction *> src_implicit_return_type_list;
42 ZigList<IrSuspendPosition> resume_stack;42 ZigList<IrSuspendPosition> resume_stack;
43 IrBasicBlock *const_predecessor_bb;43 IrBasicBlock *const_predecessor_bb;
44 size_t ref_count;
4445
45 // For the purpose of using in a debugger46 // For the purpose of using in a debugger
46 void dump();47 void dump();
...@@ -74,6 +75,7 @@ enum ConstCastResultId {...@@ -74,6 +75,7 @@ enum ConstCastResultId {
74 ConstCastResultIdPtrLens,75 ConstCastResultIdPtrLens,
75 ConstCastResultIdCV,76 ConstCastResultIdCV,
76 ConstCastResultIdPtrSentinel,77 ConstCastResultIdPtrSentinel,
78 ConstCastResultIdIntShorten,
77};79};
7880
79struct ConstCastOnly;81struct ConstCastOnly;
...@@ -100,6 +102,7 @@ struct ConstCastBadAllowsZero;...@@ -100,6 +102,7 @@ struct ConstCastBadAllowsZero;
100struct ConstCastBadNullTermArrays;102struct ConstCastBadNullTermArrays;
101struct ConstCastBadCV;103struct ConstCastBadCV;
102struct ConstCastPtrSentinel;104struct ConstCastPtrSentinel;
105struct ConstCastIntShorten;
103106
104struct ConstCastOnly {107struct ConstCastOnly {
105 ConstCastResultId id;108 ConstCastResultId id;
...@@ -120,6 +123,7 @@ struct ConstCastOnly {...@@ -120,6 +123,7 @@ struct ConstCastOnly {
120 ConstCastBadNullTermArrays *sentinel_arrays;123 ConstCastBadNullTermArrays *sentinel_arrays;
121 ConstCastBadCV *bad_cv;124 ConstCastBadCV *bad_cv;
122 ConstCastPtrSentinel *bad_ptr_sentinel;125 ConstCastPtrSentinel *bad_ptr_sentinel;
126 ConstCastIntShorten *int_shorten;
123 } data;127 } data;
124};128};
125129
...@@ -189,6 +193,11 @@ struct ConstCastPtrSentinel {...@@ -189,6 +193,11 @@ struct ConstCastPtrSentinel {
189 ZigType *actual_type;193 ZigType *actual_type;
190};194};
191195
196struct ConstCastIntShorten {
197 ZigType *wanted_type;
198 ZigType *actual_type;
199};
200
192static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);201static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
193static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,202static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
194 ResultLoc *result_loc);203 ResultLoc *result_loc);
...@@ -248,6 +257,381 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n...@@ -248,6 +257,381 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n
248 IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type);257 IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type);
249static ResultLoc *no_result_loc(void);258static ResultLoc *no_result_loc(void);
250259
260static void destroy_instruction(IrInstruction *inst) {
261#ifdef ZIG_ENABLE_MEM_PROFILE
262 const char *name = ir_instruction_type_str(inst->id);
263#else
264 const char *name = nullptr;
265#endif
266 switch (inst->id) {
267 case IrInstructionIdInvalid:
268 zig_unreachable();
269 case IrInstructionIdReturn:
270 return destroy(reinterpret_cast<IrInstructionReturn *>(inst), name);
271 case IrInstructionIdConst:
272 return destroy(reinterpret_cast<IrInstructionConst *>(inst), name);
273 case IrInstructionIdBinOp:
274 return destroy(reinterpret_cast<IrInstructionBinOp *>(inst), name);
275 case IrInstructionIdMergeErrSets:
276 return destroy(reinterpret_cast<IrInstructionMergeErrSets *>(inst), name);
277 case IrInstructionIdDeclVarSrc:
278 return destroy(reinterpret_cast<IrInstructionDeclVarSrc *>(inst), name);
279 case IrInstructionIdCast:
280 return destroy(reinterpret_cast<IrInstructionCast *>(inst), name);
281 case IrInstructionIdCallSrc:
282 return destroy(reinterpret_cast<IrInstructionCallSrc *>(inst), name);
283 case IrInstructionIdCallGen:
284 return destroy(reinterpret_cast<IrInstructionCallGen *>(inst), name);
285 case IrInstructionIdUnOp:
286 return destroy(reinterpret_cast<IrInstructionUnOp *>(inst), name);
287 case IrInstructionIdCondBr:
288 return destroy(reinterpret_cast<IrInstructionCondBr *>(inst), name);
289 case IrInstructionIdBr:
290 return destroy(reinterpret_cast<IrInstructionBr *>(inst), name);
291 case IrInstructionIdPhi:
292 return destroy(reinterpret_cast<IrInstructionPhi *>(inst), name);
293 case IrInstructionIdContainerInitList:
294 return destroy(reinterpret_cast<IrInstructionContainerInitList *>(inst), name);
295 case IrInstructionIdContainerInitFields:
296 return destroy(reinterpret_cast<IrInstructionContainerInitFields *>(inst), name);
297 case IrInstructionIdUnreachable:
298 return destroy(reinterpret_cast<IrInstructionUnreachable *>(inst), name);
299 case IrInstructionIdElemPtr:
300 return destroy(reinterpret_cast<IrInstructionElemPtr *>(inst), name);
301 case IrInstructionIdVarPtr:
302 return destroy(reinterpret_cast<IrInstructionVarPtr *>(inst), name);
303 case IrInstructionIdReturnPtr:
304 return destroy(reinterpret_cast<IrInstructionReturnPtr *>(inst), name);
305 case IrInstructionIdLoadPtr:
306 return destroy(reinterpret_cast<IrInstructionLoadPtr *>(inst), name);
307 case IrInstructionIdLoadPtrGen:
308 return destroy(reinterpret_cast<IrInstructionLoadPtrGen *>(inst), name);
309 case IrInstructionIdStorePtr:
310 return destroy(reinterpret_cast<IrInstructionStorePtr *>(inst), name);
311 case IrInstructionIdVectorStoreElem:
312 return destroy(reinterpret_cast<IrInstructionVectorStoreElem *>(inst), name);
313 case IrInstructionIdTypeOf:
314 return destroy(reinterpret_cast<IrInstructionTypeOf *>(inst), name);
315 case IrInstructionIdFieldPtr:
316 return destroy(reinterpret_cast<IrInstructionFieldPtr *>(inst), name);
317 case IrInstructionIdStructFieldPtr:
318 return destroy(reinterpret_cast<IrInstructionStructFieldPtr *>(inst), name);
319 case IrInstructionIdUnionFieldPtr:
320 return destroy(reinterpret_cast<IrInstructionUnionFieldPtr *>(inst), name);
321 case IrInstructionIdSetCold:
322 return destroy(reinterpret_cast<IrInstructionSetCold *>(inst), name);
323 case IrInstructionIdSetRuntimeSafety:
324 return destroy(reinterpret_cast<IrInstructionSetRuntimeSafety *>(inst), name);
325 case IrInstructionIdSetFloatMode:
326 return destroy(reinterpret_cast<IrInstructionSetFloatMode *>(inst), name);
327 case IrInstructionIdArrayType:
328 return destroy(reinterpret_cast<IrInstructionArrayType *>(inst), name);
329 case IrInstructionIdSliceType:
330 return destroy(reinterpret_cast<IrInstructionSliceType *>(inst), name);
331 case IrInstructionIdAnyFrameType:
332 return destroy(reinterpret_cast<IrInstructionAnyFrameType *>(inst), name);
333 case IrInstructionIdGlobalAsm:
334 return destroy(reinterpret_cast<IrInstructionGlobalAsm *>(inst), name);
335 case IrInstructionIdAsm:
336 return destroy(reinterpret_cast<IrInstructionAsm *>(inst), name);
337 case IrInstructionIdSizeOf:
338 return destroy(reinterpret_cast<IrInstructionSizeOf *>(inst), name);
339 case IrInstructionIdTestNonNull:
340 return destroy(reinterpret_cast<IrInstructionTestNonNull *>(inst), name);
341 case IrInstructionIdOptionalUnwrapPtr:
342 return destroy(reinterpret_cast<IrInstructionOptionalUnwrapPtr *>(inst), name);
343 case IrInstructionIdPopCount:
344 return destroy(reinterpret_cast<IrInstructionPopCount *>(inst), name);
345 case IrInstructionIdClz:
346 return destroy(reinterpret_cast<IrInstructionClz *>(inst), name);
347 case IrInstructionIdCtz:
348 return destroy(reinterpret_cast<IrInstructionCtz *>(inst), name);
349 case IrInstructionIdBswap:
350 return destroy(reinterpret_cast<IrInstructionBswap *>(inst), name);
351 case IrInstructionIdBitReverse:
352 return destroy(reinterpret_cast<IrInstructionBitReverse *>(inst), name);
353 case IrInstructionIdSwitchBr:
354 return destroy(reinterpret_cast<IrInstructionSwitchBr *>(inst), name);
355 case IrInstructionIdSwitchVar:
356 return destroy(reinterpret_cast<IrInstructionSwitchVar *>(inst), name);
357 case IrInstructionIdSwitchElseVar:
358 return destroy(reinterpret_cast<IrInstructionSwitchElseVar *>(inst), name);
359 case IrInstructionIdSwitchTarget:
360 return destroy(reinterpret_cast<IrInstructionSwitchTarget *>(inst), name);
361 case IrInstructionIdUnionTag:
362 return destroy(reinterpret_cast<IrInstructionUnionTag *>(inst), name);
363 case IrInstructionIdImport:
364 return destroy(reinterpret_cast<IrInstructionImport *>(inst), name);
365 case IrInstructionIdRef:
366 return destroy(reinterpret_cast<IrInstructionRef *>(inst), name);
367 case IrInstructionIdRefGen:
368 return destroy(reinterpret_cast<IrInstructionRefGen *>(inst), name);
369 case IrInstructionIdCompileErr:
370 return destroy(reinterpret_cast<IrInstructionCompileErr *>(inst), name);
371 case IrInstructionIdCompileLog:
372 return destroy(reinterpret_cast<IrInstructionCompileLog *>(inst), name);
373 case IrInstructionIdErrName:
374 return destroy(reinterpret_cast<IrInstructionErrName *>(inst), name);
375 case IrInstructionIdCImport:
376 return destroy(reinterpret_cast<IrInstructionCImport *>(inst), name);
377 case IrInstructionIdCInclude:
378 return destroy(reinterpret_cast<IrInstructionCInclude *>(inst), name);
379 case IrInstructionIdCDefine:
380 return destroy(reinterpret_cast<IrInstructionCDefine *>(inst), name);
381 case IrInstructionIdCUndef:
382 return destroy(reinterpret_cast<IrInstructionCUndef *>(inst), name);
383 case IrInstructionIdEmbedFile:
384 return destroy(reinterpret_cast<IrInstructionEmbedFile *>(inst), name);
385 case IrInstructionIdCmpxchgSrc:
386 return destroy(reinterpret_cast<IrInstructionCmpxchgSrc *>(inst), name);
387 case IrInstructionIdCmpxchgGen:
388 return destroy(reinterpret_cast<IrInstructionCmpxchgGen *>(inst), name);
389 case IrInstructionIdFence:
390 return destroy(reinterpret_cast<IrInstructionFence *>(inst), name);
391 case IrInstructionIdTruncate:
392 return destroy(reinterpret_cast<IrInstructionTruncate *>(inst), name);
393 case IrInstructionIdIntCast:
394 return destroy(reinterpret_cast<IrInstructionIntCast *>(inst), name);
395 case IrInstructionIdFloatCast:
396 return destroy(reinterpret_cast<IrInstructionFloatCast *>(inst), name);
397 case IrInstructionIdErrSetCast:
398 return destroy(reinterpret_cast<IrInstructionErrSetCast *>(inst), name);
399 case IrInstructionIdFromBytes:
400 return destroy(reinterpret_cast<IrInstructionFromBytes *>(inst), name);
401 case IrInstructionIdToBytes:
402 return destroy(reinterpret_cast<IrInstructionToBytes *>(inst), name);
403 case IrInstructionIdIntToFloat:
404 return destroy(reinterpret_cast<IrInstructionIntToFloat *>(inst), name);
405 case IrInstructionIdFloatToInt:
406 return destroy(reinterpret_cast<IrInstructionFloatToInt *>(inst), name);
407 case IrInstructionIdBoolToInt:
408 return destroy(reinterpret_cast<IrInstructionBoolToInt *>(inst), name);
409 case IrInstructionIdIntType:
410 return destroy(reinterpret_cast<IrInstructionIntType *>(inst), name);
411 case IrInstructionIdVectorType:
412 return destroy(reinterpret_cast<IrInstructionVectorType *>(inst), name);
413 case IrInstructionIdShuffleVector:
414 return destroy(reinterpret_cast<IrInstructionShuffleVector *>(inst), name);
415 case IrInstructionIdSplatSrc:
416 return destroy(reinterpret_cast<IrInstructionSplatSrc *>(inst), name);
417 case IrInstructionIdSplatGen:
418 return destroy(reinterpret_cast<IrInstructionSplatGen *>(inst), name);
419 case IrInstructionIdBoolNot:
420 return destroy(reinterpret_cast<IrInstructionBoolNot *>(inst), name);
421 case IrInstructionIdMemset:
422 return destroy(reinterpret_cast<IrInstructionMemset *>(inst), name);
423 case IrInstructionIdMemcpy:
424 return destroy(reinterpret_cast<IrInstructionMemcpy *>(inst), name);
425 case IrInstructionIdSliceSrc:
426 return destroy(reinterpret_cast<IrInstructionSliceSrc *>(inst), name);
427 case IrInstructionIdSliceGen:
428 return destroy(reinterpret_cast<IrInstructionSliceGen *>(inst), name);
429 case IrInstructionIdMemberCount:
430 return destroy(reinterpret_cast<IrInstructionMemberCount *>(inst), name);
431 case IrInstructionIdMemberType:
432 return destroy(reinterpret_cast<IrInstructionMemberType *>(inst), name);
433 case IrInstructionIdMemberName:
434 return destroy(reinterpret_cast<IrInstructionMemberName *>(inst), name);
435 case IrInstructionIdBreakpoint:
436 return destroy(reinterpret_cast<IrInstructionBreakpoint *>(inst), name);
437 case IrInstructionIdReturnAddress:
438 return destroy(reinterpret_cast<IrInstructionReturnAddress *>(inst), name);
439 case IrInstructionIdFrameAddress:
440 return destroy(reinterpret_cast<IrInstructionFrameAddress *>(inst), name);
441 case IrInstructionIdFrameHandle:
442 return destroy(reinterpret_cast<IrInstructionFrameHandle *>(inst), name);
443 case IrInstructionIdFrameType:
444 return destroy(reinterpret_cast<IrInstructionFrameType *>(inst), name);
445 case IrInstructionIdFrameSizeSrc:
446 return destroy(reinterpret_cast<IrInstructionFrameSizeSrc *>(inst), name);
447 case IrInstructionIdFrameSizeGen:
448 return destroy(reinterpret_cast<IrInstructionFrameSizeGen *>(inst), name);
449 case IrInstructionIdAlignOf:
450 return destroy(reinterpret_cast<IrInstructionAlignOf *>(inst), name);
451 case IrInstructionIdOverflowOp:
452 return destroy(reinterpret_cast<IrInstructionOverflowOp *>(inst), name);
453 case IrInstructionIdTestErrSrc:
454 return destroy(reinterpret_cast<IrInstructionTestErrSrc *>(inst), name);
455 case IrInstructionIdTestErrGen:
456 return destroy(reinterpret_cast<IrInstructionTestErrGen *>(inst), name);
457 case IrInstructionIdUnwrapErrCode:
458 return destroy(reinterpret_cast<IrInstructionUnwrapErrCode *>(inst), name);
459 case IrInstructionIdUnwrapErrPayload:
460 return destroy(reinterpret_cast<IrInstructionUnwrapErrPayload *>(inst), name);
461 case IrInstructionIdOptionalWrap:
462 return destroy(reinterpret_cast<IrInstructionOptionalWrap *>(inst), name);
463 case IrInstructionIdErrWrapCode:
464 return destroy(reinterpret_cast<IrInstructionErrWrapCode *>(inst), name);
465 case IrInstructionIdErrWrapPayload:
466 return destroy(reinterpret_cast<IrInstructionErrWrapPayload *>(inst), name);
467 case IrInstructionIdFnProto:
468 return destroy(reinterpret_cast<IrInstructionFnProto *>(inst), name);
469 case IrInstructionIdTestComptime:
470 return destroy(reinterpret_cast<IrInstructionTestComptime *>(inst), name);
471 case IrInstructionIdPtrCastSrc:
472 return destroy(reinterpret_cast<IrInstructionPtrCastSrc *>(inst), name);
473 case IrInstructionIdPtrCastGen:
474 return destroy(reinterpret_cast<IrInstructionPtrCastGen *>(inst), name);
475 case IrInstructionIdBitCastSrc:
476 return destroy(reinterpret_cast<IrInstructionBitCastSrc *>(inst), name);
477 case IrInstructionIdBitCastGen:
478 return destroy(reinterpret_cast<IrInstructionBitCastGen *>(inst), name);
479 case IrInstructionIdWidenOrShorten:
480 return destroy(reinterpret_cast<IrInstructionWidenOrShorten *>(inst), name);
481 case IrInstructionIdPtrToInt:
482 return destroy(reinterpret_cast<IrInstructionPtrToInt *>(inst), name);
483 case IrInstructionIdIntToPtr:
484 return destroy(reinterpret_cast<IrInstructionIntToPtr *>(inst), name);
485 case IrInstructionIdIntToEnum:
486 return destroy(reinterpret_cast<IrInstructionIntToEnum *>(inst), name);
487 case IrInstructionIdIntToErr:
488 return destroy(reinterpret_cast<IrInstructionIntToErr *>(inst), name);
489 case IrInstructionIdErrToInt:
490 return destroy(reinterpret_cast<IrInstructionErrToInt *>(inst), name);
491 case IrInstructionIdCheckSwitchProngs:
492 return destroy(reinterpret_cast<IrInstructionCheckSwitchProngs *>(inst), name);
493 case IrInstructionIdCheckStatementIsVoid:
494 return destroy(reinterpret_cast<IrInstructionCheckStatementIsVoid *>(inst), name);
495 case IrInstructionIdTypeName:
496 return destroy(reinterpret_cast<IrInstructionTypeName *>(inst), name);
497 case IrInstructionIdTagName:
498 return destroy(reinterpret_cast<IrInstructionTagName *>(inst), name);
499 case IrInstructionIdPtrType:
500 return destroy(reinterpret_cast<IrInstructionPtrType *>(inst), name);
501 case IrInstructionIdDeclRef:
502 return destroy(reinterpret_cast<IrInstructionDeclRef *>(inst), name);
503 case IrInstructionIdPanic:
504 return destroy(reinterpret_cast<IrInstructionPanic *>(inst), name);
505 case IrInstructionIdFieldParentPtr:
506 return destroy(reinterpret_cast<IrInstructionFieldParentPtr *>(inst), name);
507 case IrInstructionIdByteOffsetOf:
508 return destroy(reinterpret_cast<IrInstructionByteOffsetOf *>(inst), name);
509 case IrInstructionIdBitOffsetOf:
510 return destroy(reinterpret_cast<IrInstructionBitOffsetOf *>(inst), name);
511 case IrInstructionIdTypeInfo:
512 return destroy(reinterpret_cast<IrInstructionTypeInfo *>(inst), name);
513 case IrInstructionIdType:
514 return destroy(reinterpret_cast<IrInstructionType *>(inst), name);
515 case IrInstructionIdHasField:
516 return destroy(reinterpret_cast<IrInstructionHasField *>(inst), name);
517 case IrInstructionIdTypeId:
518 return destroy(reinterpret_cast<IrInstructionTypeId *>(inst), name);
519 case IrInstructionIdSetEvalBranchQuota:
520 return destroy(reinterpret_cast<IrInstructionSetEvalBranchQuota *>(inst), name);
521 case IrInstructionIdAlignCast:
522 return destroy(reinterpret_cast<IrInstructionAlignCast *>(inst), name);
523 case IrInstructionIdImplicitCast:
524 return destroy(reinterpret_cast<IrInstructionImplicitCast *>(inst), name);
525 case IrInstructionIdResolveResult:
526 return destroy(reinterpret_cast<IrInstructionResolveResult *>(inst), name);
527 case IrInstructionIdResetResult:
528 return destroy(reinterpret_cast<IrInstructionResetResult *>(inst), name);
529 case IrInstructionIdOpaqueType:
530 return destroy(reinterpret_cast<IrInstructionOpaqueType *>(inst), name);
531 case IrInstructionIdSetAlignStack:
532 return destroy(reinterpret_cast<IrInstructionSetAlignStack *>(inst), name);
533 case IrInstructionIdArgType:
534 return destroy(reinterpret_cast<IrInstructionArgType *>(inst), name);
535 case IrInstructionIdTagType:
536 return destroy(reinterpret_cast<IrInstructionTagType *>(inst), name);
537 case IrInstructionIdExport:
538 return destroy(reinterpret_cast<IrInstructionExport *>(inst), name);
539 case IrInstructionIdErrorReturnTrace:
540 return destroy(reinterpret_cast<IrInstructionErrorReturnTrace *>(inst), name);
541 case IrInstructionIdErrorUnion:
542 return destroy(reinterpret_cast<IrInstructionErrorUnion *>(inst), name);
543 case IrInstructionIdAtomicRmw:
544 return destroy(reinterpret_cast<IrInstructionAtomicRmw *>(inst), name);
545 case IrInstructionIdSaveErrRetAddr:
546 return destroy(reinterpret_cast<IrInstructionSaveErrRetAddr *>(inst), name);
547 case IrInstructionIdAddImplicitReturnType:
548 return destroy(reinterpret_cast<IrInstructionAddImplicitReturnType *>(inst), name);
549 case IrInstructionIdFloatOp:
550 return destroy(reinterpret_cast<IrInstructionFloatOp *>(inst), name);
551 case IrInstructionIdMulAdd:
552 return destroy(reinterpret_cast<IrInstructionMulAdd *>(inst), name);
553 case IrInstructionIdAtomicLoad:
554 return destroy(reinterpret_cast<IrInstructionAtomicLoad *>(inst), name);
555 case IrInstructionIdAtomicStore:
556 return destroy(reinterpret_cast<IrInstructionAtomicStore *>(inst), name);
557 case IrInstructionIdEnumToInt:
558 return destroy(reinterpret_cast<IrInstructionEnumToInt *>(inst), name);
559 case IrInstructionIdCheckRuntimeScope:
560 return destroy(reinterpret_cast<IrInstructionCheckRuntimeScope *>(inst), name);
561 case IrInstructionIdDeclVarGen:
562 return destroy(reinterpret_cast<IrInstructionDeclVarGen *>(inst), name);
563 case IrInstructionIdArrayToVector:
564 return destroy(reinterpret_cast<IrInstructionArrayToVector *>(inst), name);
565 case IrInstructionIdVectorToArray:
566 return destroy(reinterpret_cast<IrInstructionVectorToArray *>(inst), name);
567 case IrInstructionIdPtrOfArrayToSlice:
568 return destroy(reinterpret_cast<IrInstructionPtrOfArrayToSlice *>(inst), name);
569 case IrInstructionIdAssertZero:
570 return destroy(reinterpret_cast<IrInstructionAssertZero *>(inst), name);
571 case IrInstructionIdAssertNonNull:
572 return destroy(reinterpret_cast<IrInstructionAssertNonNull *>(inst), name);
573 case IrInstructionIdResizeSlice:
574 return destroy(reinterpret_cast<IrInstructionResizeSlice *>(inst), name);
575 case IrInstructionIdHasDecl:
576 return destroy(reinterpret_cast<IrInstructionHasDecl *>(inst), name);
577 case IrInstructionIdUndeclaredIdent:
578 return destroy(reinterpret_cast<IrInstructionUndeclaredIdent *>(inst), name);
579 case IrInstructionIdAllocaSrc:
580 return destroy(reinterpret_cast<IrInstructionAllocaSrc *>(inst), name);
581 case IrInstructionIdAllocaGen:
582 return destroy(reinterpret_cast<IrInstructionAllocaGen *>(inst), name);
583 case IrInstructionIdEndExpr:
584 return destroy(reinterpret_cast<IrInstructionEndExpr *>(inst), name);
585 case IrInstructionIdUnionInitNamedField:
586 return destroy(reinterpret_cast<IrInstructionUnionInitNamedField *>(inst), name);
587 case IrInstructionIdSuspendBegin:
588 return destroy(reinterpret_cast<IrInstructionSuspendBegin *>(inst), name);
589 case IrInstructionIdSuspendFinish:
590 return destroy(reinterpret_cast<IrInstructionSuspendFinish *>(inst), name);
591 case IrInstructionIdResume:
592 return destroy(reinterpret_cast<IrInstructionResume *>(inst), name);
593 case IrInstructionIdAwaitSrc:
594 return destroy(reinterpret_cast<IrInstructionAwaitSrc *>(inst), name);
595 case IrInstructionIdAwaitGen:
596 return destroy(reinterpret_cast<IrInstructionAwaitGen *>(inst), name);
597 case IrInstructionIdSpillBegin:
598 return destroy(reinterpret_cast<IrInstructionSpillBegin *>(inst), name);
599 case IrInstructionIdSpillEnd:
600 return destroy(reinterpret_cast<IrInstructionSpillEnd *>(inst), name);
601 case IrInstructionIdVectorExtractElem:
602 return destroy(reinterpret_cast<IrInstructionVectorExtractElem *>(inst), name);
603 }
604 zig_unreachable();
605}
606
607static void ira_ref(IrAnalyze *ira) {
608 ira->ref_count += 1;
609}
610static void ira_deref(IrAnalyze *ira) {
611 if (ira->ref_count > 1) {
612 ira->ref_count -= 1;
613 return;
614 }
615 assert(ira->ref_count != 0);
616
617 for (size_t bb_i = 0; bb_i < ira->old_irb.exec->basic_block_list.length; bb_i += 1) {
618 IrBasicBlock *pass1_bb = ira->old_irb.exec->basic_block_list.items[bb_i];
619 for (size_t inst_i = 0; inst_i < pass1_bb->instruction_list.length; inst_i += 1) {
620 IrInstruction *pass1_inst = pass1_bb->instruction_list.items[inst_i];
621 destroy_instruction(pass1_inst);
622 }
623 destroy(pass1_bb, "IrBasicBlock");
624 }
625 ira->old_irb.exec->basic_block_list.deinit();
626 ira->old_irb.exec->tld_list.deinit();
627 // cannot destroy here because of var->owner_exec
628 //destroy(ira->old_irb.exec, "IrExecutablePass1");
629 ira->src_implicit_return_type_list.deinit();
630 ira->resume_stack.deinit();
631 ira->exec_context.mem_slot_list.deinit();
632 destroy(ira, "IrAnalyze");
633}
634
251static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) {635static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) {
252 assert(get_src_ptr_type(const_val->type) != nullptr);636 assert(get_src_ptr_type(const_val->type) != nullptr);
253 assert(const_val->special == ConstValSpecialStatic);637 assert(const_val->special == ConstValSpecialStatic);
...@@ -4186,7 +4570,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod...@@ -4186,7 +4570,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
4186 IrInstruction **incoming_values = allocate<IrInstruction *>(2);4570 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
4187 incoming_values[0] = val1;4571 incoming_values[0] = val1;
4188 incoming_values[1] = val2;4572 incoming_values[1] = val2;
4189 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);4573 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
4190 incoming_blocks[0] = post_val1_block;4574 incoming_blocks[0] = post_val1_block;
4191 incoming_blocks[1] = post_val2_block;4575 incoming_blocks[1] = post_val2_block;
41924576
...@@ -4277,7 +4661,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -4277,7 +4661,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
4277 IrInstruction **incoming_values = allocate<IrInstruction *>(2);4661 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
4278 incoming_values[0] = null_result;4662 incoming_values[0] = null_result;
4279 incoming_values[1] = unwrapped_payload;4663 incoming_values[1] = unwrapped_payload;
4280 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);4664 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
4281 incoming_blocks[0] = after_null_block;4665 incoming_blocks[0] = after_null_block;
4282 incoming_blocks[1] = after_ok_block;4666 incoming_blocks[1] = after_ok_block;
4283 IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent);4667 IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent);
...@@ -6044,7 +6428,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode...@@ -6044,7 +6428,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
6044 IrInstruction **incoming_values = allocate<IrInstruction *>(2);6428 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
6045 incoming_values[0] = then_expr_result;6429 incoming_values[0] = then_expr_result;
6046 incoming_values[1] = else_expr_result;6430 incoming_values[1] = else_expr_result;
6047 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);6431 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
6048 incoming_blocks[0] = after_then_block;6432 incoming_blocks[0] = after_then_block;
6049 incoming_blocks[1] = after_else_block;6433 incoming_blocks[1] = after_else_block;
60506434
...@@ -7398,7 +7782,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN...@@ -7398,7 +7782,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
7398 IrInstruction **incoming_values = allocate<IrInstruction *>(2);7782 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
7399 incoming_values[0] = then_expr_result;7783 incoming_values[0] = then_expr_result;
7400 incoming_values[1] = else_expr_result;7784 incoming_values[1] = else_expr_result;
7401 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);7785 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
7402 incoming_blocks[0] = after_then_block;7786 incoming_blocks[0] = after_then_block;
7403 incoming_blocks[1] = after_else_block;7787 incoming_blocks[1] = after_else_block;
74047788
...@@ -7495,7 +7879,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -7495,7 +7879,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
7495 IrInstruction **incoming_values = allocate<IrInstruction *>(2);7879 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
7496 incoming_values[0] = then_expr_result;7880 incoming_values[0] = then_expr_result;
7497 incoming_values[1] = else_expr_result;7881 incoming_values[1] = else_expr_result;
7498 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);7882 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
7499 incoming_blocks[0] = after_then_block;7883 incoming_blocks[0] = after_then_block;
7500 incoming_blocks[1] = after_else_block;7884 incoming_blocks[1] = after_else_block;
75017885
...@@ -8092,7 +8476,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -8092,7 +8476,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
8092 IrInstruction **incoming_values = allocate<IrInstruction *>(2);8476 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
8093 incoming_values[0] = err_result;8477 incoming_values[0] = err_result;
8094 incoming_values[1] = unwrapped_payload;8478 incoming_values[1] = unwrapped_payload;
8095 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);8479 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
8096 incoming_blocks[0] = after_err_block;8480 incoming_blocks[0] = after_err_block;
8097 incoming_blocks[1] = after_ok_block;8481 incoming_blocks[1] = after_ok_block;
8098 IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent);8482 IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent);
...@@ -8680,7 +9064,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -8680,7 +9064,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
8680bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {9064bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
8681 assert(fn_entry);9065 assert(fn_entry);
86829066
8683 IrExecutable *ir_executable = &fn_entry->ir_executable;9067 IrExecutable *ir_executable = fn_entry->ir_executable;
8684 AstNode *body_node = fn_entry->body_node;9068 AstNode *body_node = fn_entry->body_node;
86859069
8686 assert(fn_entry->child_scope);9070 assert(fn_entry->child_scope);
...@@ -10224,6 +10608,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -10224,6 +10608,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
10224 return result;10608 return result;
10225 }10609 }
1022610610
10611 if (wanted_type->id == ZigTypeIdInt && actual_type->id == ZigTypeIdInt) {
10612 result.id = ConstCastResultIdIntShorten;
10613 result.data.int_shorten = allocate_nonzero<ConstCastIntShorten>(1);
10614 result.data.int_shorten->wanted_type = wanted_type;
10615 result.data.int_shorten->actual_type = actual_type;
10616 return result;
10617 }
10618
10227 result.id = ConstCastResultIdType;10619 result.id = ConstCastResultIdType;
10228 result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1);10620 result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1);
10229 result.data.type_mismatch->wanted_type = wanted_type;10621 result.data.type_mismatch->wanted_type = wanted_type;
...@@ -11490,7 +11882,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,...@@ -11490,7 +11882,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
11490 if (expected_type != nullptr && type_is_invalid(expected_type))11882 if (expected_type != nullptr && type_is_invalid(expected_type))
11491 return codegen->invalid_instruction->value;11883 return codegen->invalid_instruction->value;
1149211884
11493 IrExecutable *ir_executable = allocate<IrExecutable>(1);11885 IrExecutable *ir_executable = allocate<IrExecutable>(1, "IrExecutablePass1");
11494 ir_executable->source_node = source_node;11886 ir_executable->source_node = source_node;
11495 ir_executable->parent_exec = parent_exec;11887 ir_executable->parent_exec = parent_exec;
11496 ir_executable->name = exec_name;11888 ir_executable->name = exec_name;
...@@ -11512,7 +11904,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,...@@ -11512,7 +11904,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
11512 ir_print(codegen, stderr, ir_executable, 2, IrPassSrc);11904 ir_print(codegen, stderr, ir_executable, 2, IrPassSrc);
11513 fprintf(stderr, "}\n");11905 fprintf(stderr, "}\n");
11514 }11906 }
11515 IrExecutable *analyzed_executable = allocate<IrExecutable>(1);11907 IrExecutable *analyzed_executable = allocate<IrExecutable>(1, "IrExecutablePass2");
11516 analyzed_executable->source_node = source_node;11908 analyzed_executable->source_node = source_node;
11517 analyzed_executable->parent_exec = parent_exec;11909 analyzed_executable->parent_exec = parent_exec;
11518 analyzed_executable->source_exec = ir_executable;11910 analyzed_executable->source_exec = ir_executable;
...@@ -12641,6 +13033,17 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa...@@ -12641,6 +13033,17 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
12641 add_error_note(ira->codegen, parent_msg, source_node,13033 add_error_note(ira->codegen, parent_msg, source_node,
12642 buf_sprintf("calling convention mismatch"));13034 buf_sprintf("calling convention mismatch"));
12643 break;13035 break;
13036 case ConstCastResultIdIntShorten: {
13037 ZigType *wanted_type = cast_result->data.int_shorten->wanted_type;
13038 ZigType *actual_type = cast_result->data.int_shorten->actual_type;
13039 const char *wanted_signed = wanted_type->data.integral.is_signed ? "signed" : "unsigned";
13040 const char *actual_signed = actual_type->data.integral.is_signed ? "signed" : "unsigned";
13041 add_error_note(ira->codegen, parent_msg, source_node,
13042 buf_sprintf("%s %" PRIu32 "-bit int cannot represent all possible %s %" PRIu32 "-bit values",
13043 wanted_signed, wanted_type->data.integral.bit_count,
13044 actual_signed, actual_type->data.integral.bit_count));
13045 break;
13046 }
12644 case ConstCastResultIdFnAlign: // TODO13047 case ConstCastResultIdFnAlign: // TODO
12645 case ConstCastResultIdFnVarArgs: // TODO13048 case ConstCastResultIdFnVarArgs: // TODO
12646 case ConstCastResultIdFnReturnType: // TODO13049 case ConstCastResultIdFnReturnType: // TODO
...@@ -15597,6 +16000,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,...@@ -15597,6 +16000,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
15597 assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);16000 assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
15598 ZigValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);16001 ZigValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
15599 copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);16002 copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);
16003 ira_ref(var->owner_exec->analysis);
1560016004
15601 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {16005 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
15602 return ir_const_void(ira, &decl_var_instruction->base);16006 return ir_const_void(ira, &decl_var_instruction->base);
...@@ -15869,8 +16273,8 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,...@@ -15869,8 +16273,8 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,
15869 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);16273 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
15870 result->value->special = ConstValSpecialLazy;16274 result->value->special = ConstValSpecialLazy;
1587116275
15872 LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1);16276 LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1, "LazyValueErrUnionType");
15873 lazy_err_union_type->ira = ira;16277 lazy_err_union_type->ira = ira; ira_ref(ira);
15874 result->value->data.x_lazy = &lazy_err_union_type->base;16278 result->value->data.x_lazy = &lazy_err_union_type->base;
15875 lazy_err_union_type->base.id = LazyValueIdErrUnionType;16279 lazy_err_union_type->base.id = LazyValueIdErrUnionType;
1587616280
...@@ -17368,8 +17772,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -17368,8 +17772,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
17368 if (type_is_invalid(impl_fn->type_entry))17772 if (type_is_invalid(impl_fn->type_entry))
17369 return ira->codegen->invalid_instruction;17773 return ira->codegen->invalid_instruction;
1737017774
17371 impl_fn->ir_executable.source_node = call_instruction->base.source_node;17775 impl_fn->ir_executable->source_node = call_instruction->base.source_node;
17372 impl_fn->ir_executable.parent_exec = ira->new_irb.exec;17776 impl_fn->ir_executable->parent_exec = ira->new_irb.exec;
17373 impl_fn->analyzed_executable.source_node = call_instruction->base.source_node;17777 impl_fn->analyzed_executable.source_node = call_instruction->base.source_node;
17374 impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec;17778 impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec;
17375 impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota;17779 impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota;
...@@ -17722,8 +18126,8 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp...@@ -17722,8 +18126,8 @@ static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp
17722 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);18126 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
17723 result->value->special = ConstValSpecialLazy;18127 result->value->special = ConstValSpecialLazy;
1772418128
17725 LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1);18129 LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1, "LazyValueOptType");
17726 lazy_opt_type->ira = ira;18130 lazy_opt_type->ira = ira; ira_ref(ira);
17727 result->value->data.x_lazy = &lazy_opt_type->base;18131 result->value->data.x_lazy = &lazy_opt_type->base;
17728 lazy_opt_type->base.id = LazyValueIdOptType;18132 lazy_opt_type->base.id = LazyValueIdOptType;
1772918133
...@@ -19668,8 +20072,8 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,...@@ -19668,8 +20072,8 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
19668 IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type);20072 IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type);
19669 result->value->special = ConstValSpecialLazy;20073 result->value->special = ConstValSpecialLazy;
1967020074
19671 LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1);20075 LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1, "LazyValueSliceType");
19672 lazy_slice_type->ira = ira;20076 lazy_slice_type->ira = ira; ira_ref(ira);
19673 result->value->data.x_lazy = &lazy_slice_type->base;20077 result->value->data.x_lazy = &lazy_slice_type->base;
19674 lazy_slice_type->base.id = LazyValueIdSliceType;20078 lazy_slice_type->base.id = LazyValueIdSliceType;
1967520079
...@@ -19828,8 +20232,8 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi...@@ -19828,8 +20232,8 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi
19828 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);20232 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
19829 result->value->special = ConstValSpecialLazy;20233 result->value->special = ConstValSpecialLazy;
1983020234
19831 LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1);20235 LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1, "LazyValueSizeOf");
19832 lazy_size_of->ira = ira;20236 lazy_size_of->ira = ira; ira_ref(ira);
19833 result->value->data.x_lazy = &lazy_size_of->base;20237 result->value->data.x_lazy = &lazy_size_of->base;
19834 lazy_size_of->base.id = LazyValueIdSizeOf;20238 lazy_size_of->base.id = LazyValueIdSizeOf;
1983520239
...@@ -24556,8 +24960,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct...@@ -24556,8 +24960,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
24556 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);24960 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
24557 result->value->special = ConstValSpecialLazy;24961 result->value->special = ConstValSpecialLazy;
2455824962
24559 LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);24963 LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1, "LazyValueAlignOf");
24560 lazy_align_of->ira = ira;24964 lazy_align_of->ira = ira; ira_ref(ira);
24561 result->value->data.x_lazy = &lazy_align_of->base;24965 result->value->data.x_lazy = &lazy_align_of->base;
24562 lazy_align_of->base.id = LazyValueIdAlignOf;24966 lazy_align_of->base.id = LazyValueIdAlignOf;
2456324967
...@@ -25040,8 +25444,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct...@@ -25040,8 +25444,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
25040 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);25444 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
25041 result->value->special = ConstValSpecialLazy;25445 result->value->special = ConstValSpecialLazy;
2504225446
25043 LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1);25447 LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1, "LazyValueFnType");
25044 lazy_fn_type->ira = ira;25448 lazy_fn_type->ira = ira; ira_ref(ira);
25045 result->value->data.x_lazy = &lazy_fn_type->base;25449 result->value->data.x_lazy = &lazy_fn_type->base;
25046 lazy_fn_type->base.id = LazyValueIdFnType;25450 lazy_fn_type->base.id = LazyValueIdFnType;
2504725451
...@@ -26081,8 +26485,8 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct...@@ -26081,8 +26485,8 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
26081 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);26485 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
26082 result->value->special = ConstValSpecialLazy;26486 result->value->special = ConstValSpecialLazy;
2608326487
26084 LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1);26488 LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1, "LazyValuePtrType");
26085 lazy_ptr_type->ira = ira;26489 lazy_ptr_type->ira = ira; ira_ref(ira);
26086 result->value->data.x_lazy = &lazy_ptr_type->base;26490 result->value->data.x_lazy = &lazy_ptr_type->base;
26087 lazy_ptr_type->base.id = LazyValueIdPtrType;26491 lazy_ptr_type->base.id = LazyValueIdPtrType;
2608826492
...@@ -27551,7 +27955,8 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_...@@ -27551,7 +27955,8 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
27551 assert(old_exec->first_err_trace_msg == nullptr);27955 assert(old_exec->first_err_trace_msg == nullptr);
27552 assert(expected_type == nullptr || !type_is_invalid(expected_type));27956 assert(expected_type == nullptr || !type_is_invalid(expected_type));
2755327957
27554 IrAnalyze *ira = allocate<IrAnalyze>(1);27958 IrAnalyze *ira = allocate<IrAnalyze>(1, "IrAnalyze");
27959 ira->ref_count = 1;
27555 old_exec->analysis = ira;27960 old_exec->analysis = ira;
27556 ira->codegen = codegen;27961 ira->codegen = codegen;
2755727962
...@@ -27618,6 +28023,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_...@@ -27618,6 +28023,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
27618 ira->instruction_index += 1;28023 ira->instruction_index += 1;
27619 }28024 }
2762028025
28026 ZigType *res_type;
27621 if (new_exec->first_err_trace_msg != nullptr) {28027 if (new_exec->first_err_trace_msg != nullptr) {
27622 codegen->trace_err = new_exec->first_err_trace_msg;28028 codegen->trace_err = new_exec->first_err_trace_msg;
27623 if (codegen->trace_err != nullptr && new_exec->source_node != nullptr &&28029 if (codegen->trace_err != nullptr && new_exec->source_node != nullptr &&
...@@ -27627,13 +28033,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_...@@ -27627,13 +28033,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
27627 codegen->trace_err = add_error_note(codegen, codegen->trace_err,28033 codegen->trace_err = add_error_note(codegen, codegen->trace_err,
27628 new_exec->source_node, buf_create_from_str("referenced here"));28034 new_exec->source_node, buf_create_from_str("referenced here"));
27629 }28035 }
27630 return ira->codegen->builtin_types.entry_invalid;28036 res_type = ira->codegen->builtin_types.entry_invalid;
27631 } else if (ira->src_implicit_return_type_list.length == 0) {28037 } else if (ira->src_implicit_return_type_list.length == 0) {
27632 return codegen->builtin_types.entry_unreachable;28038 res_type = codegen->builtin_types.entry_unreachable;
27633 } else {28039 } else {
27634 return ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items,28040 res_type = ir_resolve_peer_types(ira, expected_type_source_node, expected_type, ira->src_implicit_return_type_list.items,
27635 ira->src_implicit_return_type_list.length);28041 ira->src_implicit_return_type_list.length);
27636 }28042 }
28043
28044 // It is now safe to free Pass 1 IR instructions.
28045 ira_deref(ira);
28046
28047 return res_type;
27637}28048}
2763828049
27639bool ir_has_side_effects(IrInstruction *instruction) {28050bool ir_has_side_effects(IrInstruction *instruction) {
...@@ -27969,6 +28380,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {...@@ -27969,6 +28380,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
27969 val->special = ConstValSpecialStatic;28380 val->special = ConstValSpecialStatic;
27970 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);28381 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
27971 bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);28382 bigint_init_unsigned(&val->data.x_bigint, align_in_bytes);
28383
28384 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
27972 return ErrorNone;28385 return ErrorNone;
27973 }28386 }
27974 case LazyValueIdSizeOf: {28387 case LazyValueIdSizeOf: {
...@@ -28024,6 +28437,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {...@@ -28024,6 +28437,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
28024 val->special = ConstValSpecialStatic;28437 val->special = ConstValSpecialStatic;
28025 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);28438 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
28026 bigint_init_unsigned(&val->data.x_bigint, abi_size);28439 bigint_init_unsigned(&val->data.x_bigint, abi_size);
28440
28441 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
28027 return ErrorNone;28442 return ErrorNone;
28028 }28443 }
28029 case LazyValueIdSliceType: {28444 case LazyValueIdSliceType: {
...@@ -28102,6 +28517,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {...@@ -28102,6 +28517,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
28102 val->special = ConstValSpecialStatic;28517 val->special = ConstValSpecialStatic;
28103 assert(val->type->id == ZigTypeIdMetaType);28518 assert(val->type->id == ZigTypeIdMetaType);
28104 val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type);28519 val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type);
28520
28521 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
28105 return ErrorNone;28522 return ErrorNone;
28106 }28523 }
28107 case LazyValueIdPtrType: {28524 case LazyValueIdPtrType: {
...@@ -28173,6 +28590,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {...@@ -28173,6 +28590,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
28173 lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes,28590 lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes,
28174 allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val);28591 allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val);
28175 val->special = ConstValSpecialStatic;28592 val->special = ConstValSpecialStatic;
28593
28594 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
28176 return ErrorNone;28595 return ErrorNone;
28177 }28596 }
28178 case LazyValueIdOptType: {28597 case LazyValueIdOptType: {
...@@ -28195,16 +28614,21 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {...@@ -28195,16 +28614,21 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
28195 assert(val->type->id == ZigTypeIdMetaType);28614 assert(val->type->id == ZigTypeIdMetaType);
28196 val->data.x_type = get_optional_type(ira->codegen, payload_type);28615 val->data.x_type = get_optional_type(ira->codegen, payload_type);
28197 val->special = ConstValSpecialStatic;28616 val->special = ConstValSpecialStatic;
28617
28618 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
28198 return ErrorNone;28619 return ErrorNone;
28199 }28620 }
28200 case LazyValueIdFnType: {28621 case LazyValueIdFnType: {
28201 LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(val->data.x_lazy);28622 LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(val->data.x_lazy);
28202 ZigType *fn_type = ir_resolve_lazy_fn_type(lazy_fn_type->ira, source_node, lazy_fn_type);28623 IrAnalyze *ira = lazy_fn_type->ira;
28624 ZigType *fn_type = ir_resolve_lazy_fn_type(ira, source_node, lazy_fn_type);
28203 if (fn_type == nullptr)28625 if (fn_type == nullptr)
28204 return ErrorSemanticAnalyzeFail;28626 return ErrorSemanticAnalyzeFail;
28205 val->special = ConstValSpecialStatic;28627 val->special = ConstValSpecialStatic;
28206 assert(val->type->id == ZigTypeIdMetaType);28628 assert(val->type->id == ZigTypeIdMetaType);
28207 val->data.x_type = fn_type;28629 val->data.x_type = fn_type;
28630
28631 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
28208 return ErrorNone;28632 return ErrorNone;
28209 }28633 }
28210 case LazyValueIdErrUnionType: {28634 case LazyValueIdErrUnionType: {
...@@ -28233,6 +28657,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {...@@ -28233,6 +28657,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
28233 assert(val->type->id == ZigTypeIdMetaType);28657 assert(val->type->id == ZigTypeIdMetaType);
28234 val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type);28658 val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type);
28235 val->special = ConstValSpecialStatic;28659 val->special = ConstValSpecialStatic;
28660
28661 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
28236 return ErrorNone;28662 return ErrorNone;
28237 }28663 }
28238 }28664 }
src/libc_installation.cpp+1-1
...@@ -389,7 +389,7 @@ static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, Zi...@@ -389,7 +389,7 @@ static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, Zi
389 }389 }
390 Buf search_path = BUF_INIT;390 Buf search_path = BUF_INIT;
391 buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);391 buf_init_from_mem(&search_path, sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
392 buf_append_str(&search_path, "\\..\\..\\include");392 buf_append_str(&search_path, "..\\..\\include");
393393
394 Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path));394 Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path));
395 bool exists;395 bool exists;
src/list.hpp+1-1
...@@ -13,7 +13,7 @@...@@ -13,7 +13,7 @@
13template<typename T>13template<typename T>
14struct ZigList {14struct ZigList {
15 void deinit() {15 void deinit() {
16 free(items);16 deallocate(items, capacity);
17 }17 }
18 void append(const T& item) {18 void append(const T& item) {
19 ensure_capacity(length + 1);19 ensure_capacity(length + 1);
src/memory_profiling.cpp+5-2
...@@ -35,7 +35,9 @@ static const char *get_default_name(const char *name_or_null, size_t type_size)...@@ -35,7 +35,9 @@ static const char *get_default_name(const char *name_or_null, size_t type_size)
35 if (name_or_null != nullptr) return name_or_null;35 if (name_or_null != nullptr) return name_or_null;
36 if (type_size >= unknown_names.length) {36 if (type_size >= unknown_names.length) {
37 table_active = false;37 table_active = false;
38 unknown_names.resize(type_size + 1);38 while (type_size >= unknown_names.length) {
39 unknown_names.append(nullptr);
40 }
39 table_active = true;41 table_active = true;
40 }42 }
41 if (unknown_names.at(type_size) == nullptr) {43 if (unknown_names.at(type_size) == nullptr) {
...@@ -66,7 +68,8 @@ void memprof_dealloc(const char *name, size_t count, size_t type_size) {...@@ -66,7 +68,8 @@ void memprof_dealloc(const char *name, size_t count, size_t type_size) {
66 name = get_default_name(name, type_size);68 name = get_default_name(name, type_size);
67 auto existing_entry = usage_table.maybe_get(name);69 auto existing_entry = usage_table.maybe_get(name);
68 if (existing_entry == nullptr) {70 if (existing_entry == nullptr) {
69 zig_panic("deallocated more than allocated; compromised memory usage stats");71 zig_panic("deallocated name '%s' (size %zu) not found in allocated table; compromised memory usage stats",
72 name, type_size);
70 }73 }
71 if (existing_entry->value.type_size != type_size) {74 if (existing_entry->value.type_size != type_size) {
72 zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size);75 zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size);
src/os.cpp+4-4
...@@ -1554,7 +1554,7 @@ void os_stderr_set_color(TermColor color) {...@@ -1554,7 +1554,7 @@ void os_stderr_set_color(TermColor color) {
1554Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {1554Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
1555#if defined(ZIG_OS_WINDOWS)1555#if defined(ZIG_OS_WINDOWS)
1556 buf_resize(output_buf, 0);1556 buf_resize(output_buf, 0);
1557 buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);1557 buf_appendf(output_buf, "%sLib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
1558 switch (platform_type) {1558 switch (platform_type) {
1559 case ZigLLVM_x86:1559 case ZigLLVM_x86:
1560 buf_append_str(output_buf, "x86\\");1560 buf_append_str(output_buf, "x86\\");
...@@ -1586,7 +1586,7 @@ Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Ar...@@ -1586,7 +1586,7 @@ Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Ar
1586Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {1586Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
1587#if defined(ZIG_OS_WINDOWS)1587#if defined(ZIG_OS_WINDOWS)
1588 buf_resize(output_buf, 0);1588 buf_resize(output_buf, 0);
1589 buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);1589 buf_appendf(output_buf, "%sInclude\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
1590 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {1590 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
1591 return ErrorNone;1591 return ErrorNone;
1592 }1592 }
...@@ -1603,7 +1603,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch...@@ -1603,7 +1603,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
1603#if defined(ZIG_OS_WINDOWS)1603#if defined(ZIG_OS_WINDOWS)
1604 {1604 {
1605 buf_resize(output_buf, 0);1605 buf_resize(output_buf, 0);
1606 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);1606 buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);
1607 switch (platform_type) {1607 switch (platform_type) {
1608 case ZigLLVM_x86:1608 case ZigLLVM_x86:
1609 buf_append_str(output_buf, "x86\\");1609 buf_append_str(output_buf, "x86\\");
...@@ -1626,7 +1626,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch...@@ -1626,7 +1626,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
1626 }1626 }
1627 {1627 {
1628 buf_resize(output_buf, 0);1628 buf_resize(output_buf, 0);
1629 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);1629 buf_appendf(output_buf, "%sLib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);
1630 switch (platform_type) {1630 switch (platform_type) {
1631 case ZigLLVM_x86:1631 case ZigLLVM_x86:
1632 buf_append_str(output_buf, "x86\\");1632 buf_append_str(output_buf, "x86\\");
src/util.hpp+1-1
...@@ -165,7 +165,7 @@ static inline void deallocate(T *old, size_t count, const char *name = nullptr)...@@ -165,7 +165,7 @@ static inline void deallocate(T *old, size_t count, const char *name = nullptr)
165165
166template<typename T>166template<typename T>
167static inline void destroy(T *old, const char *name = nullptr) {167static inline void destroy(T *old, const char *name = nullptr) {
168 return deallocate(old, 1);168 return deallocate(old, 1, name);
169}169}
170170
171template <typename T, size_t n>171template <typename T, size_t n>
test/compile_errors.zig+7
...@@ -1670,10 +1670,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -1670,10 +1670,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
1670 \\ var spartan_count: u16 = 300;1670 \\ var spartan_count: u16 = 300;
1671 \\ var byte: u8 = spartan_count;1671 \\ var byte: u8 = spartan_count;
1672 \\}1672 \\}
1673 \\export fn entry4() void {
1674 \\ var signed: i8 = -1;
1675 \\ var unsigned: u64 = signed;
1676 \\}
1673 ,1677 ,
1674 "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'",1678 "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'",
1675 "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'",1679 "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'",
1676 "tmp.zig:11:20: error: expected type 'u8', found 'u16'",1680 "tmp.zig:11:20: error: expected type 'u8', found 'u16'",
1681 "tmp.zig:11:20: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values",
1682 "tmp.zig:15:25: error: expected type 'u64', found 'i8'",
1683 "tmp.zig:15:25: note: unsigned 64-bit int cannot represent all possible signed 8-bit values",
1677 );1684 );
16781685
1679 cases.add(1686 cases.add(
test/gen_h.zig+17-15
...@@ -10,9 +10,8 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -10,9 +10,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
10 \\ B = 1,10 \\ B = 1,
11 \\ C = 211 \\ C = 2
12 \\};12 \\};
13 \\13 ,
14 \\TEST_EXTERN_C void entry(enum Foo foo);14 \\void entry(enum Foo foo);
15 \\
16 );15 );
1716
18 cases.add("declare struct",17 cases.add("declare struct",
...@@ -34,8 +33,8 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -34,8 +33,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
34 \\ uint64_t E;33 \\ uint64_t E;
35 \\ uint64_t F;34 \\ uint64_t F;
36 \\};35 \\};
37 \\36 ,
38 \\TEST_EXTERN_C void entry(struct Foo foo);37 \\void entry(struct Foo foo);
39 \\38 \\
40 );39 );
4140
...@@ -69,19 +68,19 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -69,19 +68,19 @@ pub fn addCases(cases: *tests.GenHContext) void {
69 \\ bool C;68 \\ bool C;
70 \\ struct Big D;69 \\ struct Big D;
71 \\};70 \\};
72 \\71 ,
73 \\TEST_EXTERN_C void entry(union Foo foo);72 \\void entry(union Foo foo);
74 \\73 \\
75 );74 );
7675
77 cases.add("declare opaque type",76 cases.add("declare opaque type",
78 \\export const Foo = @OpaqueType();77 \\const Foo = @OpaqueType();
79 \\78 \\
80 \\export fn entry(foo: ?*Foo) void { }79 \\export fn entry(foo: ?*Foo) void { }
81 ,80 ,
82 \\struct Foo;81 \\struct Foo;
83 \\82 ,
84 \\TEST_EXTERN_C void entry(struct Foo * foo);83 \\void entry(struct Foo * foo);
85 );84 );
8685
87 cases.add("array field-type",86 cases.add("array field-type",
...@@ -95,8 +94,8 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -95,8 +94,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
95 \\ int32_t A[2];94 \\ int32_t A[2];
96 \\ uint32_t * B[4];95 \\ uint32_t * B[4];
97 \\};96 \\};
98 \\97 ,
99 \\TEST_EXTERN_C void entry(struct Foo foo, uint8_t bar[]);98 \\void entry(struct Foo foo, uint8_t bar[]);
100 \\99 \\
101 );100 );
102101
...@@ -110,7 +109,8 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -110,7 +109,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
110 \\}109 \\}
111 ,110 ,
112 \\struct S;111 \\struct S;
113 \\TEST_EXTERN_C uint8_t a(struct S * s);112 ,
113 \\uint8_t a(struct S * s);
114 \\114 \\
115 );115 );
116116
...@@ -125,7 +125,8 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -125,7 +125,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
125 \\}125 \\}
126 ,126 ,
127 \\union U;127 \\union U;
128 \\TEST_EXTERN_C uint8_t a(union U * s);128 ,
129 \\uint8_t a(union U * s);
129 \\130 \\
130 );131 );
131132
...@@ -140,7 +141,8 @@ pub fn addCases(cases: *tests.GenHContext) void {...@@ -140,7 +141,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
140 \\}141 \\}
141 ,142 ,
142 \\enum E;143 \\enum E;
143 \\TEST_EXTERN_C uint8_t a(enum E * s);144 ,
145 \\uint8_t a(enum E * s);
144 \\146 \\
145 );147 );
146}148}
test/standalone/cat/main.zig+5-3
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const io = std.io;2const io = std.io;
3const process = std.process;3const process = std.process;
4const File = std.fs.File;4const fs = std.fs;
5const mem = std.mem;5const mem = std.mem;
6const warn = std.debug.warn;6const warn = std.debug.warn;
7const allocator = std.debug.global_allocator;7const allocator = std.debug.global_allocator;
...@@ -12,6 +12,8 @@ pub fn main() !void {...@@ -12,6 +12,8 @@ pub fn main() !void {
12 var catted_anything = false;12 var catted_anything = false;
13 const stdout_file = io.getStdOut();13 const stdout_file = io.getStdOut();
1414
15 const cwd = fs.cwd();
16
15 while (args_it.next(allocator)) |arg_or_err| {17 while (args_it.next(allocator)) |arg_or_err| {
16 const arg = try unwrapArg(arg_or_err);18 const arg = try unwrapArg(arg_or_err);
17 if (mem.eql(u8, arg, "-")) {19 if (mem.eql(u8, arg, "-")) {
...@@ -20,7 +22,7 @@ pub fn main() !void {...@@ -20,7 +22,7 @@ pub fn main() !void {
20 } else if (arg[0] == '-') {22 } else if (arg[0] == '-') {
21 return usage(exe);23 return usage(exe);
22 } else {24 } else {
23 const file = File.openRead(arg) catch |err| {25 const file = cwd.openFile(arg, .{}) catch |err| {
24 warn("Unable to open file: {}\n", @errorName(err));26 warn("Unable to open file: {}\n", @errorName(err));
25 return err;27 return err;
26 };28 };
...@@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void {...@@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void {
40 return error.Invalid;42 return error.Invalid;
41}43}
4244
43fn cat_file(stdout: File, file: File) !void {45fn cat_file(stdout: fs.File, file: fs.File) !void {
44 var buf: [1024 * 4]u8 = undefined;46 var buf: [1024 * 4]u8 = undefined;
4547
46 while (true) {48 while (true) {
test/standalone/static_c_lib/foo.c+2
...@@ -2,3 +2,5 @@...@@ -2,3 +2,5 @@
2uint32_t add(uint32_t a, uint32_t b) {2uint32_t add(uint32_t a, uint32_t b) {
3 return a + b;3 return a + b;
4}4}
5
6uint32_t foo = 12345;
test/standalone/static_c_lib/foo.h+1
...@@ -1,2 +1,3 @@...@@ -1,2 +1,3 @@
1#include <stdint.h>1#include <stdint.h>
2uint32_t add(uint32_t a, uint32_t b);2uint32_t add(uint32_t a, uint32_t b);
3extern uint32_t foo;
test/standalone/static_c_lib/foo.zig+4
...@@ -6,3 +6,7 @@ test "C add" {...@@ -6,3 +6,7 @@ test "C add" {
6 const result = c.add(1, 2);6 const result = c.add(1, 2);
7 expect(result == 3);7 expect(result == 3);
8}8}
9
10test "C extern variable" {
11 expect(c.foo == 12345);
12}
test/tests.zig+20
...@@ -70,6 +70,26 @@ const test_targets = [_]TestTarget{...@@ -70,6 +70,26 @@ const test_targets = [_]TestTarget{
70 .link_libc = true,70 .link_libc = true,
71 },71 },
7272
73 TestTarget{
74 .target = Target{
75 .Cross = CrossTarget{
76 .os = .linux,
77 .arch = .i386,
78 .abi = .none,
79 },
80 },
81 },
82 TestTarget{
83 .target = Target{
84 .Cross = CrossTarget{
85 .os = .linux,
86 .arch = .i386,
87 .abi = .musl,
88 },
89 },
90 .link_libc = true,
91 },
92
73 TestTarget{93 TestTarget{
74 .target = Target{94 .target = Target{
75 .Cross = CrossTarget{95 .Cross = CrossTarget{