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
signaturelock-open 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; }
74557455 Attempting to convert a number which is out of range of the destination type results in
74567456 safety-protected {#link|Undefined Behavior#}.
74577457 </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>
74587462 {#header_close#}
74597463
74607464 {#header_open|@intToEnum#}
......@@ -8206,10 +8210,6 @@ test "integer truncation" {
82068210 This function always truncates the significant bits of the integer, regardless
82078211 of endianness on the target platform.
82088212 </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>
82138213 {#header_close#}
82148214
82158215 {#header_open|@Type#}
lib/std/array_list.zig+17
......@@ -40,6 +40,14 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
4040 .allocator = allocator,
4141 };
4242 }
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
4452 /// Release all allocated memory.
4553 pub fn deinit(self: Self) void {
......@@ -271,6 +279,15 @@ test "std.ArrayList.init" {
271279 testing.expect(list.capacity() == 0);
272280}
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
274291test "std.ArrayList.basic" {
275292 var bytes: [1024]u8 = undefined;
276293 const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
lib/std/buffer.zig+35-1
......@@ -16,13 +16,22 @@ pub const Buffer = struct {
1616 mem.copy(u8, self.list.items, m);
1717 return self;
1818 }
19
19
20 /// Initialize memory to size bytes of undefined values.
2021 /// Must deinitialize with deinit.
2122 pub fn initSize(allocator: *Allocator, size: usize) !Buffer {
2223 var self = initNull(allocator);
2324 try self.resize(size);
2425 return self;
2526 }
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
2736 /// Must deinitialize with deinit.
2837 /// None of the other operations are valid until you do one of these:
......@@ -98,6 +107,13 @@ pub const Buffer = struct {
98107 pub fn len(self: Buffer) usize {
99108 return self.list.len - 1;
100109 }
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
102118 pub fn append(self: *Buffer, m: []const u8) !void {
103119 const old_len = self.len();
......@@ -151,3 +167,21 @@ test "simple Buffer" {
151167 try buf2.resize(4);
152168 testing.expect(buf.startsWith(buf2.toSlice()));
153169}
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 {
20622062 }
20632063
20642064 pub fn addPathDir(self: *RunStep, search_path: []const u8) void {
2065 const PATH = if (builtin.os == .windows) "Path" else "PATH";
20662065 const env_map = self.getEnvMap();
2067 const prev_path = env_map.get(PATH) orelse {
2068 env_map.set(PATH, search_path) catch unreachable;
2069 return;
2070 };
2071 const new_path = self.builder.fmt("{}" ++ &[1]u8{fs.path.delimiter} ++ "{}", prev_path, search_path);
2072 env_map.set(PATH, new_path) catch unreachable;
2066
2067 var key: []const u8 = undefined;
2068 var prev_path: ?[]const u8 = undefined;
2069 if (builtin.os == .windows) {
2070 key = "Path";
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 }
20732087 }
20742088
20752089 pub fn getEnvMap(self: *RunStep) *BufMap {
......@@ -2178,7 +2192,7 @@ const InstallArtifactStep = struct {
21782192
21792193 const full_dest_path = builder.getInstallPath(self.dest_dir, self.artifact.out_filename);
21802194 try builder.updateFile(self.artifact.getOutputPath(), full_dest_path);
2181 if (self.artifact.isDynamicLibrary()) {
2195 if (self.artifact.isDynamicLibrary() and self.artifact.target.wantSharedLibSymLinks()) {
21822196 try doAtomicSymLinks(builder.allocator, full_dest_path, self.artifact.major_only_filename, self.artifact.name_only_filename);
21832197 }
21842198 if (self.pdb_dir) |pdb_dir| {
......@@ -2405,7 +2419,7 @@ fn findVcpkgRoot(allocator: *Allocator) !?[]const u8 {
24052419 const path_file = try fs.path.join(allocator, &[_][]const u8{ appdata_path, "vcpkg.path.txt" });
24062420 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;
24092423 defer file.close();
24102424
24112425 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;
220220
221221pub const PTHREAD_COND_INITIALIZER = pthread_cond_t{};
222222pub 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;
223224pub extern "c" fn pthread_cond_signal(cond: *pthread_cond_t) c_int;
224225pub 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 {
11311131}
11321132
11331133fn 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, .{});
11351135 defer f.close();
11361136 // 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
20892089 const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx));
20902090
20912091 gop.kv.value = MachOFile{
2092 .bytes = try std.fs.Dir.cwd().readFileAllocAligned(
2092 .bytes = try std.fs.cwd().readFileAllocAligned(
20932093 di.ofiles.allocator,
20942094 ofile_path,
20952095 maxInt(usize),
......@@ -2417,6 +2417,12 @@ extern fn handleSegfaultLinux(sig: i32, info: *const os.siginfo_t, ctx_ptr: *con
24172417 std.debug.warn("Segmentation fault at address 0x{x}\n", addr);
24182418
24192419 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 },
24202426 .x86_64 => {
24212427 const ctx = @ptrCast(*const os.ucontext_t, @alignCast(@alignOf(os.ucontext_t), ctx_ptr));
24222428 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 {
5454 /// For a zero length buffer, use `[0]T{}`.
5555 /// TODO https://github.com/ziglang/zig/issues/2765
5656 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
5761 self.* = SelfChannel{
5862 .buffer_len = 0,
5963 .buffer_nodes = buffer,
......@@ -184,11 +188,11 @@ pub fn Channel(comptime T: type) type {
184188 const get_node = &self.getters.get().?.data;
185189 switch (get_node.data) {
186190 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];
188192 },
189193 GetNode.Data.OrNull => |info| {
190194 _ = 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];
192196 },
193197 }
194198 global_event_loop.onNextTick(get_node.tick_node);
......@@ -222,7 +226,7 @@ pub fn Channel(comptime T: type) type {
222226 while (self.buffer_len != self.buffer_nodes.len and put_count != 0) {
223227 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;
226230 global_event_loop.onNextTick(put_node.tick_node);
227231 self.buffer_index +%= 1;
228232 self.buffer_len += 1;
......@@ -283,6 +287,29 @@ test "std.event.Channel" {
283287 await putter;
284288}
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
286313async fn testChannelGetter(channel: *Channel(i32)) void {
287314 const value1 = channel.get();
288315 testing.expect(value1 == 1234);
lib/std/event/fs.zig+15-13
......@@ -735,24 +735,26 @@ pub fn Watch(comptime V: type) type {
735735 allocator: *Allocator,
736736
737737 const OsData = switch (builtin.os) {
738 .macosx, .freebsd, .netbsd, .dragonfly => struct {
739 file_table: FileTable,
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
738 // TODO https://github.com/ziglang/zig/issues/3778
739 .macosx, .freebsd, .netbsd, .dragonfly => KqOsData,
750740 .linux => LinuxOsData,
751741 .windows => WindowsOsData,
752742
753743 else => @compileError("Unsupported OS"),
754744 };
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
756758 const WindowsOsData = struct {
757759 table_lock: event.Lock,
758760 dir_table: DirTable,
......@@ -1291,7 +1293,7 @@ pub fn Watch(comptime V: type) type {
12911293 os.linux.EINVAL => unreachable,
12921294 os.linux.EFAULT => unreachable,
12931295 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);
12951297 },
12961298 else => unreachable,
12971299 }
lib/std/fs.zig+229-49
......@@ -13,8 +13,6 @@ pub const File = @import("fs/file.zig").File;
1313
1414pub const symLink = os.symlink;
1515pub const symLinkC = os.symlinkC;
16pub const deleteFile = os.unlink;
17pub const deleteFileC = os.unlinkC;
1816pub const rename = os.rename;
1917pub const renameC = os.renameC;
2018pub const renameW = os.renameW;
......@@ -88,13 +86,15 @@ pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus {
8886/// If any of the directories do not exist for dest_path, they are created.
8987/// TODO https://github.com/ziglang/zig/issues/2885
9088pub 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, .{});
9292 defer src_file.close();
9393
9494 const src_stat = try src_file.stat();
9595 check_dest_stat: {
9696 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) {
9898 error.FileNotFound => break :check_dest_stat,
9999 else => |e| return e,
100100 };
......@@ -157,7 +157,7 @@ pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?Fil
157157/// in the same directory as dest_path.
158158/// Destination file will have the same mode as the source file.
159159pub 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, .{});
161161 defer in_file.close();
162162
163163 const mode = try in_file.mode();
......@@ -180,7 +180,7 @@ pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void {
180180/// merged and readily available,
181181/// there is a possibility of power loss or application termination leaving temporary files present
182182pub 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, .{});
184184 defer in_file.close();
185185
186186 var atomic_file = try AtomicFile.init(dest_path, mode);
......@@ -206,8 +206,6 @@ pub const AtomicFile = struct {
206206
207207 /// dest_path must remain valid for the lifetime of AtomicFile
208208 /// call finish to atomically replace dest_path with contents
209 /// TODO once we have null terminated pointers, use the
210 /// openWriteNoClobberN function
211209 pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile {
212210 const dirname = path.dirname(dest_path);
213211 var rand_buf: [12]u8 = undefined;
......@@ -224,15 +222,19 @@ pub const AtomicFile = struct {
224222
225223 tmp_path_buf[tmp_path_len] = 0;
226224
225 const my_cwd = cwd();
226
227227 while (true) {
228228 try crypto.randomBytes(rand_buf[0..]);
229229 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) {
232236 error.PathAlreadyExists => continue,
233 // TODO zig should figure out that this error set does not include PathAlreadyExists since
234 // it is handled in the above switch
235 else => return err,
237 else => |e| return e,
236238 };
237239
238240 return AtomicFile{
......@@ -248,7 +250,7 @@ pub const AtomicFile = struct {
248250 pub fn deinit(self: *AtomicFile) void {
249251 if (!self.finished) {
250252 self.file.close();
251 deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {};
253 cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {};
252254 self.finished = true;
253255 }
254256 }
......@@ -350,12 +352,12 @@ pub fn deleteTree(full_path: []const u8) !void {
350352 CannotDeleteRootDirectory,
351353 }.CannotDeleteRootDirectory;
352354
353 var dir = try Dir.cwd().openDirList(dirname);
355 var dir = try cwd().openDirList(dirname);
354356 defer dir.close();
355357
356358 return dir.deleteTree(path.basename(full_path));
357359 } else {
358 return Dir.cwd().deleteTree(full_path);
360 return cwd().deleteTree(full_path);
359361 }
360362}
361363
......@@ -657,17 +659,6 @@ pub const Dir = struct {
657659 }
658660 }
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
671662 pub const OpenError = error{
672663 FileNotFound,
673664 NotDir,
......@@ -683,12 +674,12 @@ pub const Dir = struct {
683674 DeviceBusy,
684675 } || os.UnexpectedError;
685676
686 /// Deprecated; call `Dir.cwd().openDirList` directly.
677 /// Deprecated; call `cwd().openDirList` directly.
687678 pub fn open(dir_path: []const u8) OpenError!Dir {
688679 return cwd().openDirList(dir_path);
689680 }
690681
691 /// Deprecated; call `Dir.cwd().openDirListC` directly.
682 /// Deprecated; call `cwd().openDirListC` directly.
692683 pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir {
693684 return cwd().openDirListC(dir_path_c);
694685 }
......@@ -698,29 +689,110 @@ pub const Dir = struct {
698689 self.* = undefined;
699690 }
700691
701 /// Call `File.close` on the result when done.
702 pub fn openRead(self: Dir, sub_path: []const u8) File.OpenError!File {
692 /// Opens a file for reading or writing, without attempting to create a new 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);
703697 if (builtin.os == .windows) {
704698 const path_w = try os.windows.sliceToPrefixedFileW(sub_path);
705 return self.openReadW(&path_w);
699 return self.openFileW(&path_w, flags);
706700 }
707701 const path_c = try os.toPosixPath(sub_path);
708 return self.openReadC(&path_c);
702 return self.openFileC(&path_c, flags);
709703 }
710704
711 /// Call `File.close` on the result when done.
712 pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File {
705 /// Same as `openFile` but the path parameter is null-terminated.
706 pub fn openFileC(self: Dir, sub_path: [*:0]const u8, flags: File.OpenFlags) File.OpenError!File {
713707 if (builtin.os == .windows) {
714708 const path_w = try os.windows.cStrToPrefixedFileW(sub_path);
715 return self.openReadW(&path_w);
709 return self.openFileW(&path_w, flags);
716710 }
717711 const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0;
718 const flags = O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
719 const fd = try os.openatC(self.fd, sub_path, flags, 0);
720 return File.openHandle(fd);
712 const os_flags = O_LARGEFILE | os.O_CLOEXEC | if (flags.write and flags.read)
713 @as(u32, os.O_RDWR)
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);
721730 }
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 {
724796 const w = os.windows;
725797
726798 var result = File{ .handle = undefined };
......@@ -750,13 +822,13 @@ pub const Dir = struct {
750822 var io: w.IO_STATUS_BLOCK = undefined;
751823 const rc = w.ntdll.NtCreateFile(
752824 &result.handle,
753 w.GENERIC_READ | w.SYNCHRONIZE,
825 access_mask,
754826 &attr,
755827 &io,
756828 null,
757829 w.FILE_ATTRIBUTE_NORMAL,
758 w.FILE_SHARE_READ,
759 w.FILE_OPEN,
830 w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
831 creation,
760832 w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT,
761833 null,
762834 0,
......@@ -771,6 +843,7 @@ pub const Dir = struct {
771843 w.STATUS.ACCESS_DENIED => return error.AccessDenied,
772844 w.STATUS.PIPE_BUSY => return error.PipeBusy,
773845 w.STATUS.OBJECT_PATH_SYNTAX_BAD => unreachable,
846 w.STATUS.OBJECT_NAME_COLLISION => return error.PathAlreadyExists,
774847 else => return w.unexpectedStatus(rc),
775848 }
776849 }
......@@ -790,7 +863,10 @@ pub const Dir = struct {
790863 /// list the contents of a directory, open it with `openDirList`.
791864 ///
792865 /// Call `close` on the result when done.
866 ///
867 /// Asserts that the path parameter has no null bytes.
793868 pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir {
869 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
794870 if (builtin.os == .windows) {
795871 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
796872 return self.openDirTraverseW(&sub_path_w);
......@@ -805,7 +881,10 @@ pub const Dir = struct {
805881 /// same and may be more efficient.
806882 ///
807883 /// Call `close` on the result when done.
884 ///
885 /// Asserts that the path parameter has no null bytes.
808886 pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir {
887 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
809888 if (builtin.os == .windows) {
810889 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
811890 return self.openDirListW(&sub_path_w);
......@@ -920,9 +999,12 @@ pub const Dir = struct {
920999 pub const DeleteFileError = os.UnlinkError;
9211000
9221001 /// 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.
9231003 pub fn deleteFile(self: Dir, sub_path: []const u8) DeleteFileError!void {
924 const sub_path_c = try os.toPosixPath(sub_path);
925 return self.deleteFileC(&sub_path_c);
1004 os.unlinkat(self.fd, sub_path, 0) catch |err| switch (err) {
1005 error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR
1006 else => |e| return e,
1007 };
9261008 }
9271009
9281010 /// Same as `deleteFile` except the parameter is null-terminated.
......@@ -933,6 +1015,14 @@ pub const Dir = struct {
9331015 };
9341016 }
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
9361026 pub const DeleteDirError = error{
9371027 DirNotEmpty,
9381028 FileNotFound,
......@@ -951,7 +1041,9 @@ pub const Dir = struct {
9511041
9521042 /// Returns `error.DirNotEmpty` if the directory is not empty.
9531043 /// To delete a directory recursively, see `deleteTree`.
1044 /// Asserts that the path parameter has no null bytes.
9541045 pub fn deleteDir(self: Dir, sub_path: []const u8) DeleteDirError!void {
1046 if (std.debug.runtime_safety) for (sub_path) |byte| assert(byte != 0);
9551047 if (builtin.os == .windows) {
9561048 const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path);
9571049 return self.deleteDirW(&sub_path_w);
......@@ -979,7 +1071,9 @@ pub const Dir = struct {
9791071
9801072 /// Read value of a symbolic link.
9811073 /// The return value is a slice of `buffer`, from index `0`.
1074 /// Asserts that the path parameter has no null bytes.
9821075 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);
9831077 const sub_path_c = try os.toPosixPath(sub_path);
9841078 return self.readLinkC(&sub_path_c, buffer);
9851079 }
......@@ -1190,8 +1284,94 @@ pub const Dir = struct {
11901284 }
11911285 }
11921286 }
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 }
11931295};
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
11951375pub const Walker = struct {
11961376 stack: std.ArrayList(StackItem),
11971377 name_buffer: std.Buffer,
......@@ -1264,7 +1444,7 @@ pub const Walker = struct {
12641444pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker {
12651445 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);
12681448 errdefer dir.close();
12691449
12701450 var name_buffer = try std.Buffer.init(allocator, dir_path);
......@@ -1298,18 +1478,18 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE
12981478
12991479pub fn openSelfExe() OpenSelfExeError!File {
13001480 if (builtin.os == .linux) {
1301 return File.openReadC("/proc/self/exe");
1481 return openFileAbsoluteC("/proc/self/exe", .{});
13021482 }
13031483 if (builtin.os == .windows) {
13041484 const wide_slice = selfExePathW();
13051485 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);
13071487 }
13081488 var buf: [MAX_PATH_BYTES]u8 = undefined;
13091489 const self_exe_path = try selfExePath(&buf);
13101490 buf[self_exe_path.len] = 0;
1311 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
1312 return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr));
1491 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
1492 return openFileAbsoluteC(@ptrCast([*:0]u8, self_exe_path.ptr), .{});
13131493}
13141494
13151495test "openSelfExe" {
lib/std/fs/file.zig+56-73
......@@ -25,105 +25,87 @@ pub const File = struct {
2525
2626 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.
2953 pub fn openRead(path: []const u8) OpenError!File {
30 return std.fs.Dir.cwd().openRead(path);
54 return std.fs.cwd().openFile(path, .{});
3155 }
3256
33 /// Deprecated; call `std.fs.Dir.openReadC` directly.
57 /// Deprecated; call `std.fs.Dir.openFileC` directly.
3458 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, .{});
3660 }
3761
38 /// Deprecated; call `std.fs.Dir.openReadW` directly.
62 /// Deprecated; call `std.fs.Dir.openFileW` directly.
3963 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, .{});
4165 }
4266
43 /// Calls `openWriteMode` with `default_mode` for the mode.
44 /// TODO: deprecate this and move it to `std.fs.Dir`.
67 /// Deprecated; call `std.fs.Dir.createFile` directly.
4568 pub fn openWrite(path: []const u8) OpenError!File {
46 return openWriteMode(path, default_mode);
69 return std.fs.cwd().createFile(path, .{});
4770 }
4871
49 /// If the path does not exist it will be created.
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`.
72 /// Deprecated; call `std.fs.Dir.createFile` directly.
5373 pub fn openWriteMode(path: []const u8, file_mode: Mode) OpenError!File {
54 if (builtin.os == .windows) {
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);
74 return std.fs.cwd().createFile(path, .{ .mode = file_mode });
6075 }
6176
62 /// Same as `openWriteMode` except `path` is null-terminated.
63 /// TODO: deprecate this and move it to `std.fs.Dir`.
64 pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File {
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);
77 /// Deprecated; call `std.fs.Dir.createFileC` directly.
78 pub fn openWriteModeC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File {
79 return std.fs.cwd().createFileC(path_c, .{ .mode = file_mode });
7380 }
7481
75 /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded
76 /// TODO: deprecate this and move it to `std.fs.Dir`.
82 /// Deprecated; call `std.fs.Dir.createFileW` directly.
7783 pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
78 const handle = try windows.CreateFileW(
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);
84 return std.fs.cwd().createFileW(path_w, .{ .mode = file_mode });
8885 }
8986
90 /// If the path does not exist it will be created.
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`.
87 /// Deprecated; call `std.fs.Dir.createFile` directly.
9488 pub fn openWriteNoClobber(path: []const u8, file_mode: Mode) OpenError!File {
95 if (builtin.os == .windows) {
96 const path_w = try windows.sliceToPrefixedFileW(path);
97 return openWriteNoClobberW(&path_w, file_mode);
98 }
99 const path_c = try os.toPosixPath(path);
100 return openWriteNoClobberC(&path_c, file_mode);
89 return std.fs.cwd().createFile(path, .{
90 .mode = file_mode,
91 .exclusive = true,
92 });
10193 }
10294
103 /// TODO: deprecate this and move it to `std.fs.Dir`.
104 pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File {
105 if (builtin.os == .windows) {
106 const path_w = try windows.cStrToPrefixedFileW(path);
107 return openWriteNoClobberW(&path_w, file_mode);
108 }
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);
95 /// Deprecated; call `std.fs.Dir.createFileC` directly.
96 pub fn openWriteNoClobberC(path_c: [*:0]const u8, file_mode: Mode) OpenError!File {
97 return std.fs.cwd().createFileC(path_c, .{
98 .mode = file_mode,
99 .exclusive = true,
100 });
113101 }
114102
115 /// TODO: deprecate this and move it to `std.fs.Dir`.
103 /// Deprecated; call `std.fs.Dir.createFileW` directly.
116104 pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File {
117 const handle = try windows.CreateFileW(
118 path_w,
119 windows.GENERIC_WRITE,
120 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
121 null,
122 windows.CREATE_NEW,
123 windows.FILE_ATTRIBUTE_NORMAL,
124 null,
125 );
126 return openHandle(handle);
105 return std.fs.cwd().createFileW(path_w, .{
106 .mode = file_mode,
107 .exclusive = true,
108 });
127109 }
128110
129111 pub fn openHandle(handle: os.fd_t) File {
......@@ -246,6 +228,7 @@ pub const File = struct {
246228 windows.STATUS.SUCCESS => {},
247229 windows.STATUS.BUFFER_OVERFLOW => {},
248230 windows.STATUS.INVALID_PARAMETER => unreachable,
231 windows.STATUS.ACCESS_DENIED => return error.AccessDenied,
249232 else => return windows.unexpectedStatus(rc),
250233 }
251234 return Stat{
lib/std/fs/path.zig+32-1
......@@ -130,6 +130,14 @@ test "join" {
130130 testJoinPosix(&[_][]const u8{ "a/", "/c" }, "a/c");
131131}
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
133141pub fn isAbsolute(path: []const u8) bool {
134142 if (builtin.os == .windows) {
135143 return isAbsoluteWindows(path);
......@@ -138,7 +146,7 @@ pub fn isAbsolute(path: []const u8) bool {
138146 }
139147}
140148
141pub fn isAbsoluteW(path_w: [*]const u16) bool {
149pub fn isAbsoluteW(path_w: [*:0]const u16) bool {
142150 if (path_w[0] == '/')
143151 return true;
144152
......@@ -176,10 +184,33 @@ pub fn isAbsoluteWindows(path: []const u8) bool {
176184 return false;
177185}
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
179206pub fn isAbsolutePosix(path: []const u8) bool {
180207 return path[0] == sep_posix;
181208}
182209
210pub fn isAbsolutePosixC(path_c: [*:0]const u8) bool {
211 return path_c[0] == sep_posix;
212}
213
183214test "isAbsoluteWindows" {
184215 testIsAbsoluteWindows("/", true);
185216 testIsAbsoluteWindows("//", true);
lib/std/io.zig+4-7
......@@ -61,17 +61,14 @@ pub const COutStream = @import("io/c_out_stream.zig").COutStream;
6161pub const InStream = @import("io/in_stream.zig").InStream;
6262pub 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`.
6565pub fn writeFile(path: []const u8, data: []const u8) !void {
66 var file = try File.openWrite(path);
67 defer file.close();
68 try file.write(data);
66 return fs.cwd().writeFile(path, data);
6967}
7068
71/// On success, caller owns returned buffer.
72/// This function is deprecated; use `std.fs.Dir.readFileAlloc`.
69/// Deprecated; use `std.fs.Dir.readFileAlloc`.
7370pub 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));
7572}
7673
7774pub 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" {
1414 var raw_bytes: [200 * 1024]u8 = undefined;
1515 var allocator = &std.heap.FixedBufferAllocator.init(raw_bytes[0..]).allocator;
1616
17 const cwd = fs.cwd();
18
1719 var data: [1024]u8 = undefined;
1820 var prng = DefaultPrng.init(1234);
1921 prng.random.bytes(data[0..]);
2022 const tmp_file_name = "temp_test_file.txt";
2123 {
22 var file = try File.openWrite(tmp_file_name);
24 var file = try cwd.createFile(tmp_file_name, .{});
2325 defer file.close();
2426
2527 var file_out_stream = file.outStream();
......@@ -32,8 +34,8 @@ test "write a file, read it, then delete it" {
3234 }
3335
3436 {
35 // make sure openWriteNoClobber doesn't harm the file
36 if (File.openWriteNoClobber(tmp_file_name, File.default_mode)) |file| {
37 // Make sure the exclusive flag is honored.
38 if (cwd.createFile(tmp_file_name, .{ .exclusive = true })) |file| {
3739 unreachable;
3840 } else |err| {
3941 std.debug.assert(err == File.OpenError.PathAlreadyExists);
......@@ -41,7 +43,7 @@ test "write a file, read it, then delete it" {
4143 }
4244
4345 {
44 var file = try File.openRead(tmp_file_name);
46 var file = try cwd.openFile(tmp_file_name, .{});
4547 defer file.close();
4648
4749 const file_size = try file.getEndPos();
......@@ -58,7 +60,7 @@ test "write a file, read it, then delete it" {
5860 expect(mem.eql(u8, contents["begin".len .. contents.len - "end".len], &data));
5961 expect(mem.eql(u8, contents[contents.len - "end".len ..], "end"));
6062 }
61 try fs.deleteFile(tmp_file_name);
63 try cwd.deleteFile(tmp_file_name);
6264}
6365
6466test "BufferOutStream" {
......@@ -274,7 +276,7 @@ test "BitOutStream" {
274276test "BitStreams with File Stream" {
275277 const tmp_file_name = "temp_test_file.txt";
276278 {
277 var file = try File.openWrite(tmp_file_name);
279 var file = try fs.cwd().createFile(tmp_file_name, .{});
278280 defer file.close();
279281
280282 var file_out = file.outStream();
......@@ -291,7 +293,7 @@ test "BitStreams with File Stream" {
291293 try bit_stream.flushBits();
292294 }
293295 {
294 var file = try File.openRead(tmp_file_name);
296 var file = try fs.cwd().openFile(tmp_file_name, .{});
295297 defer file.close();
296298
297299 var file_in = file.inStream();
......@@ -316,7 +318,7 @@ test "BitStreams with File Stream" {
316318
317319 expectError(error.EndOfStream, bit_stream.readBitsNoEof(u1, 1));
318320 }
319 try fs.deleteFile(tmp_file_name);
321 try fs.cwd().deleteFile(tmp_file_name);
320322}
321323
322324fn testIntSerializerDeserializer(comptime endian: builtin.Endian, comptime packing: io.Packing) !void {
......@@ -599,7 +601,7 @@ test "c out stream" {
599601 const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile;
600602 defer {
601603 _ = std.c.fclose(out_file);
602 fs.deleteFileC(filename) catch {};
604 fs.cwd().deleteFileC(filename) catch {};
603605 }
604606
605607 const out_stream = &io.COutStream.init(out_file).stream;
......@@ -608,10 +610,10 @@ test "c out stream" {
608610
609611test "File seek ops" {
610612 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, .{});
612614 defer {
613615 file.close();
614 fs.deleteFile(tmp_file_name) catch {};
616 fs.cwd().deleteFile(tmp_file_name) catch {};
615617 }
616618
617619 try file.write(&([_]u8{0x55} ** 8192));
......@@ -632,10 +634,10 @@ test "File seek ops" {
632634
633635test "updateTimes" {
634636 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 });
636638 defer {
637639 file.close();
638 std.fs.deleteFile(tmp_file_name) catch {};
640 std.fs.cwd().deleteFile(tmp_file_name) catch {};
639641 }
640642 var stat_old = try file.stat();
641643 // Set atime and mtime to 5s before
lib/std/math.zig-12
......@@ -25,18 +25,6 @@ pub const ln2 = 0.693147180559945309417232121458176568;
2525/// ln(10)
2626pub 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
4028/// 2/sqrt(π)
4129pub const two_sqrtpi = 1.128379167095512573896158903121545172;
4230
lib/std/mutex.zig+85-47
......@@ -1,13 +1,12 @@
11const std = @import("std.zig");
22const builtin = @import("builtin");
33const testing = std.testing;
4const SpinLock = std.SpinLock;
5const ThreadParker = std.ThreadParker;
4const ResetEvent = std.ResetEvent;
65
76/// Lock may be held only once. If the same thread
87/// 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:
10/// https://github.com/golang/go/blob/master/src/runtime/lock_futex.go
8/// This type supports static initialization and is based off of Webkit's WTF Lock (via rust parking_lot)
9/// https://github.com/Amanieu/parking_lot/blob/master/core/src/word_lock.rs
1110/// When an application is built in single threaded release mode, all the functions are
1211/// no-ops. In single threaded debug mode, there is deadlock detection.
1312pub const Mutex = if (builtin.single_threaded)
......@@ -39,80 +38,119 @@ pub const Mutex = if (builtin.single_threaded)
3938 }
4039else
4140 struct {
42 state: State, // TODO: make this an enum
43 parker: ThreadParker,
41 state: usize,
4442
45 const State = enum(u32) {
46 Unlocked,
47 Sleeping,
48 Locked,
49 };
43 const MUTEX_LOCK: usize = 1 << 0;
44 const QUEUE_LOCK: usize = 1 << 1;
45 const QUEUE_MASK: usize = ~(MUTEX_LOCK | QUEUE_LOCK);
46 const QueueNode = std.atomic.Stack(ResetEvent).Node;
5047
5148 /// number of iterations to spin yielding the cpu
5249 const SPIN_CPU = 4;
5350
54 /// number of iterations to perform in the cpu yield loop
51 /// number of iterations to spin in the cpu yield loop
5552 const SPIN_CPU_COUNT = 30;
5653
5754 /// number of iterations to spin yielding the thread
5855 const SPIN_THREAD = 1;
5956
6057 pub fn init() Mutex {
61 return Mutex{
62 .state = .Unlocked,
63 .parker = ThreadParker.init(),
64 };
58 return Mutex{ .state = 0 };
6559 }
6660
6761 pub fn deinit(self: *Mutex) void {
68 self.parker.deinit();
62 self.* = undefined;
6963 }
7064
7165 pub const Held = struct {
7266 mutex: *Mutex,
7367
7468 pub fn release(self: Held) void {
75 switch (@atomicRmw(State, &self.mutex.state, .Xchg, .Unlocked, .Release)) {
76 .Locked => {},
77 .Sleeping => self.mutex.parker.unpark(@ptrCast(*const u32, &self.mutex.state)),
78 .Unlocked => unreachable, // unlocking an unlocked mutex
79 else => unreachable, // should never be anything else
69 // since MUTEX_LOCK is the first bit, we can use (.Sub) instead of (.And, ~MUTEX_LOCK).
70 // this is because .Sub may be implemented more efficiently than the latter
71 // (e.g. `lock xadd` vs `cmpxchg` loop on x86)
72 const state = @atomicRmw(usize, &self.mutex.state, .Sub, MUTEX_LOCK, .Release);
73 if ((state & QUEUE_MASK) != 0 and (state & QUEUE_LOCK) == 0) {
74 self.mutex.releaseSlow(state);
8075 }
8176 }
8277 };
8378
8479 pub fn acquire(self: *Mutex) Held {
85 // Try and speculatively grab the lock.
86 // If it fails, the state is either Locked or Sleeping
87 // depending on if theres a thread stuck sleeping below.
88 var state = @atomicRmw(State, &self.state, .Xchg, .Locked, .Acquire);
89 if (state == .Unlocked)
90 return Held{ .mutex = self };
80 // fast path close to SpinLock fast path
81 if (@cmpxchgWeak(usize, &self.state, 0, MUTEX_LOCK, .Acquire, .Monotonic)) |current_state| {
82 self.acquireSlow(current_state);
83 }
84 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;
9290 while (true) {
93 // try and acquire the lock using cpu spinning on failure
94 var spin: usize = 0;
95 while (spin < SPIN_CPU) : (spin += 1) {
96 var value = @atomicLoad(State, &self.state, .Monotonic);
97 while (value == .Unlocked)
98 value = @cmpxchgWeak(State, &self.state, .Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
99 SpinLock.yield(SPIN_CPU_COUNT);
91
92 // try and acquire the lock if unlocked
93 if ((state & MUTEX_LOCK) == 0) {
94 state = @cmpxchgWeak(usize, &self.state, state, state | MUTEX_LOCK, .Acquire, .Monotonic) orelse return;
95 continue;
96 }
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;
100107 }
101108
102 // try and acquire the lock using thread rescheduling on failure
103 spin = 0;
104 while (spin < SPIN_THREAD) : (spin += 1) {
105 var value = @atomicLoad(State, &self.state, .Monotonic);
106 while (value == .Unlocked)
107 value = @cmpxchgWeak(State, &self.state, .Unlocked, state, .Acquire, .Monotonic) orelse return Held{ .mutex = self };
108 std.os.sched_yield() catch std.time.sleep(1);
109 // thread should block, try and add this event to the waiting queue
110 var node = QueueNode{
111 .next = @intToPtr(?*QueueNode, state & QUEUE_MASK),
112 .data = ResetEvent.init(),
113 };
114 defer node.data.deinit();
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;
109144 }
110145
111 // failed to acquire the lock, go to sleep until woken up by `Held.release()`
112 if (@atomicRmw(State, &self.state, .Xchg, .Sleeping, .Acquire) == .Unlocked)
113 return Held{ .mutex = self };
114 state = .Sleeping;
115 self.parker.park(@ptrCast(*const u32, &self.state), @enumToInt(State.Sleeping));
146 // try to pop the top node on the waiting queue stack to wake it up
147 // while at the same time unsetting the QUEUE_LOCK.
148 const node = @intToPtr(*QueueNode, state & QUEUE_MASK);
149 const new_state = @ptrToInt(node.next) | (state & MUTEX_LOCK);
150 state = @cmpxchgWeak(usize, &self.state, state, new_state, .Release, .Monotonic) orelse {
151 _ = node.data.set(false);
152 return;
153 };
116154 }
117155 }
118156 };
lib/std/net.zig+2-2
......@@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts(
812812 family: os.sa_family_t,
813813 port: u16,
814814) !void {
815 const file = fs.File.openReadC("/etc/hosts") catch |err| switch (err) {
815 const file = fs.openFileAbsoluteC("/etc/hosts", .{}) catch |err| switch (err) {
816816 error.FileNotFound,
817817 error.NotDir,
818818 error.AccessDenied,
......@@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void {
10061006 };
10071007 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) {
10101010 error.FileNotFound,
10111011 error.NotDir,
10121012 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
798798 path_buf[search_path.len] = '/';
799799 mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice);
800800 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/3731
801 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
802802 err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp);
803803 switch (err) {
804804 error.AccessDenied => seen_eacces = true,
......@@ -834,7 +834,7 @@ pub fn execvpe(
834834 @memcpy(arg_buf.ptr, arg.ptr, arg.len);
835835 arg_buf[arg.len] = 0;
836836
837 // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731
837 // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3770
838838 argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr);
839839 }
840840 argv_buf[argv_slice.len] = null;
......@@ -842,7 +842,7 @@ pub fn execvpe(
842842 const envp_buf = try createNullDelimitedEnvMap(allocator, env_map);
843843 defer freeNullDelimitedEnvMap(allocator, envp_buf);
844844
845 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
845 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
846846 const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr);
847847
848848 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.
863863 @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len);
864864 env_buf[env_buf.len - 1] = 0;
865865
866 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
866 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
867867 envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr);
868868 }
869869 assert(i == envp_count);
870870 }
871 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731
871 // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3770
872872 assert(envp_buf[envp_count] == null);
873873 return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count];
874874}
......@@ -1087,7 +1087,9 @@ pub const UnlinkatError = UnlinkError || error{
10871087};
10881088
10891089/// 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.
10901091pub 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);
10911093 if (builtin.os == .windows) {
10921094 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
10931095 return unlinkatW(dirfd, &file_path_w, flags);
......@@ -2026,7 +2028,10 @@ pub fn waitpid(pid: i32, flags: u32) u32 {
20262028 }
20272029}
20282030
2029pub const FStatError = error{SystemResources} || UnexpectedError;
2031pub const FStatError = error{
2032 SystemResources,
2033 AccessDenied,
2034} || UnexpectedError;
20302035
20312036pub fn fstat(fd: fd_t) FStatError!Stat {
20322037 var stat: Stat = undefined;
......@@ -2036,6 +2041,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
20362041 EINVAL => unreachable,
20372042 EBADF => unreachable, // Always a race condition.
20382043 ENOMEM => return error.SystemResources,
2044 EACCES => return error.AccessDenied,
20392045 else => |err| return unexpectedErrno(err),
20402046 }
20412047 }
......@@ -2045,6 +2051,7 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
20452051 EINVAL => unreachable,
20462052 EBADF => unreachable, // Always a race condition.
20472053 ENOMEM => return error.SystemResources,
2054 EACCES => return error.AccessDenied,
20482055 else => |err| return unexpectedErrno(err),
20492056 }
20502057}
lib/std/os/bits/linux.zig+1
......@@ -9,6 +9,7 @@ pub usingnamespace switch (builtin.arch) {
99};
1010
1111pub usingnamespace switch (builtin.arch) {
12 .i386 => @import("linux/i386.zig"),
1213 .x86_64 => @import("linux/x86_64.zig"),
1314 .aarch64 => @import("linux/arm64.zig"),
1415 .arm => @import("linux/arm-eabi.zig"),
lib/std/os/bits/linux/arm-eabi.zig-1
......@@ -466,7 +466,6 @@ pub const MAP_LOCKED = 0x2000;
466466/// don't check for reservations
467467pub const MAP_NORESERVE = 0x4000;
468468
469pub const VDSO_USEFUL = true;
470469pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
471470pub 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;
358358/// don't check for reservations
359359pub const MAP_NORESERVE = 0x4000;
360360
361pub const VDSO_USEFUL = true;
362361pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
363362pub 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;
454454pub const SO_SNDBUFFORCE = 31;
455455pub const SO_RCVBUFFORCE = 33;
456456
457pub const VDSO_USEFUL = true;
458457pub const VDSO_CGT_SYM = "__kernel_clock_gettime";
459458pub 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;
420420/// don't check for reservations
421421pub const MAP_NORESERVE = 0x4000;
422422
423pub const VDSO_USEFUL = true;
424423pub const VDSO_CGT_SYM = "__vdso_clock_gettime";
425424pub const VDSO_CGT_VER = "LINUX_2.6";
426425pub const VDSO_GETCPU_SYM = "__vdso_getcpu";
lib/std/os/linux.zig+49
......@@ -14,6 +14,7 @@ const vdso = @import("linux/vdso.zig");
1414const dl = @import("../dynamic_library.zig");
1515
1616pub usingnamespace switch (builtin.arch) {
17 .i386 => @import("linux/i386.zig"),
1718 .x86_64 => @import("linux/x86_64.zig"),
1819 .aarch64 => @import("linux/arm64.zig"),
1920 .arm => @import("linux/arm-eabi.zig"),
......@@ -743,26 +744,44 @@ pub fn sigismember(set: *const sigset_t, sig: u6) bool {
743744}
744745
745746pub 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 }
746750 return syscall3(SYS_getsockname, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));
747751}
748752
749753pub 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 }
750757 return syscall3(SYS_getpeername, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len));
751758}
752759
753760pub 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 }
754764 return syscall3(SYS_socket, domain, socket_type, protocol);
755765}
756766
757767pub 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 }
758771 return syscall5(SYS_setsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
759772}
760773
761774pub 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 }
762778 return syscall5(SYS_getsockopt, @bitCast(usize, @as(isize, fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
763779}
764780
765781pub 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 }
766785 return syscall3(SYS_sendmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);
767786}
768787
......@@ -807,42 +826,72 @@ pub fn sendmmsg(fd: i32, msgvec: [*]mmsghdr_const, vlen: u32, flags: u32) usize
807826}
808827
809828pub 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 }
810832 return syscall3(SYS_connect, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), len);
811833}
812834
813835pub 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 }
814839 return syscall3(SYS_recvmsg, @bitCast(usize, @as(isize, fd)), @ptrToInt(msg), flags);
815840}
816841
817842pub 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 }
818846 return syscall6(SYS_recvfrom, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
819847}
820848
821849pub 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 }
822853 return syscall2(SYS_shutdown, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, how)));
823854}
824855
825856pub 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 }
826860 return syscall3(SYS_bind, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @intCast(usize, len));
827861}
828862
829863pub 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 }
830867 return syscall2(SYS_listen, @bitCast(usize, @as(isize, fd)), backlog);
831868}
832869
833870pub 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 }
834874 return syscall6(SYS_sendto, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
835875}
836876
837877pub 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 }
838881 return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
839882}
840883
841884pub 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 }
842888 return accept4(fd, addr, len, 0);
843889}
844890
845891pub 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 }
846895 return syscall4(SYS_accept4, @bitCast(usize, @as(isize, fd)), @ptrToInt(addr), @ptrToInt(len), flags);
847896}
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;
44const mem = std.mem;
55const elf = std.elf;
66const expect = std.testing.expect;
7const fs = std.fs;
78
89test "getpid" {
910 expect(linux.getpid() != 0);
......@@ -45,14 +46,12 @@ test "timer" {
4546 err = linux.epoll_wait(@intCast(i32, epoll_fd), @ptrCast([*]linux.epoll_event, &events), 8, -1);
4647}
4748
48const File = std.fs.File;
49
5049test "statx" {
5150 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, .{});
5352 defer {
5453 file.close();
55 std.fs.deleteFile(tmp_file_name) catch {};
54 fs.cwd().deleteFile(tmp_file_name) catch {};
5655 }
5756
5857 var statx_buf: linux.Statx = undefined;
lib/std/os/linux/tls.zig+27
......@@ -109,12 +109,38 @@ const TLSImage = struct {
109109 tcb_offset: usize,
110110 dtv_offset: usize,
111111 data_offset: usize,
112 // Only used on the i386 architecture
113 gdt_entry_number: usize,
112114};
113115
114116pub var tls_image: ?TLSImage = null;
115117
116118pub fn setThreadPointer(addr: usize) void {
117119 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 },
118144 .x86_64 => {
119145 const rc = std.os.linux.syscall2(std.os.linux.SYS_arch_prctl, std.os.linux.ARCH_SET_FS, addr);
120146 assert(rc == 0);
......@@ -238,6 +264,7 @@ pub fn initTLS() ?*elf.Phdr {
238264 .tcb_offset = tcb_offset,
239265 .dtv_offset = dtv_offset,
240266 .data_offset = data_offset,
267 .gdt_entry_number = @bitCast(usize, @as(isize, -1)),
241268 };
242269 }
243270
lib/std/os/test.zig+2-2
......@@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" {
2020 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense");
2121 try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah");
2222 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| {
2424 @panic("expected error");
2525 } else |err| {
2626 expect(err == error.FileNotFound);
......@@ -111,7 +111,7 @@ test "AtomicFile" {
111111 const content = try io.readFileAlloc(allocator, test_out_file);
112112 expect(mem.eql(u8, content, test_content));
113113
114 try fs.deleteFile(test_out_file);
114 try fs.cwd().deleteFile(test_out_file);
115115}
116116
117117test "thread local storage" {
lib/std/os/wasi.zig+2-2
......@@ -12,8 +12,8 @@ comptime {
1212 assert(@alignOf(u16) == 2);
1313 assert(@alignOf(i32) == 4);
1414 assert(@alignOf(u32) == 4);
15 assert(@alignOf(i64) == 8);
16 assert(@alignOf(u64) == 8);
15 // assert(@alignOf(i64) == 8);
16 // assert(@alignOf(u64) == 8);
1717}
1818
1919pub 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;
66const os = std.os;
77const warn = std.debug.warn;
88const coff = std.coff;
9const fs = std.fs;
910const File = std.fs.File;
1011
1112const ArrayList = std.ArrayList;
......@@ -469,7 +470,7 @@ pub const Pdb = struct {
469470 msf: Msf,
470471
471472 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, .{});
473474 self.allocator = coff_ptr.allocator;
474475 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 {
197197// across .o file boundaries. fix comptime @ptrCast of nakedcc functions.
198198nakedcc fn clone() void {
199199 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 },
200243 .x86_64 => {
201244 asm volatile (
202245 \\ xor %%eax,%%eax
lib/std/std.zig+1-1
......@@ -16,6 +16,7 @@ pub const PackedIntSlice = @import("packed_int_array.zig").PackedIntSlice;
1616pub const PackedIntSliceEndian = @import("packed_int_array.zig").PackedIntSliceEndian;
1717pub const PriorityQueue = @import("priority_queue.zig").PriorityQueue;
1818pub const Progress = @import("progress.zig").Progress;
19pub const ResetEvent = @import("reset_event.zig").ResetEvent;
1920pub const SegmentedList = @import("segmented_list.zig").SegmentedList;
2021pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList;
2122pub const SpinLock = @import("spinlock.zig").SpinLock;
......@@ -23,7 +24,6 @@ pub const StringHashMap = @import("hash_map.zig").StringHashMap;
2324pub const TailQueue = @import("linked_list.zig").TailQueue;
2425pub const Target = @import("target.zig").Target;
2526pub const Thread = @import("thread.zig").Thread;
26pub const ThreadParker = @import("parker.zig").ThreadParker;
2727
2828pub const atomic = @import("atomic.zig");
2929pub const base64 = @import("base64.zig");
lib/std/testing.zig+33-1
......@@ -89,7 +89,26 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
8989 if (union_info.tag_type == null) {
9090 @compileError("Unable to compare untagged union values");
9191 }
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;
93112 },
94113
95114 .Optional => {
......@@ -124,6 +143,19 @@ pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
124143 }
125144}
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
127159/// This function is intended to be used only in tests. When the two slices are not
128160/// equal, prints diagnostics to stderr to show exactly how they are not equal,
129161/// then aborts.
lib/std/thread.zig+29-2
......@@ -314,11 +314,38 @@ pub const Thread = struct {
314314 os.CLONE_THREAD | os.CLONE_SYSVSEM | os.CLONE_PARENT_SETTID | os.CLONE_CHILD_CLEARTID |
315315 os.CLONE_DETACHED;
316316 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
317320 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 }
319337 flags |= os.CLONE_SETTLS;
320338 }
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 );
322349 switch (os.errno(rc)) {
323350 0 => return thread_ptr,
324351 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)
2525
2626 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;
2929 defer llvm.DisposeModule(module);
3030
31 llvm.SetTarget(module, comp.llvm_triple.ptr());
31 llvm.SetTarget(module, comp.llvm_triple.toSliceConst());
3232 llvm.SetDataLayout(module, comp.target_layout_str);
3333
3434 if (util.getObjectFormat(comp.target) == .coff) {
......@@ -48,23 +48,23 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
4848 const producer = try std.Buffer.allocPrint(
4949 &code.arena.allocator,
5050 "zig {}.{}.{}",
51 u32(c.ZIG_VERSION_MAJOR),
52 u32(c.ZIG_VERSION_MINOR),
53 u32(c.ZIG_VERSION_PATCH),
51 @as(u32, c.ZIG_VERSION_MAJOR),
52 @as(u32, c.ZIG_VERSION_MINOR),
53 @as(u32, c.ZIG_VERSION_PATCH),
5454 );
5555 const flags = "";
5656 const runtime_version = 0;
5757 const compile_unit_file = llvm.CreateFile(
5858 dibuilder,
59 comp.name.ptr(),
60 comp.root_package.root_src_dir.ptr(),
59 comp.name.toSliceConst(),
60 comp.root_package.root_src_dir.toSliceConst(),
6161 ) orelse return error.OutOfMemory;
6262 const is_optimized = comp.build_mode != .Debug;
6363 const compile_unit = llvm.CreateCompileUnit(
6464 dibuilder,
6565 DW.LANG_C99,
6666 compile_unit_file,
67 producer.ptr(),
67 producer.toSliceConst(),
6868 is_optimized,
6969 flags,
7070 runtime_version,
......@@ -99,7 +99,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
9999
100100 // verify the llvm module when safety is on
101101 if (std.debug.runtime_safety) {
102 var error_ptr: ?[*]u8 = null;
102 var error_ptr: ?[*:0]u8 = null;
103103 _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr);
104104 }
105105
......@@ -108,12 +108,12 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
108108 const is_small = comp.build_mode == .ReleaseSmall;
109109 const is_debug = comp.build_mode == .Debug;
110110
111 var err_msg: [*]u8 = undefined;
111 var err_msg: [*:0]u8 = undefined;
112112 // TODO integrate this with evented I/O
113113 if (llvm.TargetMachineEmitToFile(
114114 comp.target_machine,
115115 module,
116 output_path.ptr(),
116 output_path.toSliceConst(),
117117 llvm.EmitBinary,
118118 &err_msg,
119119 is_debug,
......@@ -154,7 +154,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
154154 const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context);
155155 const llvm_fn = llvm.AddFunction(
156156 ofile.module,
157 fn_val.symbol_name.ptr(),
157 fn_val.symbol_name.toSliceConst(),
158158 llvm_fn_type,
159159 ) orelse return error.OutOfMemory;
160160
......@@ -379,7 +379,7 @@ fn renderLoadUntyped(
379379 ptr: *llvm.Value,
380380 alignment: Type.Pointer.Align,
381381 vol: Type.Pointer.Vol,
382 name: [*]const u8,
382 name: [*:0]const u8,
383383) !*llvm.Value {
384384 const result = llvm.BuildLoad(ofile.builder, ptr, name) orelse return error.OutOfMemory;
385385 switch (vol) {
......@@ -390,7 +390,7 @@ fn renderLoadUntyped(
390390 return result;
391391}
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 {
394394 return renderLoadUntyped(ofile, ptr, ptr_type.key.alignment, ptr_type.key.vol, name);
395395}
396396
......@@ -438,7 +438,7 @@ pub fn renderAlloca(
438438) !*llvm.Value {
439439 const llvm_var_type = try var_type.getLlvmType(ofile.arena, ofile.context);
440440 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;
442442 llvm.SetAlignment(result, resolveAlign(ofile, alignment, llvm_var_type));
443443 return result;
444444}
src-self-hosted/compilation.zig+127-151
......@@ -93,7 +93,7 @@ pub const ZigCompiler = struct {
9393 return LlvmHandle{ .node = node };
9494 }
9595
96 pub async fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {
96 pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation {
9797 if (self.native_libc.start()) |ptr| return ptr;
9898 try self.native_libc.data.findNative(self.allocator);
9999 self.native_libc.resolve();
......@@ -133,62 +133,62 @@ pub const Compilation = struct {
133133 zig_std_dir: []const u8,
134134
135135 /// 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,
139 version_minor: u32,
140 version_patch: u32,
138 version_major: u32 = 0,
139 version_minor: u32 = 0,
140 version_patch: u32 = 0,
141141
142 linker_script: ?[]const u8,
143 out_h_path: ?[]const u8,
142 linker_script: ?[]const u8 = null,
143 out_h_path: ?[]const u8 = null,
144144
145 is_test: bool,
146 each_lib_rpath: bool,
147 strip: bool,
145 is_test: bool = false,
146 each_lib_rpath: bool = false,
147 strip: bool = false,
148148 is_static: bool,
149 linker_rdynamic: bool,
149 linker_rdynamic: bool = false,
150150
151 clang_argv: []const []const u8,
152 lib_dirs: []const []const u8,
153 rpath_list: []const []const u8,
154 assembly_files: []const []const u8,
151 clang_argv: []const []const u8 = [_][]const u8{},
152 lib_dirs: []const []const u8 = [_][]const u8{},
153 rpath_list: []const []const u8 = [_][]const u8{},
154 assembly_files: []const []const u8 = [_][]const u8{},
155155
156156 /// 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
159159 /// functions that have their own objects that we need to link
160160 /// 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
163163 pub const FnLinkSet = std.TailQueue(?*Value.Fn);
164164
165 windows_subsystem_windows: bool,
166 windows_subsystem_console: bool,
165 windows_subsystem_windows: bool = false,
166 windows_subsystem_console: bool = false,
167167
168168 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,
174 verbose_ast_tree: bool,
175 verbose_ast_fmt: bool,
176 verbose_cimport: bool,
177 verbose_ir: bool,
178 verbose_llvm_ir: bool,
179 verbose_link: bool,
173 verbose_tokenize: bool = false,
174 verbose_ast_tree: bool = false,
175 verbose_ast_fmt: bool = false,
176 verbose_cimport: bool = false,
177 verbose_ir: bool = false,
178 verbose_llvm_ir: bool = false,
179 verbose_link: bool = false,
180180
181 darwin_frameworks: []const []const u8,
182 darwin_version_min: DarwinVersionMin,
181 darwin_frameworks: []const []const u8 = [_][]const u8{},
182 darwin_version_min: DarwinVersionMin = .None,
183183
184 test_filters: []const []const u8,
185 test_name_prefix: ?[]const u8,
184 test_filters: []const []const u8 = [_][]const u8{},
185 test_name_prefix: ?[]const u8 = null,
186186
187 emit_file_type: Emit,
187 emit_file_type: Emit = .Binary,
188188
189189 kind: Kind,
190190
191 link_out_file: ?[]const u8,
191 link_out_file: ?[]const u8 = null,
192192 events: *event.Channel(Event),
193193
194194 exported_symbol_names: event.Locked(Decl.Table),
......@@ -213,7 +213,7 @@ pub const Compilation = struct {
213213
214214 target_machine: *llvm.TargetMachine,
215215 target_data_ref: *llvm.TargetData,
216 target_layout_str: [*]u8,
216 target_layout_str: [*:0]u8,
217217 target_ptr_bits: u32,
218218
219219 /// for allocating things which have the same lifetime as this Compilation
......@@ -222,16 +222,16 @@ pub const Compilation = struct {
222222 root_package: *Package,
223223 std_package: *Package,
224224
225 override_libc: ?*LibCInstallation,
225 override_libc: ?*LibCInstallation = null,
226226
227227 /// need to wait on this group before deinitializing
228228 deinit_group: event.Group(void),
229229
230 // destroy_frame: @Frame(createAsync),
231 // main_loop_frame: @Frame(Compilation.mainLoop),
232 main_loop_future: event.Future(void),
230 destroy_frame: *@Frame(createAsync),
231 main_loop_frame: *@Frame(Compilation.mainLoop),
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
236236 /// not locked because it is read-only
237237 primitive_type_table: TypeTable,
......@@ -243,7 +243,9 @@ pub const Compilation = struct {
243243
244244 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
248250 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
249251 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 {
348350 zig_lib_dir: []const u8,
349351 ) !*Compilation {
350352 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(
352356 &optional_comp,
353357 zig_compiler,
354358 name,
......@@ -359,11 +363,11 @@ pub const Compilation = struct {
359363 is_static,
360364 zig_lib_dir,
361365 );
366 // TODO causes segfault
367 // return optional_comp orelse if (await frame) |_| unreachable else |err| err;
362368 if (optional_comp) |comp| {
363369 return comp;
364 } else {
365 if (await frame) |_| unreachable else |err| return err;
366 }
370 } else if (await frame) |_| unreachable else |err| return err;
367371 }
368372
369373 async fn createAsync(
......@@ -389,50 +393,13 @@ pub const Compilation = struct {
389393 .build_mode = build_mode,
390394 .zig_lib_dir = zig_lib_dir,
391395 .zig_std_dir = undefined,
392 .tmp_dir = event.Future(BuildError![]u8).init(),
393 // .destroy_frame = @frame(),
394 // .main_loop_frame = undefined,
395 .main_loop_future = event.Future(void).init(),
396 .destroy_frame = @frame(),
397 .main_loop_frame = undefined,
396398
397399 .name = undefined,
398400 .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,
417401 .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,
427402 .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,
436403 .exported_symbol_names = event.Locked(Decl.Table).init(Decl.Table.init(allocator)),
437404 .prelink_group = event.Group(BuildError!void).init(allocator),
438405 .deinit_group = event.Group(void).init(allocator),
......@@ -462,11 +429,9 @@ pub const Compilation = struct {
462429 .root_package = undefined,
463430 .std_package = undefined,
464431
465 .override_libc = null,
466 .have_err_ret_tracing = false,
467432 .primitive_type_table = undefined,
468433
469 // .fs_watch = undefined,
434 .fs_watch = undefined,
470435 };
471436 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());
472437 comp.primitive_type_table = TypeTable.init(comp.arena());
......@@ -538,13 +503,16 @@ pub const Compilation = struct {
538503 comp.root_package = try Package.create(comp.arena(), ".", "");
539504 }
540505
541 // comp.fs_watch = try fs.Watch(*Scope.Root).create(16);
542 // defer comp.fs_watch.destroy();
506 comp.fs_watch = try fs.Watch(*Scope.Root).init(allocator, 16);
507 defer comp.fs_watch.deinit();
543508
544509 try comp.initTypes();
545510 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();
548516 // Set this to indicate that initialization completed successfully.
549517 // from here on out we must not return an error.
550518 // This must occur before the first suspend/await.
......@@ -563,7 +531,7 @@ pub const Compilation = struct {
563531 }
564532
565533 /// 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 {
567535 if (name.len >= 2) {
568536 switch (name[0]) {
569537 'i', 'u' => blk: {
......@@ -757,8 +725,11 @@ pub const Compilation = struct {
757725 }
758726
759727 pub fn destroy(self: *Compilation) void {
760 // await self.main_loop_frame;
761 // resume self.destroy_frame;
728 const allocator = self.gpa();
729 self.cancelled = true;
730 await self.main_loop_frame;
731 resume self.destroy_frame;
732 allocator.destroy(self.destroy_frame);
762733 }
763734
764735 fn start(self: *Compilation) void {
......@@ -771,7 +742,7 @@ pub const Compilation = struct {
771742
772743 var build_result = self.initialCompile();
773744
774 while (true) {
745 while (!self.cancelled) {
775746 const link_result = if (build_result) blk: {
776747 break :blk self.maybeLink();
777748 } else |err| err;
......@@ -799,47 +770,47 @@ pub const Compilation = struct {
799770 self.events.put(Event{ .Error = err });
800771 }
801772
802 // // First, get an item from the watch channel, waiting on the channel.
803 // var group = event.Group(BuildError!void).init(self.gpa());
804 // {
805 // const ev = (self.fs_watch.channel.get()) catch |err| {
806 // build_result = err;
807 // continue;
808 // };
809 // const root_scope = ev.data;
810 // group.call(rebuildFile, self, root_scope) catch |err| {
811 // build_result = err;
812 // continue;
813 // };
814 // }
815 // // Next, get all the items from the channel that are buffered up.
816 // while (self.fs_watch.channel.getOrNull()) |ev_or_err| {
817 // if (ev_or_err) |ev| {
818 // const root_scope = ev.data;
819 // group.call(rebuildFile, self, root_scope) catch |err| {
820 // build_result = err;
821 // continue;
822 // };
823 // } else |err| {
824 // build_result = err;
825 // continue;
826 // }
827 // }
828 // build_result = group.wait();
773 // First, get an item from the watch channel, waiting on the channel.
774 var group = event.Group(BuildError!void).init(self.gpa());
775 {
776 const ev = (self.fs_watch.channel.get()) catch |err| {
777 build_result = err;
778 continue;
779 };
780 const root_scope = ev.data;
781 group.call(rebuildFile, self, root_scope) catch |err| {
782 build_result = err;
783 continue;
784 };
785 }
786 // Next, get all the items from the channel that are buffered up.
787 while (self.fs_watch.channel.getOrNull()) |ev_or_err| {
788 if (ev_or_err) |ev| {
789 const root_scope = ev.data;
790 group.call(rebuildFile, self, root_scope) catch |err| {
791 build_result = err;
792 continue;
793 };
794 } else |err| {
795 build_result = err;
796 continue;
797 }
798 }
799 build_result = group.wait();
829800 }
830801 }
831802
832 async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) !void {
803 async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) BuildError!void {
833804 const tree_scope = blk: {
834 const source_code = "";
835 // const source_code = fs.readFile(
836 // root_scope.realpath,
837 // max_src_size,
838 // ) catch |err| {
839 // try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err));
840 // return;
841 // };
842 // errdefer self.gpa().free(source_code);
805 const source_code = fs.readFile(
806 self.gpa(),
807 root_scope.realpath,
808 max_src_size,
809 ) catch |err| {
810 try self.addCompileErrorCli(root_scope.realpath, "unable to open: {}", @errorName(err));
811 return;
812 };
813 errdefer self.gpa().free(source_code);
843814
844815 const tree = try std.zig.parse(self.gpa(), source_code);
845816 errdefer {
......@@ -877,7 +848,7 @@ pub const Compilation = struct {
877848 try decl_group.wait();
878849 }
879850
880 async fn rebuildChangedDecls(
851 fn rebuildChangedDecls(
881852 self: *Compilation,
882853 group: *event.Group(BuildError!void),
883854 locked_table: *Decl.Table,
......@@ -966,7 +937,7 @@ pub const Compilation = struct {
966937 }
967938 }
968939
969 async fn initialCompile(self: *Compilation) !void {
940 fn initialCompile(self: *Compilation) !void {
970941 if (self.root_src_path) |root_src_path| {
971942 const root_scope = blk: {
972943 // TODO async/await std.fs.realpath
......@@ -985,7 +956,7 @@ pub const Compilation = struct {
985956 }
986957 }
987958
988 async fn maybeLink(self: *Compilation) !void {
959 fn maybeLink(self: *Compilation) !void {
989960 (self.prelink_group.wait()) catch |err| switch (err) {
990961 error.SemanticAnalysisFailed => {},
991962 else => return err,
......@@ -1169,11 +1140,10 @@ pub const Compilation = struct {
11691140 return link_lib;
11701141 }
11711142
1172 /// cancels itself so no need to await or cancel the promise.
11731143 async fn startFindingNativeLibC(self: *Compilation) void {
1174 std.event.Loop.instance.?.yield();
1144 event.Loop.startCpuBoundOperation();
11751145 // 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;
11771147 }
11781148
11791149 /// General Purpose Allocator. Must free when done.
......@@ -1188,7 +1158,7 @@ pub const Compilation = struct {
11881158
11891159 /// If the temporary directory for this compilation has not been created, it creates it.
11901160 /// 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 {
11921162 const tmp_dir = try self.getTmpDir();
11931163 const file_prefix = self.getRandomFileName();
11941164
......@@ -1204,14 +1174,14 @@ pub const Compilation = struct {
12041174 /// If the temporary directory for this Compilation has not been created, creates it.
12051175 /// Then returns it. The directory is unique to this Compilation and cleaned up when
12061176 /// the Compilation deinitializes.
1207 async fn getTmpDir(self: *Compilation) ![]const u8 {
1177 fn getTmpDir(self: *Compilation) ![]const u8 {
12081178 if (self.tmp_dir.start()) |ptr| return ptr.*;
12091179 self.tmp_dir.data = self.getTmpDirImpl();
12101180 self.tmp_dir.resolve();
12111181 return self.tmp_dir.data;
12121182 }
12131183
1214 async fn getTmpDirImpl(self: *Compilation) ![]u8 {
1184 fn getTmpDirImpl(self: *Compilation) ![]u8 {
12151185 const comp_dir_name = self.getRandomFileName();
12161186 const zig_dir_path = try getZigDir(self.gpa());
12171187 defer self.gpa().free(zig_dir_path);
......@@ -1221,7 +1191,7 @@ pub const Compilation = struct {
12211191 return tmp_dir;
12221192 }
12231193
1224 async fn getRandomFileName(self: *Compilation) [12]u8 {
1194 fn getRandomFileName(self: *Compilation) [12]u8 {
12251195 // here we replace the standard +/ with -_ so that it can be used in a file name
12261196 const b64_fs_encoder = std.base64.Base64Encoder.init(
12271197 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
......@@ -1247,20 +1217,23 @@ pub const Compilation = struct {
12471217 }
12481218
12491219 /// Returns a value which has been ref()'d once
1250 async fn analyzeConstValue(
1220 fn analyzeConstValue(
12511221 comp: *Compilation,
12521222 tree_scope: *Scope.AstTree,
12531223 scope: *Scope,
12541224 node: *ast.Node,
12551225 expected_type: *Type,
12561226 ) !*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;
12581231 defer analyzed_code.destroy(comp.gpa());
12591232
12601233 return analyzed_code.getCompTimeResult(comp);
12611234 }
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 {
12641237 const meta_type = &Type.MetaType.get(comp).base;
12651238 defer meta_type.base.deref(comp);
12661239
......@@ -1291,7 +1264,7 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib
12911264}
12921265
12931266/// The function that actually does the generation.
1294async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
1267fn generateDecl(comp: *Compilation, decl: *Decl) !void {
12951268 switch (decl.id) {
12961269 .Var => @panic("TODO"),
12971270 .Fn => {
......@@ -1302,7 +1275,7 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
13021275 }
13031276}
13041277
1305async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1278fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
13061279 const tree_scope = fn_decl.base.tree_scope;
13071280
13081281 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 {
13191292
13201293 // The Decl.Fn owns the initial 1 reference count
13211294 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 };
13231296 symbol_name_consumed = true;
13241297
13251298 // Define local parameter variables
......@@ -1354,12 +1327,15 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
13541327 try fn_type.non_key.Normal.variable_list.append(var_scope);
13551328 }
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(
13581333 tree_scope,
13591334 fn_val.child_scope,
13601335 body_node,
13611336 fn_type.key.data.Normal.return_type,
13621337 );
1338 const analyzed_code = try await frame;
13631339 errdefer analyzed_code.destroy(comp.gpa());
13641340
13651341 assert(fn_val.block_scope != null);
......@@ -1386,7 +1362,7 @@ fn getZigDir(allocator: *mem.Allocator) ![]u8 {
13861362 return std.fs.getAppDataDir(allocator, "zig");
13871363}
13881364
1389async fn analyzeFnType(
1365fn analyzeFnType(
13901366 comp: *Compilation,
13911367 tree_scope: *Scope.AstTree,
13921368 scope: *Scope,
......@@ -1448,7 +1424,7 @@ async fn analyzeFnType(
14481424 return fn_type;
14491425}
14501426
1451async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1427fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
14521428 const fn_type = try analyzeFnType(
14531429 comp,
14541430 fn_decl.base.tree_scope,
......@@ -1463,6 +1439,6 @@ async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
14631439
14641440 // The Decl.Fn owns the initial 1 reference count
14651441 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 };
14671443 symbol_name_consumed = true;
14681444}
src-self-hosted/decl.zig+3-6
......@@ -69,15 +69,12 @@ pub const Decl = struct {
6969
7070 pub const Fn = struct {
7171 base: Decl,
72 value: Val,
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) {
72 value: union(enum) {
7773 Unresolved,
7874 Fn: *Value.Fn,
7975 FnProto: *Value.FnProto,
80 };
76 },
77 fn_proto: *ast.Node.FnProto,
8178
8279 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {
8380 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 {
110110 unreachable;
111111 }
112112
113 pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
113 pub fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
114114 switch (base.id) {
115115 .Return => return @fieldParentPtr(Return, "base", base).analyze(ira),
116116 .Const => return @fieldParentPtr(Const, "base", base).analyze(ira),
......@@ -422,7 +422,7 @@ pub const Inst = struct {
422422 return false;
423423 }
424424
425 pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
425 pub fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
426426 const target = try self.params.target.getAsParam();
427427
428428 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
......@@ -472,7 +472,7 @@ pub const Inst = struct {
472472 return false;
473473 }
474474
475 pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {
475 pub fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {
476476 (ira.irb.comp.resolveDecl(self.params.decl)) catch |err| switch (err) {
477477 error.OutOfMemory => return error.OutOfMemory,
478478 else => return error.SemanticAnalysisFailed,
......@@ -516,7 +516,7 @@ pub const Inst = struct {
516516 return false;
517517 }
518518
519 pub async fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst {
519 pub fn analyze(self: *const VarPtr, ira: *Analyze) !*Inst {
520520 switch (self.params.var_scope.data) {
521521 .Const => @panic("TODO"),
522522 .Param => |param| {
......@@ -563,7 +563,7 @@ pub const Inst = struct {
563563 return false;
564564 }
565565
566 pub async fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst {
566 pub fn analyze(self: *const LoadPtr, ira: *Analyze) !*Inst {
567567 const target = try self.params.target.getAsParam();
568568 const target_type = target.getKnownType();
569569 if (target_type.id != .Pointer) {
......@@ -645,7 +645,7 @@ pub const Inst = struct {
645645 return false;
646646 }
647647
648 pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {
648 pub fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {
649649 const child_type = try self.params.child_type.getAsConstType(ira);
650650 // if (child_type->id == TypeTableEntryIdUnreachable) {
651651 // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
......@@ -658,7 +658,7 @@ pub const Inst = struct {
658658 const amt = try align_inst.getAsConstAlign(ira);
659659 break :blk Type.Pointer.Align{ .Override = amt };
660660 } else blk: {
661 break :blk Type.Pointer.Align{ .Abi = {} };
661 break :blk .Abi;
662662 };
663663 const ptr_type = try Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
664664 .child_type = child_type,
......@@ -927,7 +927,7 @@ pub const Variable = struct {
927927
928928pub const BasicBlock = struct {
929929 ref_count: usize,
930 name_hint: [*]const u8, // must be a C string literal
930 name_hint: [*:0]const u8,
931931 debug_id: usize,
932932 scope: *Scope,
933933 instruction_list: std.ArrayList(*Inst),
......@@ -1051,7 +1051,7 @@ pub const Builder = struct {
10511051 }
10521052
10531053 /// 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 {
10551055 const basic_block = try self.arena().create(BasicBlock);
10561056 basic_block.* = BasicBlock{
10571057 .ref_count = 0,
......@@ -1078,6 +1078,14 @@ pub const Builder = struct {
10781078 self.current_basic_block = basic_block;
10791079 }
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
10811089 pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
10821090 switch (node.id) {
10831091 .Root => unreachable,
......@@ -1157,7 +1165,7 @@ pub const Builder = struct {
11571165 },
11581166 .GroupedExpression => {
11591167 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);
11611169 },
11621170 .BuiltinCall => return error.Unimplemented,
11631171 .ErrorSetDecl => return error.Unimplemented,
......@@ -1186,14 +1194,14 @@ pub const Builder = struct {
11861194 }
11871195 }
11881196
1189 async 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);
1197 fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
1198 const fn_ref = try irb.genNodeRecursive(suffix_op.lhs.node, scope, .None);
11911199
11921200 const args = try irb.arena().alloc(*Inst, call.params.len);
11931201 var it = call.params.iterator(0);
11941202 var i: usize = 0;
11951203 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);
11971205 }
11981206
11991207 //bool is_async = node->data.fn_call_expr.is_async;
......@@ -1214,7 +1222,7 @@ pub const Builder = struct {
12141222 //return ir_lval_wrap(irb, scope, fn_call, lval);
12151223 }
12161224
1217 async fn genPtrType(
1225 fn genPtrType(
12181226 irb: *Builder,
12191227 prefix_op: *ast.Node.PrefixOp,
12201228 ptr_info: ast.Node.PrefixOp.PtrInfo,
......@@ -1238,7 +1246,7 @@ pub const Builder = struct {
12381246 //} else {
12391247 // align_value = nullptr;
12401248 //}
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
12431251 //uint32_t bit_offset_start = 0;
12441252 //if (node->data.pointer_type.bit_offset_start != nullptr) {
......@@ -1307,9 +1315,9 @@ pub const Builder = struct {
13071315 var rest: []const u8 = undefined;
13081316 if (int_token.len >= 3 and int_token[0] == '0') {
13091317 base = switch (int_token[1]) {
1310 'b' => u8(2),
1311 'o' => u8(8),
1312 'x' => u8(16),
1318 'b' => 2,
1319 'o' => 8,
1320 'x' => 16,
13131321 else => unreachable,
13141322 };
13151323 rest = int_token[2..];
......@@ -1339,7 +1347,7 @@ pub const Builder = struct {
13391347 return inst;
13401348 }
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 {
13431351 const str_token = irb.code.tree_scope.tree.tokenSlice(str_lit.token);
13441352 const src_span = Span.token(str_lit.token);
13451353
......@@ -1389,7 +1397,7 @@ pub const Builder = struct {
13891397 }
13901398 }
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 {
13931401 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
13941402
13951403 const outer_block_scope = &block_scope.base;
......@@ -1437,7 +1445,7 @@ pub const Builder = struct {
14371445 child_scope = &defer_child_scope.base;
14381446 continue;
14391447 }
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
14421450 is_continuation_unreachable = statement_value.isNoReturn();
14431451 if (is_continuation_unreachable) {
......@@ -1499,7 +1507,7 @@ pub const Builder = struct {
14991507 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);
15001508 }
15011509
1502 pub async fn genControlFlowExpr(
1510 pub fn genControlFlowExpr(
15031511 irb: *Builder,
15041512 control_flow_expr: *ast.Node.ControlFlowExpression,
15051513 scope: *Scope,
......@@ -1533,7 +1541,7 @@ pub const Builder = struct {
15331541
15341542 const outer_scope = irb.begin_scope.?;
15351543 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);
15371545 } else blk: {
15381546 break :blk try irb.buildConstVoid(scope, src_span, true);
15391547 };
......@@ -1596,7 +1604,7 @@ pub const Builder = struct {
15961604 }
15971605 }
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 {
16001608 const src_span = Span.token(identifier.token);
16011609 const name = irb.code.tree_scope.tree.tokenSlice(identifier.token);
16021610
......@@ -1694,7 +1702,7 @@ pub const Builder = struct {
16941702 return result;
16951703 }
16961704
1697 async fn genDefersForBlock(
1705 fn genDefersForBlock(
16981706 irb: *Builder,
16991707 inner_scope: *Scope,
17001708 outer_scope: *Scope,
......@@ -1712,7 +1720,7 @@ pub const Builder = struct {
17121720 };
17131721 if (generate) {
17141722 const defer_expr_scope = defer_scope.defer_expr_scope;
1715 const instruction = try irb.genNode(
1723 const instruction = try irb.genNodeRecursive(
17161724 defer_expr_scope.expr_node,
17171725 &defer_expr_scope.base,
17181726 .None,
......@@ -1797,7 +1805,7 @@ pub const Builder = struct {
17971805 // Look at the params and ref() other instructions
17981806 comptime var i = 0;
17991807 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)));
18011809 switch (FieldType) {
18021810 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
18031811 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),
......@@ -1909,7 +1917,7 @@ pub const Builder = struct {
19091917 VarScope: *Scope.Var,
19101918 };
19111919
1912 async fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident {
1920 fn findIdent(irb: *Builder, scope: *Scope, name: []const u8) Ident {
19131921 var s = scope;
19141922 while (true) {
19151923 switch (s.id) {
......@@ -2519,7 +2527,7 @@ const Analyze = struct {
25192527 }
25202528};
25212529
2522pub async fn gen(
2530pub fn gen(
25232531 comp: *Compilation,
25242532 body_node: *ast.Node,
25252533 tree_scope: *Scope.AstTree,
......@@ -2541,7 +2549,7 @@ pub async fn gen(
25412549 return irb.finish();
25422550}
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 {
25452553 const old_entry_bb = old_code.basic_block_list.at(0);
25462554
25472555 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 {
143143 }
144144
145145 /// Finds the default, native libc.
146 pub async fn findNative(self: *LibCInstallation, allocator: *Allocator) !void {
146 pub fn findNative(self: *LibCInstallation, allocator: *Allocator) !void {
147147 self.initEmpty();
148148 var group = event.Group(FindError!void).init(allocator);
149149 errdefer group.wait() catch {};
......@@ -393,14 +393,14 @@ pub const LibCInstallation = struct {
393393};
394394
395395/// 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 {
397397 const cc_exe = std.os.getenv("CC") orelse "cc";
398398 const arg1 = try std.fmt.allocPrint(allocator, "-print-file-name={}", o_file);
399399 defer allocator.free(arg1);
400400 const argv = [_][]const u8{ cc_exe, arg1 };
401401
402402 // TODO This simulates evented I/O for the child process exec
403 std.event.Loop.instance.?.yield();
403 event.Loop.startCpuBoundOperation();
404404 const errorable_result = std.ChildProcess.exec(allocator, &argv, null, null, 1024 * 1024);
405405 const exec_result = if (std.debug.runtime_safety) blk: {
406406 break :blk errorable_result catch unreachable;
src-self-hosted/link.zig+33-35
......@@ -11,7 +11,7 @@ const util = @import("util.zig");
1111const Context = struct {
1212 comp: *Compilation,
1313 arena: std.heap.ArenaAllocator,
14 args: std.ArrayList([*]const u8),
14 args: std.ArrayList([*:0]const u8),
1515 link_in_crt: bool,
1616
1717 link_err: error{OutOfMemory}!void,
......@@ -21,7 +21,7 @@ const Context = struct {
2121 out_file_path: std.Buffer,
2222};
2323
24pub async fn link(comp: *Compilation) !void {
24pub fn link(comp: *Compilation) !void {
2525 var ctx = Context{
2626 .comp = comp,
2727 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
......@@ -33,7 +33,7 @@ pub async fn link(comp: *Compilation) !void {
3333 .out_file_path = undefined,
3434 };
3535 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);
3737 ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);
3838
3939 if (comp.link_out_file) |out_file| {
......@@ -58,7 +58,8 @@ pub async fn link(comp: *Compilation) !void {
5858 try ctx.args.append("lld");
5959
6060 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: {
6263 switch (comp.target) {
6364 Target.Native => {
6465 break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound;
......@@ -66,6 +67,7 @@ pub async fn link(comp: *Compilation) !void {
6667 else => return error.LibCRequiredButNotProvidedOrFound,
6768 }
6869 };
70 ctx.libc = libc;
6971 }
7072
7173 try constructLinkerArgs(&ctx);
......@@ -171,7 +173,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
171173 //}
172174
173175 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
176178 if (ctx.link_in_crt) {
177179 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
......@@ -214,10 +216,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
214216
215217 if (ctx.comp.haveLibC()) {
216218 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
219222 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
222225 if (!ctx.comp.is_static) {
223226 const dl = blk: {
......@@ -226,7 +229,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
226229 return error.LibCMissingDynamicLinker;
227230 };
228231 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));
230233 }
231234 }
232235
......@@ -238,7 +241,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
238241 // .o files
239242 for (ctx.comp.link_objects) |link_object| {
240243 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));
242245 }
243246 try addFnObjects(ctx);
244247
......@@ -313,7 +316,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
313316fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
314317 const full_path = try std.fs.path.join(&ctx.arena.allocator, [_][]const u8{ dirname, basename });
315318 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));
317320}
318321
319322fn constructLinkerArgsCoff(ctx: *Context) !void {
......@@ -339,12 +342,12 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
339342 const is_library = ctx.comp.kind == .Lib;
340343
341344 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
344347 if (ctx.comp.haveLibC()) {
345 try ctx.args.append((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);
347 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.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));
349 try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_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));
348351 }
349352
350353 if (ctx.link_in_crt) {
......@@ -353,17 +356,17 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
353356
354357 if (ctx.comp.is_static) {
355358 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));
357360 } else {
358361 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));
360363 }
361364
362365 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
365368 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
368371 // Visual C++ 2015 Conformance Changes
369372 // https://msdn.microsoft.com/en-us/library/bb531344.aspx
......@@ -395,7 +398,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void {
395398
396399 for (ctx.comp.link_objects) |link_object| {
397400 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));
399402 }
400403 try addFnObjects(ctx);
401404
......@@ -504,11 +507,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
504507 //}
505508
506509 try ctx.args.append("-arch");
507 const darwin_arch_str = try std.cstr.addNullByte(
508 &ctx.arena.allocator,
509 ctx.comp.target.getDarwinArchString(),
510 );
511 try ctx.args.append(darwin_arch_str.ptr);
510 try ctx.args.append(util.getDarwinArchString(ctx.comp.target));
512511
513512 const platform = try DarwinPlatform.get(ctx.comp);
514513 switch (platform.kind) {
......@@ -517,7 +516,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
517516 .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"),
518517 }
519518 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
522521 if (ctx.comp.kind == .Exe) {
523522 if (ctx.comp.is_static) {
......@@ -528,7 +527,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
528527 }
529528
530529 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
533532 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {
534533 // Buf *rpath = g->rpath_list.at(i);
......@@ -572,7 +571,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
572571
573572 for (ctx.comp.link_objects) |link_object| {
574573 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));
576575 }
577576 try addFnObjects(ctx);
578577
......@@ -593,10 +592,10 @@ fn constructLinkerArgsMachO(ctx: *Context) !void {
593592 } else {
594593 if (mem.indexOfScalar(u8, lib.name, '/') == null) {
595594 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));
597596 } else {
598597 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));
600599 }
601600 }
602601 }
......@@ -626,20 +625,19 @@ fn constructLinkerArgsWasm(ctx: *Context) void {
626625}
627626
628627fn addFnObjects(ctx: *Context) !void {
629 // at this point it's guaranteed nobody else has this lock, so we circumvent it
630 // and avoid having to be an async function
631 const fn_link_set = &ctx.comp.fn_link_set.private_data;
628 const held = ctx.comp.fn_link_set.acquire();
629 defer held.release();
632630
633 var it = fn_link_set.first;
631 var it = held.value.first;
634632 while (it) |node| {
635633 const fn_val = node.data orelse {
636634 // handle the tombstone. See Value.Fn.destroy.
637635 it = node.next;
638 fn_link_set.remove(node);
636 held.value.remove(node);
639637 ctx.comp.gpa().destroy(node);
640638 continue;
641639 };
642 try ctx.args.append(fn_val.containing_object.ptr());
640 try ctx.args.append(fn_val.containing_object.toSliceConst());
643641 it = node.next;
644642 }
645643}
src-self-hosted/llvm.zig+1-1
......@@ -86,7 +86,7 @@ pub const AddGlobal = LLVMAddGlobal;
8686extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value;
8787
8888pub 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
9191pub const ConstInt = LLVMConstInt;
9292extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value;
src-self-hosted/main.zig+64-73
......@@ -49,14 +49,15 @@ const usage =
4949
5050const Command = struct {
5151 name: []const u8,
52 exec: fn (*Allocator, []const []const u8) anyerror!void,
52 exec: async fn (*Allocator, []const []const u8) anyerror!void,
5353};
5454
5555pub fn main() !void {
5656 // This allocator needs to be thread-safe because we use it for the event.Loop
5757 // which multiplexes async functions onto kernel threads.
5858 // 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
6162 stdout = &std.io.getStdOut().outStream().stream;
6263
......@@ -118,14 +119,18 @@ pub fn main() !void {
118119 },
119120 };
120121
121 for (commands) |command| {
122 inline for (commands) |command| {
122123 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;
124128 }
125129 }
126130
127131 try stderr.print("unknown command: {}\n\n", args[1]);
128132 try stderr.write(usage);
133 process.argsFree(allocator, args);
129134 process.exit(1);
130135}
131136
......@@ -461,13 +466,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
461466 comp.link_objects = link_objects;
462467
463468 comp.start();
464 const frame = async processBuildEvents(comp, color);
469 processBuildEvents(comp, color);
465470}
466471
467async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
472fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
468473 var count: usize = 0;
469 while (true) {
470 // TODO directly awaiting async should guarantee memory allocation elision
474 while (!comp.cancelled) {
471475 const build_event = comp.events.get();
472476 count += 1;
473477
......@@ -545,7 +549,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil
545549 "Try running `zig libc` to see an example for the native target.\n",
546550 libc_paths_file,
547551 @errorName(err),
548 ) catch process.exit(1);
552 ) catch {};
549553 process.exit(1);
550554 };
551555}
......@@ -567,12 +571,8 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
567571 var zig_compiler = try ZigCompiler.init(allocator);
568572 defer zig_compiler.deinit();
569573
570 const frame = async findLibCAsync(&zig_compiler);
571}
572
573async fn findLibCAsync(zig_compiler: *ZigCompiler) void {
574574 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 {};
576576 process.exit(1);
577577 };
578578 libc.render(stdout) catch process.exit(1);
......@@ -644,11 +644,23 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
644644 process.exit(1);
645645 }
646646
647 return asyncFmtMain(
648 allocator,
649 &flags,
650 color,
651 );
647 var fmt = Fmt{
648 .allocator = allocator,
649 .seen = event.Locked(Fmt.SeenMap).init(Fmt.SeenMap.init(allocator)),
650 .any_error = false,
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 }
652664}
653665
654666const FmtError = error{
......@@ -673,30 +685,6 @@ const FmtError = error{
673685 CurrentWorkingDirectoryUnlinked,
674686} || 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
700688async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void {
701689 const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref);
702690 defer fmt.allocator.free(file_path);
......@@ -708,33 +696,34 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro
708696 if (try held.value.put(file_path, {})) |_| return;
709697 }
710698
711 const source_code = "";
712 // const source_code = event.fs.readFile(
713 // file_path,
714 // max_src_size,
715 // ) catch |err| switch (err) {
716 // error.IsDir, error.AccessDenied => {
717 // // TODO make event based (and dir.next())
718 // var dir = try fs.Dir.cwd().openDirList(file_path);
719 // defer dir.close();
720
721 // var group = event.Group(FmtError!void).init(fmt.allocator);
722 // while (try dir.next()) |entry| {
723 // if (entry.kind == fs.Dir.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 });
725 // try group.call(fmtPath, fmt, full_path, check_mode);
726 // }
727 // }
728 // return group.wait();
729 // },
730 // else => {
731 // // TODO lock stderr printing
732 // try stderr.print("unable to open '{}': {}\n", file_path, err);
733 // fmt.any_error = true;
734 // return;
735 // },
736 // };
737 // defer fmt.allocator.free(source_code);
699 const source_code = event.fs.readFile(
700 fmt.allocator,
701 file_path,
702 max_src_size,
703 ) catch |err| switch (err) {
704 error.IsDir, error.AccessDenied => {
705 var dir = try fs.cwd().openDirList(file_path);
706 defer dir.close();
707
708 var group = event.Group(FmtError!void).init(fmt.allocator);
709 var it = dir.iterate();
710 while (try it.next()) |entry| {
711 if (entry.kind == .Directory or mem.endsWith(u8, entry.name, ".zig")) {
712 const full_path = try fs.path.join(fmt.allocator, [_][]const u8{ file_path, entry.name });
713 @panic("TODO https://github.com/ziglang/zig/issues/3777");
714 // try group.call(fmtPath, fmt, full_path, check_mode);
715 }
716 }
717 return group.wait();
718 },
719 else => {
720 // TODO lock stderr printing
721 try stderr.print("unable to open '{}': {}\n", file_path, err);
722 fmt.any_error = true;
723 return;
724 },
725 };
726 defer fmt.allocator.free(source_code);
738727
739728 const tree = std.zig.parse(fmt.allocator, source_code) catch |err| {
740729 try stderr.print("error parsing file '{}': {}\n", file_path, err);
......@@ -867,10 +856,12 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void {
867856 .exec = cmdInternalBuildInfo,
868857 }};
869858
870 for (sub_commands) |sub_command| {
859 inline for (sub_commands) |sub_command| {
871860 if (mem.eql(u8, sub_command.name, args[0])) {
872 try sub_command.exec(allocator, args[1..]);
873 return;
861 var frame = try allocator.create(@Frame(sub_command.exec));
862 defer allocator.destroy(frame);
863 frame.* = async sub_command.exec(allocator, args[1..]);
864 return await frame;
874865 }
875866 }
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
279279 const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) {
280280 error.IsDir, error.AccessDenied => {
281281 // 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);
283283 defer dir.close();
284284
285285 var dir_it = dir.iterate();
......@@ -427,11 +427,11 @@ export fn stage2_DepTokenizer_next(self: *stage2_DepTokenizer) stage2_DepNextRes
427427 };
428428}
429429
430export const stage2_DepTokenizer = extern struct {
430const stage2_DepTokenizer = extern struct {
431431 handle: *DepTokenizer,
432432};
433433
434export const stage2_DepNextResult = extern struct {
434const stage2_DepNextResult = extern struct {
435435 type_id: TypeId,
436436
437437 // when type_id == error --> error text
......@@ -440,7 +440,7 @@ export const stage2_DepNextResult = extern struct {
440440 // when type_id == prereq --> prereq pathname
441441 textz: [*]const u8,
442442
443 export const TypeId = extern enum {
443 const TypeId = extern enum {
444444 error_,
445445 null_,
446446 target,
src-self-hosted/test.zig+11-13
......@@ -26,7 +26,8 @@ test "stage2" {
2626}
2727
2828const 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
3132pub const TestContext = struct {
3233 zig_compiler: ZigCompiler,
......@@ -94,8 +95,8 @@ pub const TestContext = struct {
9495 &self.zig_compiler,
9596 "test",
9697 file1_path,
97 Target.Native,
98 Compilation.Kind.Obj,
98 .Native,
99 .Obj,
99100 .Debug,
100101 true, // is_static
101102 self.zig_lib_dir,
......@@ -116,7 +117,7 @@ pub const TestContext = struct {
116117 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
117118 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());
120121 if (std.fs.path.dirname(file1_path)) |dirname| {
121122 try std.fs.makePath(allocator, dirname);
122123 }
......@@ -128,8 +129,8 @@ pub const TestContext = struct {
128129 &self.zig_compiler,
129130 "test",
130131 file1_path,
131 Target.Native,
132 Compilation.Kind.Exe,
132 .Native,
133 .Exe,
133134 .Debug,
134135 false,
135136 self.zig_lib_dir,
......@@ -148,15 +149,12 @@ pub const TestContext = struct {
148149 exe_file: []const u8,
149150 expected_output: []const u8,
150151 ) anyerror!void {
151 // TODO this should not be necessary
152 const exe_file_2 = try std.mem.dupe(allocator, u8, exe_file);
153
154152 defer comp.destroy();
155153 const build_event = comp.events.get();
156154
157155 switch (build_event) {
158156 .Ok => {
159 const argv = [_][]const u8{exe_file_2};
157 const argv = [_][]const u8{exe_file};
160158 // TODO use event loop
161159 const child = try std.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
162160 switch (child.term) {
......@@ -173,13 +171,13 @@ pub const TestContext = struct {
173171 return error.OutputMismatch;
174172 }
175173 },
176 Compilation.Event.Error => |err| return err,
177 Compilation.Event.Fail => |msgs| {
174 .Error => @panic("Cannot return error: https://github.com/ziglang/zig/issues/3190"), // |err| return err,
175 .Fail => |msgs| {
178176 const stderr = std.io.getStdErr();
179177 try stderr.write("build incorrectly failed:\n");
180178 for (msgs) |msg| {
181179 defer msg.destroy();
182 try msg.printToFile(stderr, errmsg.Color.Auto);
180 try msg.printToFile(stderr, .Auto);
183181 }
184182 },
185183 }
src-self-hosted/type.zig+14-12
......@@ -53,7 +53,7 @@ pub const Type = struct {
5353 base: *Type,
5454 allocator: *Allocator,
5555 llvm_context: *llvm.Context,
56 ) (error{OutOfMemory}!*llvm.Type) {
56 ) error{OutOfMemory}!*llvm.Type {
5757 switch (base.id) {
5858 .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
5959 .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
......@@ -184,7 +184,7 @@ pub const Type = struct {
184184
185185 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
186186 /// 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 {
188188 if (base.abi_alignment.start()) |ptr| return ptr.*;
189189
190190 {
......@@ -200,7 +200,7 @@ pub const Type = struct {
200200 }
201201
202202 /// 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 {
204204 if (base.abi_alignment.start()) |ptr| return ptr.*;
205205
206206 base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context);
......@@ -209,7 +209,7 @@ pub const Type = struct {
209209 }
210210
211211 /// 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 {
213213 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
214214 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
215215 }
......@@ -367,7 +367,7 @@ pub const Type = struct {
367367 }
368368
369369 /// 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 {
371371 {
372372 const held = comp.fn_type_table.acquire();
373373 defer held.release();
......@@ -564,7 +564,7 @@ pub const Type = struct {
564564 return comp.u8_type;
565565 }
566566
567 pub async fn get(comp: *Compilation, key: Key) !*Int {
567 pub fn get(comp: *Compilation, key: Key) !*Int {
568568 {
569569 const held = comp.int_type_table.acquire();
570570 defer held.release();
......@@ -606,7 +606,7 @@ pub const Type = struct {
606606 comp.registerGarbage(Int, &self.garbage_node);
607607 }
608608
609 pub async fn gcDestroy(self: *Int, comp: *Compilation) void {
609 pub fn gcDestroy(self: *Int, comp: *Compilation) void {
610610 {
611611 const held = comp.int_type_table.acquire();
612612 defer held.release();
......@@ -700,7 +700,7 @@ pub const Type = struct {
700700 comp.registerGarbage(Pointer, &self.garbage_node);
701701 }
702702
703 pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void {
703 pub fn gcDestroy(self: *Pointer, comp: *Compilation) void {
704704 {
705705 const held = comp.ptr_type_table.acquire();
706706 defer held.release();
......@@ -711,14 +711,14 @@ pub const Type = struct {
711711 comp.gpa().destroy(self);
712712 }
713713
714 pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
714 pub fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
715715 switch (self.key.alignment) {
716716 .Abi => return self.key.child_type.getAbiAlignment(comp),
717717 .Override => |alignment| return alignment,
718718 }
719719 }
720720
721 pub async fn get(
721 pub fn get(
722722 comp: *Compilation,
723723 key: Key,
724724 ) !*Pointer {
......@@ -726,8 +726,10 @@ pub const Type = struct {
726726 switch (key.alignment) {
727727 .Abi => {},
728728 .Override => |alignment| {
729 // TODO https://github.com/ziglang/zig/issues/3190
730 var align_spill = alignment;
729731 const abi_align = try key.child_type.getAbiAlignment(comp);
730 if (abi_align == alignment) {
732 if (abi_align == align_spill) {
731733 normal_key.alignment = .Abi;
732734 }
733735 },
......@@ -828,7 +830,7 @@ pub const Type = struct {
828830 comp.gpa().destroy(self);
829831 }
830832
831 pub async fn get(comp: *Compilation, key: Key) !*Array {
833 pub fn get(comp: *Compilation, key: Key) !*Array {
832834 key.elem_type.base.ref();
833835 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 {
3232 };
3333}
3434
35pub fn getObjectFormat(self: Target) Target.ObjectFormat {
36 return switch (self) {
37 .Native => @import("builtin").object_format,
38 .Cross => {
35pub fn getObjectFormat(target: Target) Target.ObjectFormat {
36 switch (target) {
37 .Native => return @import("builtin").object_format,
38 .Cross => blk: {
3939 if (target.isWindows() or target.isUefi()) {
40 break .coff;
40 return .coff;
4141 } else if (target.isDarwin()) {
42 break .macho;
42 return .macho;
4343 }
4444 if (target.isWasm()) {
45 break .wasm;
45 return .wasm;
4646 }
47 break .elf;
47 return .elf;
4848 },
49 };
49 }
5050}
5151
5252pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
......@@ -156,7 +156,7 @@ pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
156156 }
157157}
158158
159pub fn getDarwinArchString(self: Target) []const u8 {
159pub fn getDarwinArchString(self: Target) [:0]const u8 {
160160 const arch = self.getArch();
161161 switch (arch) {
162162 .aarch64 => return "arm64",
......@@ -166,7 +166,8 @@ pub fn getDarwinArchString(self: Target) []const u8 {
166166 .powerpc => return "ppc",
167167 .powerpc64 => return "ppc64",
168168 .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),
170171 }
171172}
172173
src-self-hosted/value.zig+7-7
......@@ -156,7 +156,7 @@ pub const Value = struct {
156156 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
157157 const llvm_fn = llvm.AddFunction(
158158 ofile.module,
159 self.symbol_name.ptr(),
159 self.symbol_name.toSliceConst(),
160160 llvm_fn_type,
161161 ) orelse return error.OutOfMemory;
162162
......@@ -241,7 +241,7 @@ pub const Value = struct {
241241 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
242242 const llvm_fn = llvm.AddFunction(
243243 ofile.module,
244 self.symbol_name.ptr(),
244 self.symbol_name.toSliceConst(),
245245 llvm_fn_type,
246246 ) orelse return error.OutOfMemory;
247247
......@@ -334,7 +334,7 @@ pub const Value = struct {
334334 field_index: usize,
335335 };
336336
337 pub async fn createArrayElemPtr(
337 pub fn createArrayElemPtr(
338338 comp: *Compilation,
339339 array_val: *Array,
340340 mut: Type.Pointer.Mut,
......@@ -350,7 +350,7 @@ pub const Value = struct {
350350 .mut = mut,
351351 .vol = Type.Pointer.Vol.Non,
352352 .size = size,
353 .alignment = Type.Pointer.Align.Abi,
353 .alignment = .Abi,
354354 });
355355 var ptr_type_consumed = false;
356356 errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
......@@ -390,13 +390,13 @@ pub const Value = struct {
390390 const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
391391 const ptr_bit_count = ofile.comp.target_ptr_bits;
392392 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{
394394 llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
395395 llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
396396 };
397397 return llvm.ConstInBoundsGEP(
398398 array_llvm_value,
399 &indices,
399 @ptrCast([*]*llvm.Value, &indices),
400400 @intCast(c_uint, indices.len),
401401 ) orelse return error.OutOfMemory;
402402 },
......@@ -423,7 +423,7 @@ pub const Value = struct {
423423 };
424424
425425 /// Takes ownership of buffer
426 pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {
426 pub fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {
427427 const u8_type = Type.Int.get_u8(comp);
428428 defer u8_type.base.base.deref(comp);
429429
src/all_types.hpp+3-1
......@@ -1565,7 +1565,7 @@ struct ZigFn {
15651565 // in the case of async functions this is the implicit return type according to the
15661566 // zig source code, not according to zig ir
15671567 ZigType *src_implicit_return_type;
1568 IrExecutable ir_executable;
1568 IrExecutable *ir_executable;
15691569 IrExecutable analyzed_executable;
15701570 size_t prealloc_bbc;
15711571 size_t prealloc_backward_branch_quota;
......@@ -2204,6 +2204,8 @@ struct ZigVar {
22042204 bool src_is_const;
22052205 bool gen_is_const;
22062206 bool is_thread_local;
2207 bool is_comptime_memoized;
2208 bool is_comptime_memoized_value;
22072209};
22082210
22092211struct 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
32753275}
32763276
32773277ZigFn *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
32803281 fn_entry->prealloc_backward_branch_quota = default_backward_branch_quota;
32813282
32823283 fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc;
32833284 fn_entry->analyzed_executable.backward_branch_quota = &fn_entry->prealloc_backward_branch_quota;
32843285 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;
32863287 fn_entry->fn_inline = inline_value;
32873288
32883289 return fn_entry;
......@@ -3792,6 +3793,16 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
37923793 return variable_entry;
37933794}
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
37953806static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
37963807 AstNode *source_node = tld_var->base.source_node;
37973808 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) {
38813892 }
38823893
38833894 if (is_export) {
3895 validate_export_var_type(g, type, source_node);
38843896 add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong);
38853897 }
38863898
......@@ -4599,7 +4611,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) {
45994611 assert(!fn_type->data.fn.is_generic);
46004612 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,
46034615 &fn->analyzed_executable, fn_type_id->return_type, return_type_node);
46044616 fn->src_implicit_return_type = block_return_type;
46054617
......@@ -4695,7 +4707,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
46954707 assert(!fn_type->data.fn.is_generic);
46964708
46974709 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) {
46994711 fn_table_entry->anal_state = FnAnalStateInvalid;
47004712 return;
47014713 }
......@@ -4703,7 +4715,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) {
47034715 fprintf(stderr, "\n");
47044716 ast_render(stderr, fn_table_entry->body_node, 4);
47054717 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);
47074719 fprintf(stderr, "}\n");
47084720 }
47094721
......@@ -6442,20 +6454,31 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) {
64426454}
64436455
64446456bool 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
64456462 // The is_comptime field can be left null, which means not comptime.
6446 if (var->is_comptime == nullptr)
6447 return false;
6463 if (var->is_comptime == nullptr) {
6464 var->is_comptime_memoized_value = false;
6465 return var->is_comptime_memoized_value;
6466 }
64486467 // When the is_comptime field references an instruction that has to get analyzed, this
64496468 // is the value.
64506469 if (var->is_comptime->child != nullptr) {
64516470 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;
64536474 }
64546475 // As an optimization, is_comptime values which are constant are allowed
64556476 // to be omitted from analysis. In this case, there is no child instruction
64566477 // and we simply look at the unanalyzed const parent instruction.
64576478 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;
64596482}
64606483
64616484bool 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
95639563 case ZigTypeIdVoid:
95649564 case ZigTypeIdUnreachable:
95659565 case ZigTypeIdBool:
9566 g->c_want_stdbool = true;
9567 return;
95669568 case ZigTypeIdInt:
9569 g->c_want_stdint = true;
9570 return;
95679571 case ZigTypeIdFloat:
95689572 return;
95699573 case ZigTypeIdOpaque:
......@@ -9644,7 +9648,6 @@ static void get_c_type(CodeGen *g, GenH *gen_h, ZigType *type_entry, Buf *out_bu
96449648 break;
96459649 case ZigTypeIdBool:
96469650 buf_init_from_str(out_buf, "bool");
9647 g->c_want_stdbool = true;
96489651 break;
96499652 case ZigTypeIdUnreachable:
96509653 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
96689671 }
96699672 break;
96709673 case ZigTypeIdInt:
9671 g->c_want_stdint = true;
96729674 buf_resize(out_buf, 0);
96739675 buf_appendf(out_buf, "%sint%" PRIu32 "_t",
96749676 type_entry->data.integral.is_signed ? "" : "u",
......@@ -9780,113 +9782,7 @@ static Buf *preprocessor_mangle(Buf *src) {
97809782 return result;
97819783}
97829784
9783static void gen_h_file(CodeGen *g) {
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
9785static void gen_h_file_types(CodeGen* g, GenH* gen_h, Buf* out_buf) {
98909786 for (size_t type_i = 0; type_i < gen_h->types_to_declare.length; type_i += 1) {
98919787 ZigType *type_entry = gen_h->types_to_declare.at(type_i);
98929788 switch (type_entry->id) {
......@@ -9917,25 +9813,25 @@ static void gen_h_file(CodeGen *g) {
99179813
99189814 case ZigTypeIdEnum:
99199815 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)));
99219817 for (uint32_t field_i = 0; field_i < type_entry->data.enumeration.src_field_count; field_i += 1) {
99229818 TypeEnumField *enum_field = &type_entry->data.enumeration.fields[field_i];
99239819 Buf *value_buf = buf_alloc();
99249820 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));
99269822 if (field_i != type_entry->data.enumeration.src_field_count - 1) {
9927 fprintf(out_h, ",");
9823 buf_appendf(out_buf, ",");
99289824 }
9929 fprintf(out_h, "\n");
9825 buf_appendf(out_buf, "\n");
99309826 }
9931 fprintf(out_h, "};\n\n");
9827 buf_appendf(out_buf, "};\n\n");
99329828 } 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)));
99349830 }
99359831 break;
99369832 case ZigTypeIdStruct:
99379833 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)));
99399835 for (uint32_t field_i = 0; field_i < type_entry->data.structure.src_field_count; field_i += 1) {
99409836 TypeStructField *struct_field = type_entry->data.structure.fields[field_i];
99419837
......@@ -9943,43 +9839,194 @@ static void gen_h_file(CodeGen *g) {
99439839 get_c_type(g, gen_h, struct_field->type_entry, type_name_buf);
99449840
99459841 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),
99479843 buf_ptr(struct_field->name),
99489844 struct_field->type_entry->data.array.len);
99499845 } 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));
99519847 }
99529848
99539849 }
9954 fprintf(out_h, "};\n\n");
9850 buf_appendf(out_buf, "};\n\n");
99559851 } 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)));
99579853 }
99589854 break;
99599855 case ZigTypeIdUnion:
99609856 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)));
99629858 for (uint32_t field_i = 0; field_i < type_entry->data.unionation.src_field_count; field_i += 1) {
99639859 TypeUnionField *union_field = &type_entry->data.unionation.fields[field_i];
99649860
99659861 Buf *type_name_buf = buf_alloc();
99669862 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));
99689864 }
9969 fprintf(out_h, "};\n\n");
9865 buf_appendf(out_buf, "};\n\n");
99709866 } 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)));
99729868 }
99739869 break;
99749870 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)));
99769872 break;
99779873 }
99789874 }
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
998410031 if (fclose(out_h))
998510032 zig_panic("unable to close h file: %s", strerror(errno));
src/ir.cpp+456-30
......@@ -41,6 +41,7 @@ struct IrAnalyze {
4141 ZigList<IrInstruction *> src_implicit_return_type_list;
4242 ZigList<IrSuspendPosition> resume_stack;
4343 IrBasicBlock *const_predecessor_bb;
44 size_t ref_count;
4445
4546 // For the purpose of using in a debugger
4647 void dump();
......@@ -74,6 +75,7 @@ enum ConstCastResultId {
7475 ConstCastResultIdPtrLens,
7576 ConstCastResultIdCV,
7677 ConstCastResultIdPtrSentinel,
78 ConstCastResultIdIntShorten,
7779};
7880
7981struct ConstCastOnly;
......@@ -100,6 +102,7 @@ struct ConstCastBadAllowsZero;
100102struct ConstCastBadNullTermArrays;
101103struct ConstCastBadCV;
102104struct ConstCastPtrSentinel;
105struct ConstCastIntShorten;
103106
104107struct ConstCastOnly {
105108 ConstCastResultId id;
......@@ -120,6 +123,7 @@ struct ConstCastOnly {
120123 ConstCastBadNullTermArrays *sentinel_arrays;
121124 ConstCastBadCV *bad_cv;
122125 ConstCastPtrSentinel *bad_ptr_sentinel;
126 ConstCastIntShorten *int_shorten;
123127 } data;
124128};
125129
......@@ -189,6 +193,11 @@ struct ConstCastPtrSentinel {
189193 ZigType *actual_type;
190194};
191195
196struct ConstCastIntShorten {
197 ZigType *wanted_type;
198 ZigType *actual_type;
199};
200
192201static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope);
193202static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval,
194203 ResultLoc *result_loc);
......@@ -248,6 +257,381 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n
248257 IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type);
249258static 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
251635static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) {
252636 assert(get_src_ptr_type(const_val->type) != nullptr);
253637 assert(const_val->special == ConstValSpecialStatic);
......@@ -4186,7 +4570,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod
41864570 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
41874571 incoming_values[0] = val1;
41884572 incoming_values[1] = val2;
4189 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
4573 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
41904574 incoming_blocks[0] = post_val1_block;
41914575 incoming_blocks[1] = post_val2_block;
41924576
......@@ -4277,7 +4661,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode
42774661 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
42784662 incoming_values[0] = null_result;
42794663 incoming_values[1] = unwrapped_payload;
4280 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
4664 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
42814665 incoming_blocks[0] = after_null_block;
42824666 incoming_blocks[1] = after_ok_block;
42834667 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
60446428 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
60456429 incoming_values[0] = then_expr_result;
60466430 incoming_values[1] = else_expr_result;
6047 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
6431 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
60486432 incoming_blocks[0] = after_then_block;
60496433 incoming_blocks[1] = after_else_block;
60506434
......@@ -7398,7 +7782,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN
73987782 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
73997783 incoming_values[0] = then_expr_result;
74007784 incoming_values[1] = else_expr_result;
7401 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
7785 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
74027786 incoming_blocks[0] = after_then_block;
74037787 incoming_blocks[1] = after_else_block;
74047788
......@@ -7495,7 +7879,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
74957879 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
74967880 incoming_values[0] = then_expr_result;
74977881 incoming_values[1] = else_expr_result;
7498 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
7882 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
74997883 incoming_blocks[0] = after_then_block;
75007884 incoming_blocks[1] = after_else_block;
75017885
......@@ -8092,7 +8476,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode
80928476 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
80938477 incoming_values[0] = err_result;
80948478 incoming_values[1] = unwrapped_payload;
8095 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
8479 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
80968480 incoming_blocks[0] = after_err_block;
80978481 incoming_blocks[1] = after_ok_block;
80988482 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
86809064bool ir_gen_fn(CodeGen *codegen, ZigFn *fn_entry) {
86819065 assert(fn_entry);
86829066
8683 IrExecutable *ir_executable = &fn_entry->ir_executable;
9067 IrExecutable *ir_executable = fn_entry->ir_executable;
86849068 AstNode *body_node = fn_entry->body_node;
86859069
86869070 assert(fn_entry->child_scope);
......@@ -10224,6 +10608,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
1022410608 return result;
1022510609 }
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
1022710619 result.id = ConstCastResultIdType;
1022810620 result.data.type_mismatch = allocate_nonzero<ConstCastTypeMismatch>(1);
1022910621 result.data.type_mismatch->wanted_type = wanted_type;
......@@ -11490,7 +11882,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
1149011882 if (expected_type != nullptr && type_is_invalid(expected_type))
1149111883 return codegen->invalid_instruction->value;
1149211884
11493 IrExecutable *ir_executable = allocate<IrExecutable>(1);
11885 IrExecutable *ir_executable = allocate<IrExecutable>(1, "IrExecutablePass1");
1149411886 ir_executable->source_node = source_node;
1149511887 ir_executable->parent_exec = parent_exec;
1149611888 ir_executable->name = exec_name;
......@@ -11512,7 +11904,7 @@ ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node,
1151211904 ir_print(codegen, stderr, ir_executable, 2, IrPassSrc);
1151311905 fprintf(stderr, "}\n");
1151411906 }
11515 IrExecutable *analyzed_executable = allocate<IrExecutable>(1);
11907 IrExecutable *analyzed_executable = allocate<IrExecutable>(1, "IrExecutablePass2");
1151611908 analyzed_executable->source_node = source_node;
1151711909 analyzed_executable->parent_exec = parent_exec;
1151811910 analyzed_executable->source_exec = ir_executable;
......@@ -12641,6 +13033,17 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
1264113033 add_error_note(ira->codegen, parent_msg, source_node,
1264213034 buf_sprintf("calling convention mismatch"));
1264313035 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 }
1264413047 case ConstCastResultIdFnAlign: // TODO
1264513048 case ConstCastResultIdFnVarArgs: // TODO
1264613049 case ConstCastResultIdFnReturnType: // TODO
......@@ -15597,6 +16000,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
1559716000 assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length);
1559816001 ZigValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index);
1559916002 copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const);
16003 ira_ref(var->owner_exec->analysis);
1560016004
1560116005 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
1560216006 return ir_const_void(ira, &decl_var_instruction->base);
......@@ -15869,8 +16273,8 @@ static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira,
1586916273 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
1587016274 result->value->special = ConstValSpecialLazy;
1587116275
15872 LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1);
15873 lazy_err_union_type->ira = ira;
16276 LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1, "LazyValueErrUnionType");
16277 lazy_err_union_type->ira = ira; ira_ref(ira);
1587416278 result->value->data.x_lazy = &lazy_err_union_type->base;
1587516279 lazy_err_union_type->base.id = LazyValueIdErrUnionType;
1587616280
......@@ -17368,8 +17772,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1736817772 if (type_is_invalid(impl_fn->type_entry))
1736917773 return ira->codegen->invalid_instruction;
1737017774
17371 impl_fn->ir_executable.source_node = call_instruction->base.source_node;
17372 impl_fn->ir_executable.parent_exec = ira->new_irb.exec;
17775 impl_fn->ir_executable->source_node = call_instruction->base.source_node;
17776 impl_fn->ir_executable->parent_exec = ira->new_irb.exec;
1737317777 impl_fn->analyzed_executable.source_node = call_instruction->base.source_node;
1737417778 impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec;
1737517779 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
1772218126 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
1772318127 result->value->special = ConstValSpecialLazy;
1772418128
17725 LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1);
17726 lazy_opt_type->ira = ira;
18129 LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1, "LazyValueOptType");
18130 lazy_opt_type->ira = ira; ira_ref(ira);
1772718131 result->value->data.x_lazy = &lazy_opt_type->base;
1772818132 lazy_opt_type->base.id = LazyValueIdOptType;
1772918133
......@@ -19668,8 +20072,8 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
1966820072 IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type);
1966920073 result->value->special = ConstValSpecialLazy;
1967020074
19671 LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1);
19672 lazy_slice_type->ira = ira;
20075 LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1, "LazyValueSliceType");
20076 lazy_slice_type->ira = ira; ira_ref(ira);
1967320077 result->value->data.x_lazy = &lazy_slice_type->base;
1967420078 lazy_slice_type->base.id = LazyValueIdSliceType;
1967520079
......@@ -19828,8 +20232,8 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, IrInstructi
1982820232 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
1982920233 result->value->special = ConstValSpecialLazy;
1983020234
19831 LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1);
19832 lazy_size_of->ira = ira;
20235 LazyValueSizeOf *lazy_size_of = allocate<LazyValueSizeOf>(1, "LazyValueSizeOf");
20236 lazy_size_of->ira = ira; ira_ref(ira);
1983320237 result->value->data.x_lazy = &lazy_size_of->base;
1983420238 lazy_size_of->base.id = LazyValueIdSizeOf;
1983520239
......@@ -24556,8 +24960,8 @@ static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruct
2455624960 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int);
2455724961 result->value->special = ConstValSpecialLazy;
2455824962
24559 LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1);
24560 lazy_align_of->ira = ira;
24963 LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1, "LazyValueAlignOf");
24964 lazy_align_of->ira = ira; ira_ref(ira);
2456124965 result->value->data.x_lazy = &lazy_align_of->base;
2456224966 lazy_align_of->base.id = LazyValueIdAlignOf;
2456324967
......@@ -25040,8 +25444,8 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct
2504025444 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
2504125445 result->value->special = ConstValSpecialLazy;
2504225446
25043 LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1);
25044 lazy_fn_type->ira = ira;
25447 LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1, "LazyValueFnType");
25448 lazy_fn_type->ira = ira; ira_ref(ira);
2504525449 result->value->data.x_lazy = &lazy_fn_type->base;
2504625450 lazy_fn_type->base.id = LazyValueIdFnType;
2504725451
......@@ -26081,8 +26485,8 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct
2608126485 IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type);
2608226486 result->value->special = ConstValSpecialLazy;
2608326487
26084 LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1);
26085 lazy_ptr_type->ira = ira;
26488 LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1, "LazyValuePtrType");
26489 lazy_ptr_type->ira = ira; ira_ref(ira);
2608626490 result->value->data.x_lazy = &lazy_ptr_type->base;
2608726491 lazy_ptr_type->base.id = LazyValueIdPtrType;
2608826492
......@@ -27551,7 +27955,8 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
2755127955 assert(old_exec->first_err_trace_msg == nullptr);
2755227956 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;
2755527960 old_exec->analysis = ira;
2755627961 ira->codegen = codegen;
2755727962
......@@ -27618,6 +28023,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
2761828023 ira->instruction_index += 1;
2761928024 }
2762028025
28026 ZigType *res_type;
2762128027 if (new_exec->first_err_trace_msg != nullptr) {
2762228028 codegen->trace_err = new_exec->first_err_trace_msg;
2762328029 if (codegen->trace_err != nullptr && new_exec->source_node != nullptr &&
......@@ -27627,13 +28033,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_
2762728033 codegen->trace_err = add_error_note(codegen, codegen->trace_err,
2762828034 new_exec->source_node, buf_create_from_str("referenced here"));
2762928035 }
27630 return ira->codegen->builtin_types.entry_invalid;
28036 res_type = ira->codegen->builtin_types.entry_invalid;
2763128037 } 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;
2763328039 } 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,
2763528041 ira->src_implicit_return_type_list.length);
2763628042 }
28043
28044 // It is now safe to free Pass 1 IR instructions.
28045 ira_deref(ira);
28046
28047 return res_type;
2763728048}
2763828049
2763928050bool ir_has_side_effects(IrInstruction *instruction) {
......@@ -27969,6 +28380,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
2796928380 val->special = ConstValSpecialStatic;
2797028381 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
2797128382 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.
2797228385 return ErrorNone;
2797328386 }
2797428387 case LazyValueIdSizeOf: {
......@@ -28024,6 +28437,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
2802428437 val->special = ConstValSpecialStatic;
2802528438 assert(val->type->id == ZigTypeIdComptimeInt || val->type->id == ZigTypeIdInt);
2802628439 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.
2802728442 return ErrorNone;
2802828443 }
2802928444 case LazyValueIdSliceType: {
......@@ -28102,6 +28517,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
2810228517 val->special = ConstValSpecialStatic;
2810328518 assert(val->type->id == ZigTypeIdMetaType);
2810428519 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.
2810528522 return ErrorNone;
2810628523 }
2810728524 case LazyValueIdPtrType: {
......@@ -28173,6 +28590,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
2817328590 lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes,
2817428591 allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val);
2817528592 val->special = ConstValSpecialStatic;
28593
28594 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
2817628595 return ErrorNone;
2817728596 }
2817828597 case LazyValueIdOptType: {
......@@ -28195,16 +28614,21 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
2819528614 assert(val->type->id == ZigTypeIdMetaType);
2819628615 val->data.x_type = get_optional_type(ira->codegen, payload_type);
2819728616 val->special = ConstValSpecialStatic;
28617
28618 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
2819828619 return ErrorNone;
2819928620 }
2820028621 case LazyValueIdFnType: {
2820128622 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);
2820328625 if (fn_type == nullptr)
2820428626 return ErrorSemanticAnalyzeFail;
2820528627 val->special = ConstValSpecialStatic;
2820628628 assert(val->type->id == ZigTypeIdMetaType);
2820728629 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.
2820828632 return ErrorNone;
2820928633 }
2821028634 case LazyValueIdErrUnionType: {
......@@ -28233,6 +28657,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) {
2823328657 assert(val->type->id == ZigTypeIdMetaType);
2823428658 val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type);
2823528659 val->special = ConstValSpecialStatic;
28660
28661 // We can't free the lazy value here, because multiple other ZigValues might be pointing to it.
2823628662 return ErrorNone;
2823728663 }
2823828664 }
src/libc_installation.cpp+1-1
......@@ -389,7 +389,7 @@ static Error zig_libc_find_native_msvc_include_dir(ZigLibCInstallation *self, Zi
389389 }
390390 Buf search_path = BUF_INIT;
391391 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
394394 Buf *vcruntime_path = buf_sprintf("%s\\vcruntime.h", buf_ptr(&search_path));
395395 bool exists;
src/list.hpp+1-1
......@@ -13,7 +13,7 @@
1313template<typename T>
1414struct ZigList {
1515 void deinit() {
16 free(items);
16 deallocate(items, capacity);
1717 }
1818 void append(const T& item) {
1919 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)
3535 if (name_or_null != nullptr) return name_or_null;
3636 if (type_size >= unknown_names.length) {
3737 table_active = false;
38 unknown_names.resize(type_size + 1);
38 while (type_size >= unknown_names.length) {
39 unknown_names.append(nullptr);
40 }
3941 table_active = true;
4042 }
4143 if (unknown_names.at(type_size) == nullptr) {
......@@ -66,7 +68,8 @@ void memprof_dealloc(const char *name, size_t count, size_t type_size) {
6668 name = get_default_name(name, type_size);
6769 auto existing_entry = usage_table.maybe_get(name);
6870 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);
7073 }
7174 if (existing_entry->value.type_size != type_size) {
7275 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) {
15541554Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
15551555#if defined(ZIG_OS_WINDOWS)
15561556 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);
15581558 switch (platform_type) {
15591559 case ZigLLVM_x86:
15601560 buf_append_str(output_buf, "x86\\");
......@@ -1586,7 +1586,7 @@ Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Ar
15861586Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
15871587#if defined(ZIG_OS_WINDOWS)
15881588 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);
15901590 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
15911591 return ErrorNone;
15921592 }
......@@ -1603,7 +1603,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
16031603#if defined(ZIG_OS_WINDOWS)
16041604 {
16051605 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);
16071607 switch (platform_type) {
16081608 case ZigLLVM_x86:
16091609 buf_append_str(output_buf, "x86\\");
......@@ -1626,7 +1626,7 @@ Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
16261626 }
16271627 {
16281628 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);
16301630 switch (platform_type) {
16311631 case ZigLLVM_x86:
16321632 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)
165165
166166template<typename T>
167167static inline void destroy(T *old, const char *name = nullptr) {
168 return deallocate(old, 1);
168 return deallocate(old, 1, name);
169169}
170170
171171template <typename T, size_t n>
test/compile_errors.zig+7
......@@ -1670,10 +1670,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
16701670 \\ var spartan_count: u16 = 300;
16711671 \\ var byte: u8 = spartan_count;
16721672 \\}
1673 \\export fn entry4() void {
1674 \\ var signed: i8 = -1;
1675 \\ var unsigned: u64 = signed;
1676 \\}
16731677 ,
16741678 "tmp.zig:3:31: error: integer value 300 cannot be coerced to type 'u8'",
16751679 "tmp.zig:7:22: error: integer value 300 cannot be coerced to type 'u8'",
16761680 "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",
16771684 );
16781685
16791686 cases.add(
test/gen_h.zig+17-15
......@@ -10,9 +10,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
1010 \\ B = 1,
1111 \\ C = 2
1212 \\};
13 \\
14 \\TEST_EXTERN_C void entry(enum Foo foo);
15 \\
13 ,
14 \\void entry(enum Foo foo);
1615 );
1716
1817 cases.add("declare struct",
......@@ -34,8 +33,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
3433 \\ uint64_t E;
3534 \\ uint64_t F;
3635 \\};
37 \\
38 \\TEST_EXTERN_C void entry(struct Foo foo);
36 ,
37 \\void entry(struct Foo foo);
3938 \\
4039 );
4140
......@@ -69,19 +68,19 @@ pub fn addCases(cases: *tests.GenHContext) void {
6968 \\ bool C;
7069 \\ struct Big D;
7170 \\};
72 \\
73 \\TEST_EXTERN_C void entry(union Foo foo);
71 ,
72 \\void entry(union Foo foo);
7473 \\
7574 );
7675
7776 cases.add("declare opaque type",
78 \\export const Foo = @OpaqueType();
77 \\const Foo = @OpaqueType();
7978 \\
8079 \\export fn entry(foo: ?*Foo) void { }
8180 ,
8281 \\struct Foo;
83 \\
84 \\TEST_EXTERN_C void entry(struct Foo * foo);
82 ,
83 \\void entry(struct Foo * foo);
8584 );
8685
8786 cases.add("array field-type",
......@@ -95,8 +94,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
9594 \\ int32_t A[2];
9695 \\ uint32_t * B[4];
9796 \\};
98 \\
99 \\TEST_EXTERN_C void entry(struct Foo foo, uint8_t bar[]);
97 ,
98 \\void entry(struct Foo foo, uint8_t bar[]);
10099 \\
101100 );
102101
......@@ -110,7 +109,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
110109 \\}
111110 ,
112111 \\struct S;
113 \\TEST_EXTERN_C uint8_t a(struct S * s);
112 ,
113 \\uint8_t a(struct S * s);
114114 \\
115115 );
116116
......@@ -125,7 +125,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
125125 \\}
126126 ,
127127 \\union U;
128 \\TEST_EXTERN_C uint8_t a(union U * s);
128 ,
129 \\uint8_t a(union U * s);
129130 \\
130131 );
131132
......@@ -140,7 +141,8 @@ pub fn addCases(cases: *tests.GenHContext) void {
140141 \\}
141142 ,
142143 \\enum E;
143 \\TEST_EXTERN_C uint8_t a(enum E * s);
144 ,
145 \\uint8_t a(enum E * s);
144146 \\
145147 );
146148}
test/standalone/cat/main.zig+5-3
......@@ -1,7 +1,7 @@
11const std = @import("std");
22const io = std.io;
33const process = std.process;
4const File = std.fs.File;
4const fs = std.fs;
55const mem = std.mem;
66const warn = std.debug.warn;
77const allocator = std.debug.global_allocator;
......@@ -12,6 +12,8 @@ pub fn main() !void {
1212 var catted_anything = false;
1313 const stdout_file = io.getStdOut();
1414
15 const cwd = fs.cwd();
16
1517 while (args_it.next(allocator)) |arg_or_err| {
1618 const arg = try unwrapArg(arg_or_err);
1719 if (mem.eql(u8, arg, "-")) {
......@@ -20,7 +22,7 @@ pub fn main() !void {
2022 } else if (arg[0] == '-') {
2123 return usage(exe);
2224 } else {
23 const file = File.openRead(arg) catch |err| {
25 const file = cwd.openFile(arg, .{}) catch |err| {
2426 warn("Unable to open file: {}\n", @errorName(err));
2527 return err;
2628 };
......@@ -40,7 +42,7 @@ fn usage(exe: []const u8) !void {
4042 return error.Invalid;
4143}
4244
43fn cat_file(stdout: File, file: File) !void {
45fn cat_file(stdout: fs.File, file: fs.File) !void {
4446 var buf: [1024 * 4]u8 = undefined;
4547
4648 while (true) {
test/standalone/static_c_lib/foo.c+2
......@@ -2,3 +2,5 @@
22uint32_t add(uint32_t a, uint32_t b) {
33 return a + b;
44}
5
6uint32_t foo = 12345;
test/standalone/static_c_lib/foo.h+1
......@@ -1,2 +1,3 @@
11#include <stdint.h>
22uint32_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" {
66 const result = c.add(1, 2);
77 expect(result == 3);
88}
9
10test "C extern variable" {
11 expect(c.foo == 12345);
12}
test/tests.zig+20
......@@ -70,6 +70,26 @@ const test_targets = [_]TestTarget{
7070 .link_libc = true,
7171 },
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
7393 TestTarget{
7494 .target = Target{
7595 .Cross = CrossTarget{