From edcf8e0636c5a2674ce2b3e568929232c8cc61eb Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 13 Mar 2020 17:55:40 +0100 Subject: [PATCH 01/79] std: Multithreaded-aware panic handler Gracefully handle the case of several threads panicking at the same time. --- lib/std/debug.zig | 52 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 0a7a0dee7e..cdbba2367b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -235,9 +235,17 @@ pub fn panic(comptime format: []const u8, args: var) noreturn { panicExtra(null, first_trace_addr, format, args); } -/// TODO multithreaded awareness +/// Non-zero whenever the program triggered a panic. +/// The counter is incremented/decremented atomically. var panicking: u8 = 0; +// Locked to avoid interleaving panic messages from multiple threads. +var panic_mutex = std.Mutex.init(); + +/// Counts how many times the panic handler is invoked by this thread. +/// This is used to catch and handle panics triggered by the panic handler. +threadlocal var panic_stage: usize = 0; + pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, comptime format: []const u8, args: var) noreturn { @setCold(true); @@ -247,25 +255,47 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c resetSegfaultHandler(); } - switch (@atomicRmw(u8, &panicking, .Add, 1, .SeqCst)) { + switch (panic_stage) { 0 => { - const stderr = getStderrStream(); - noasync stderr.print(format ++ "\n", args) catch os.abort(); - if (trace) |t| { - dumpStackTrace(t.*); + panic_stage = 1; + + _ = @atomicRmw(u8, &panicking, .Add, 1, .SeqCst); + + // Make sure to release the mutex when done + { + const held = panic_mutex.acquire(); + defer held.release(); + + const stderr = getStderrStream(); + noasync stderr.print(format ++ "\n", args) catch os.abort(); + if (trace) |t| { + dumpStackTrace(t.*); + } + dumpCurrentStackTrace(first_trace_addr); + } + + if (@atomicRmw(u8, &panicking, .Sub, 1, .SeqCst) != 1) { + // Another thread is panicking, wait for the last one to finish + // and call abort() + + // XXX: Find a nicer way to loop forever + while (true) {} } - dumpCurrentStackTrace(first_trace_addr); }, 1 => { - // TODO detect if a different thread caused the panic, because in that case - // we would want to return here instead of calling abort, so that the thread - // which first called panic can finish printing a stack trace. - warn("Panicked during a panic. Aborting.\n", .{}); + panic_stage = 2; + + // A panic happened while trying to print a previous panic message, + // we're still holding the mutex but that's fine as we're going to + // call abort() + const stderr = getStderrStream(); + noasync stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort(); }, else => { // Panicked while printing "Panicked during a panic." }, } + os.abort(); } From e496ef26dabb3a2da4821c7c0c2e4ffc6f7d86ce Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 13 Mar 2020 18:40:18 +0100 Subject: [PATCH 02/79] Nicer idle wait loop Trying to acquire twice the same mutex generates an idle loop. --- lib/std/debug.zig | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index cdbba2367b..f2c736bbba 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -278,8 +278,11 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c // Another thread is panicking, wait for the last one to finish // and call abort() - // XXX: Find a nicer way to loop forever - while (true) {} + // Here we sleep forever without hammering the CPU by causing a + // deadlock + var deadlock = std.Mutex.init(); + _ = deadlock.acquire(); + _ = deadlock.acquire(); } }, 1 => { From 2501e80500f99c1ede6daf2f7c50c2dec3c9675c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 13 Mar 2020 19:20:18 +0100 Subject: [PATCH 03/79] Even better idle waiting method --- lib/std/debug.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index f2c736bbba..5600990924 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -278,11 +278,11 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c // Another thread is panicking, wait for the last one to finish // and call abort() - // Here we sleep forever without hammering the CPU by causing a - // deadlock - var deadlock = std.Mutex.init(); - _ = deadlock.acquire(); - _ = deadlock.acquire(); + // Sleep forever without hammering the CPU + var event = std.ResetEvent.init(); + event.wait(); + + unreachable; } }, 1 => { From 66e76a0209586000a78fe896071e73202a80b81f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 13 Mar 2020 21:06:07 -0400 Subject: [PATCH 04/79] zig build system: correctly handle multiple output artifacts Previously the zig build system incorrectly assumed that the only build artifact was a binary. Now, when you enable the cache, only the output dir is printed to stdout, and the zig build system iterates over the files in that directory, copying them to the output directory. To support this change: * Add `std.os.renameat`, `std.os.renameatZ`, and `std.os.renameatW`. * Fix `std.os.linux.renameat` not compiling due to typos. * Deprecate `std.fs.updateFile` and `std.fs.updateFileMode`. * Add `std.fs.Dir.updateFile`, which supports using open directory handles for both the source and destination paths, as well as an options parameter which allows overriding the mode. * Update `std.fs.AtomicFile` to support operating based on an open directory handle. Instead of `std.fs.AtomicFile.init`, use `std.fs.Dir.atomicFile`. * `std.fs.AtomicFile` deinit() better handles the situation when the rename fails but the temporary file still exists, by still attempting to remove the temporary file. * `std.fs.Dir.openFileWindows` is moved to `std.os.windows.OpenFileW`. * `std.os.RenameError` gains the error codes `NoDevice`, `SharingViolation`, and `PipeBusy` which have been observed from Windows. Closes #4733 --- lib/std/build.zig | 21 +-- lib/std/c.zig | 1 + lib/std/fs.zig | 261 ++++++++++++++++-------------------- lib/std/os.zig | 114 +++++++++++++++- lib/std/os/linux.zig | 8 +- lib/std/os/windows.zig | 76 +++++++++++ lib/std/os/windows/bits.zig | 7 + src/main.cpp | 3 +- 8 files changed, 333 insertions(+), 158 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index e8484e9d1c..8fb5eaeeb0 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2144,17 +2144,22 @@ pub const LibExeObjStep = struct { try zig_args.append("--cache"); try zig_args.append("on"); - const output_path_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); - const output_path = mem.trimRight(u8, output_path_nl, "\r\n"); + const output_dir_nl = try builder.execFromStep(zig_args.toSliceConst(), &self.step); + const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); if (self.output_dir) |output_dir| { - const full_dest = try fs.path.join(builder.allocator, &[_][]const u8{ - output_dir, - fs.path.basename(output_path), - }); - try builder.updateFile(output_path, full_dest); + var src_dir = try std.fs.cwd().openDirTraverse(build_output_dir); + defer src_dir.close(); + + var dest_dir = try std.fs.cwd().openDirList(output_dir); + defer dest_dir.close(); + + var it = src_dir.iterate(); + while (try it.next()) |entry| { + _ = try src_dir.updateFile(entry.name, dest_dir, entry.name, .{}); + } } else { - self.output_dir = fs.path.dirname(output_path).?; + self.output_dir = build_output_dir; } } diff --git a/lib/std/c.zig b/lib/std/c.zig index 39a865ebbc..43b3d7f317 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -106,6 +106,7 @@ pub extern "c" fn mkdir(path: [*:0]const u8, mode: c_uint) c_int; pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: u32) c_int; pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; +pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int; pub extern "c" fn chdir(path: [*:0]const u8) c_int; pub extern "c" fn fchdir(fd: fd_t) c_int; pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index de6be91f71..231235baf5 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -81,60 +81,21 @@ pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: } } -// TODO fix enum literal not casting to error union -const PrevStatus = enum { +pub const PrevStatus = enum { stale, fresh, }; +/// Deprecated; use `Dir.updateFile`. pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { - return updateFileMode(source_path, dest_path, null); + const my_cwd = cwd(); + return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{}); } -/// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. -/// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, -/// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. -/// Returns the previous status of the file before updating. -/// If any of the directories do not exist for dest_path, they are created. -/// TODO rework this to integrate with Dir -pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !PrevStatus { +/// Deprecated; use `Dir.updateFile`. +pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !Dir.PrevStatus { const my_cwd = cwd(); - - var src_file = try my_cwd.openFile(source_path, .{}); - defer src_file.close(); - - const src_stat = try src_file.stat(); - check_dest_stat: { - const dest_stat = blk: { - var dest_file = my_cwd.openFile(dest_path, .{}) catch |err| switch (err) { - error.FileNotFound => break :check_dest_stat, - else => |e| return e, - }; - defer dest_file.close(); - - break :blk try dest_file.stat(); - }; - - if (src_stat.size == dest_stat.size and - src_stat.mtime == dest_stat.mtime and - src_stat.mode == dest_stat.mode) - { - return PrevStatus.fresh; - } - } - const actual_mode = mode orelse src_stat.mode; - - if (path.dirname(dest_path)) |dirname| { - try cwd().makePath(dirname); - } - - var atomic_file = try AtomicFile.init(dest_path, actual_mode); - defer atomic_file.deinit(); - - try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); - try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); - try atomic_file.finish(); - return PrevStatus.stale; + return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{ .override_mode = mode }); } /// Guaranteed to be atomic. @@ -172,43 +133,40 @@ pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.M return atomic_file.finish(); } -/// TODO update this API to avoid a getrandom syscall for every operation. It -/// should accept a random interface. -/// TODO rework this to integrate with Dir +/// TODO update this API to avoid a getrandom syscall for every operation. pub const AtomicFile = struct { file: File, - tmp_path_buf: [MAX_PATH_BYTES]u8, + tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8, dest_path: []const u8, - finished: bool, + file_open: bool, + file_exists: bool, + dir: Dir, const InitError = File.OpenError; - /// dest_path must remain valid for the lifetime of AtomicFile - /// call finish to atomically replace dest_path with contents - pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { + /// TODO rename this. Callers should go through Dir API + pub fn init2(dest_path: []const u8, mode: File.Mode, dir: Dir) InitError!AtomicFile { const dirname = path.dirname(dest_path); var rand_buf: [12]u8 = undefined; const dirname_component_len = if (dirname) |d| d.len + 1 else 0; const encoded_rand_len = comptime base64.Base64Encoder.calcSize(rand_buf.len); const tmp_path_len = dirname_component_len + encoded_rand_len; - var tmp_path_buf: [MAX_PATH_BYTES]u8 = undefined; - if (tmp_path_len >= tmp_path_buf.len) return error.NameTooLong; + var tmp_path_buf: [MAX_PATH_BYTES - 1:0]u8 = undefined; + if (tmp_path_len > tmp_path_buf.len) return error.NameTooLong; - if (dirname) |dir| { - mem.copy(u8, tmp_path_buf[0..], dir); - tmp_path_buf[dir.len] = path.sep; + if (dirname) |dn| { + mem.copy(u8, tmp_path_buf[0..], dn); + tmp_path_buf[dn.len] = path.sep; } tmp_path_buf[tmp_path_len] = 0; const tmp_path_slice = tmp_path_buf[0..tmp_path_len :0]; - const my_cwd = cwd(); - while (true) { try crypto.randomBytes(rand_buf[0..]); base64_encoder.encode(tmp_path_slice[dirname_component_len..tmp_path_len], &rand_buf); - const file = my_cwd.createFileC( + const file = dir.createFileC( tmp_path_slice, .{ .mode = mode, .exclusive = true }, ) catch |err| switch (err) { @@ -220,33 +178,46 @@ pub const AtomicFile = struct { .file = file, .tmp_path_buf = tmp_path_buf, .dest_path = dest_path, - .finished = false, + .file_open = true, + .file_exists = true, + .dir = dir, }; } } + /// Deprecated. Use `Dir.atomicFile`. + pub fn init(dest_path: []const u8, mode: File.Mode) InitError!AtomicFile { + return init2(dest_path, mode, cwd()); + } + /// always call deinit, even after successful finish() pub fn deinit(self: *AtomicFile) void { - if (!self.finished) { + if (self.file_open) { self.file.close(); - cwd().deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; - self.finished = true; + self.file_open = false; } + if (self.file_exists) { + self.dir.deleteFileC(&self.tmp_path_buf) catch {}; + self.file_exists = false; + } + self.* = undefined; } pub fn finish(self: *AtomicFile) !void { - assert(!self.finished); + assert(self.file_exists); + if (self.file_open) { + self.file.close(); + self.file_open = false; + } if (std.Target.current.os.tag == .windows) { const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); - const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf)); - self.file.close(); - self.finished = true; - return os.renameW(&tmp_path_w, &dest_path_w); + const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); + try os.renameatW(self.dir.fd, &tmp_path_w, self.dir.fd, &dest_path_w, os.windows.TRUE); + self.file_exists = false; } else { const dest_path_c = try os.toPosixPath(self.dest_path); - self.file.close(); - self.finished = true; - return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c); + try os.renameatZ(self.dir.fd, &self.tmp_path_buf, self.dir.fd, &dest_path_c); + self.file_exists = false; } } }; @@ -694,7 +665,10 @@ pub const Dir = struct { const access_mask = w.SYNCHRONIZE | (if (flags.read) @as(u32, w.GENERIC_READ) else 0) | (if (flags.write) @as(u32, w.GENERIC_WRITE) else 0); - return self.openFileWindows(sub_path_w, access_mask, w.FILE_OPEN); + return @as(File, .{ + .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, w.FILE_OPEN), + .io_mode = .blocking, + }); } /// Creates, opens, or overwrites a file with write access. @@ -739,7 +713,10 @@ pub const Dir = struct { @as(u32, w.FILE_OVERWRITE_IF) else @as(u32, w.FILE_OPEN_IF); - return self.openFileWindows(sub_path_w, access_mask, creation); + return @as(File, .{ + .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, creation), + .io_mode = .blocking, + }); } /// Deprecated; call `openFile` directly. @@ -757,72 +734,6 @@ pub const Dir = struct { return self.openFileW(sub_path, .{}); } - pub fn openFileWindows( - self: Dir, - sub_path_w: [*:0]const u16, - access_mask: os.windows.ACCESS_MASK, - creation: os.windows.ULONG, - ) File.OpenError!File { - const w = os.windows; - - if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { - return error.IsDir; - } - if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { - return error.IsDir; - } - - var result = File{ - .handle = undefined, - .io_mode = .blocking, - }; - - const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) { - error.Overflow => return error.NameTooLong, - }; - var nt_name = w.UNICODE_STRING{ - .Length = path_len_bytes, - .MaximumLength = path_len_bytes, - .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), - }; - var attr = w.OBJECT_ATTRIBUTES{ - .Length = @sizeOf(w.OBJECT_ATTRIBUTES), - .RootDirectory = if (path.isAbsoluteWindowsW(sub_path_w)) null else self.fd, - .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. - .ObjectName = &nt_name, - .SecurityDescriptor = null, - .SecurityQualityOfService = null, - }; - var io: w.IO_STATUS_BLOCK = undefined; - const rc = w.ntdll.NtCreateFile( - &result.handle, - access_mask, - &attr, - &io, - null, - w.FILE_ATTRIBUTE_NORMAL, - w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, - creation, - w.FILE_NON_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT, - null, - 0, - ); - switch (rc) { - .SUCCESS => return result, - .OBJECT_NAME_INVALID => unreachable, - .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, - .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, - .NO_MEDIA_IN_DEVICE => return error.NoDevice, - .INVALID_PARAMETER => unreachable, - .SHARING_VIOLATION => return error.SharingViolation, - .ACCESS_DENIED => return error.AccessDenied, - .PIPE_BUSY => return error.PipeBusy, - .OBJECT_PATH_SYNTAX_BAD => unreachable, - .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, - else => return w.unexpectedStatus(rc), - } - } - pub fn makeDir(self: Dir, sub_path: []const u8) !void { try os.mkdirat(self.fd, sub_path, default_new_dir_mode); } @@ -898,6 +809,7 @@ pub const Dir = struct { /// Call `close` on the result when done. /// /// Asserts that the path parameter has no null bytes. + /// TODO collapse this and `openDirList` into one function with an options parameter pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { if (builtin.os.tag == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); @@ -915,6 +827,7 @@ pub const Dir = struct { /// Call `close` on the result when done. /// /// Asserts that the path parameter has no null bytes. + /// TODO collapse this and `openDirTraverse` into one function with an options parameter pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { if (builtin.os.tag == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); @@ -1370,6 +1283,70 @@ pub const Dir = struct { pub fn accessW(self: Dir, sub_path_w: [*:0]const u16, flags: File.OpenFlags) AccessError!void { return os.faccessatW(self.fd, sub_path_w, 0, 0); } + + pub const UpdateFileOptions = struct { + override_mode: ?File.Mode = null, + }; + + /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. + /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, + /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. + /// Returns the previous status of the file before updating. + /// If any of the directories do not exist for dest_path, they are created. + /// If `override_mode` is provided, then that value is used rather than the source path's mode. + pub fn updateFile( + source_dir: Dir, + source_path: []const u8, + dest_dir: Dir, + dest_path: []const u8, + options: UpdateFileOptions, + ) !PrevStatus { + var src_file = try source_dir.openFile(source_path, .{}); + defer src_file.close(); + + const src_stat = try src_file.stat(); + const actual_mode = options.override_mode orelse src_stat.mode; + check_dest_stat: { + const dest_stat = blk: { + var dest_file = dest_dir.openFile(dest_path, .{}) catch |err| switch (err) { + error.FileNotFound => break :check_dest_stat, + else => |e| return e, + }; + defer dest_file.close(); + + break :blk try dest_file.stat(); + }; + + if (src_stat.size == dest_stat.size and + src_stat.mtime == dest_stat.mtime and + actual_mode == dest_stat.mode) + { + return PrevStatus.fresh; + } + } + + if (path.dirname(dest_path)) |dirname| { + try dest_dir.makePath(dirname); + } + + var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = actual_mode }); + defer atomic_file.deinit(); + + try atomic_file.file.writeFileAll(src_file, .{ .in_len = src_stat.size }); + try atomic_file.file.updateTimes(src_stat.atime, src_stat.mtime); + try atomic_file.finish(); + return PrevStatus.stale; + } + + pub const AtomicFileOptions = struct { + mode: File.Mode = File.default_mode, + }; + + /// `dest_path` must remain valid for the lifetime of `AtomicFile`. + /// Call `AtomicFile.finish` to atomically replace `dest_path` with contents. + pub fn atomicFile(self: Dir, dest_path: []const u8, options: AtomicFileOptions) !AtomicFile { + return AtomicFile.init2(dest_path, options.mode, self); + } }; /// Returns an handle to the current working directory that is open for traversal. diff --git a/lib/std/os.zig b/lib/std/os.zig index ed99c48021..0186e1b0bf 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -461,13 +461,11 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void { ); switch (rc) { - .SUCCESS => {}, + .SUCCESS => return, .INVALID_HANDLE => unreachable, // Handle not open for writing .ACCESS_DENIED => return error.CannotTruncate, else => return windows.unexpectedStatus(rc), } - - return; } while (true) { @@ -852,6 +850,7 @@ pub const OpenError = error{ /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `openC`. +/// TODO support windows pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { const file_path_c = try toPosixPath(file_path); return openC(&file_path_c, flags, perm); @@ -859,6 +858,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `open`. +/// TODO support windows pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { while (true) { const rc = system.open(file_path, flags, perm); @@ -892,6 +892,7 @@ pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openatC`. +/// TODO support windows pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) OpenError!fd_t { const file_path_c = try toPosixPath(file_path); return openatC(dir_fd, &file_path_c, flags, mode); @@ -900,6 +901,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: mode_t) Ope /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openat`. +/// TODO support windows pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t) OpenError!fd_t { while (true) { const rc = system.openat(dir_fd, file_path, flags, mode); @@ -1527,6 +1529,9 @@ const RenameError = error{ RenameAcrossMountPoints, InvalidUtf8, BadPathName, + NoDevice, + SharingViolation, + PipeBusy, } || UnexpectedError; /// Change the name or location of a file. @@ -1580,6 +1585,108 @@ pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!v return windows.MoveFileExW(old_path, new_path, flags); } +/// Change the name or location of a file based on an open directory handle. +pub fn renameat( + old_dir_fd: fd_t, + old_path: []const u8, + new_dir_fd: fd_t, + new_path: []const u8, +) RenameError!void { + if (builtin.os.tag == .windows) { + const old_path_w = try windows.sliceToPrefixedFileW(old_path); + const new_path_w = try windows.sliceToPrefixedFileW(new_path); + return renameatW(old_dir_fd, &old_path_w, new_dir_fd, &new_path_w, windows.TRUE); + } else { + const old_path_c = try toPosixPath(old_path); + const new_path_c = try toPosixPath(new_path); + return renameatZ(old_dir_fd, &old_path_c, new_dir_fd, &new_path_c); + } +} + +/// Same as `renameat` except the parameters are null-terminated byte arrays. +pub fn renameatZ( + old_dir_fd: fd_t, + old_path: [*:0]const u8, + new_dir_fd: fd_t, + new_path: [*:0]const u8, +) RenameError!void { + if (builtin.os.tag == .windows) { + const old_path_w = try windows.cStrToPrefixedFileW(old_path); + const new_path_w = try windows.cStrToPrefixedFileW(new_path); + return renameatW(old_dir_fd, &old_path_w, new_dir_fd, &new_path_w, windows.TRUE); + } + + switch (errno(system.renameat(old_dir_fd, old_path, new_dir_fd, new_path))) { + 0 => return, + EACCES => return error.AccessDenied, + EPERM => return error.AccessDenied, + EBUSY => return error.FileBusy, + EDQUOT => return error.DiskQuota, + EFAULT => unreachable, + EINVAL => unreachable, + EISDIR => return error.IsDir, + ELOOP => return error.SymLinkLoop, + EMLINK => return error.LinkQuotaExceeded, + ENAMETOOLONG => return error.NameTooLong, + ENOENT => return error.FileNotFound, + ENOTDIR => return error.NotDir, + ENOMEM => return error.SystemResources, + ENOSPC => return error.NoSpaceLeft, + EEXIST => return error.PathAlreadyExists, + ENOTEMPTY => return error.PathAlreadyExists, + EROFS => return error.ReadOnlyFileSystem, + EXDEV => return error.RenameAcrossMountPoints, + else => |err| return unexpectedErrno(err), + } +} + +/// Same as `renameat` except the parameters are null-terminated UTF16LE encoded byte arrays. +/// Assumes target is Windows. +/// TODO these args can actually be slices when using ntdll. audit the rest of the W functions too. +pub fn renameatW( + old_dir_fd: fd_t, + old_path: [*:0]const u16, + new_dir_fd: fd_t, + new_path_w: [*:0]const u16, + ReplaceIfExists: windows.BOOLEAN, +) RenameError!void { + const access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE; + const src_fd = try windows.OpenFileW(old_dir_fd, old_path, null, access_mask, windows.FILE_OPEN); + defer windows.CloseHandle(src_fd); + + const struct_buf_len = @sizeOf(windows.FILE_RENAME_INFORMATION) + (MAX_PATH_BYTES - 1); + var rename_info_buf: [struct_buf_len]u8 align(@alignOf(windows.FILE_RENAME_INFORMATION)) = undefined; + const new_path = mem.span(new_path_w); + const struct_len = @sizeOf(windows.FILE_RENAME_INFORMATION) - 1 + new_path.len * 2; + if (struct_len > struct_buf_len) return error.NameTooLong; + + const rename_info = @ptrCast(*windows.FILE_RENAME_INFORMATION, &rename_info_buf); + + rename_info.* = .{ + .ReplaceIfExists = ReplaceIfExists, + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd, + .FileNameLength = @intCast(u32, new_path.len * 2), // already checked error.NameTooLong + .FileName = undefined, + }; + std.mem.copy(u16, @as([*]u16, &rename_info.FileName)[0..new_path.len], new_path); + + var io_status_block: windows.IO_STATUS_BLOCK = undefined; + + const rc = windows.ntdll.NtSetInformationFile( + src_fd, + &io_status_block, + rename_info, + @intCast(u32, struct_len), // already checked for error.NameTooLong + .FileRenameInformation, + ); + + switch (rc) { + .SUCCESS => return, + .INVALID_HANDLE => unreachable, + else => return windows.unexpectedStatus(rc), + } +} + pub const MakeDirError = error{ AccessDenied, DiskQuota, @@ -3125,6 +3232,7 @@ pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealP } /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. +/// TODO use ntdll for better semantics pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { const h_file = try windows.CreateFileW( pathname, diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index ba7356d62c..f3265eaa61 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -465,17 +465,17 @@ pub fn renameat(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const return syscall4( SYS_renameat, @bitCast(usize, @as(isize, oldfd)), - @ptrToInt(old), + @ptrToInt(oldpath), @bitCast(usize, @as(isize, newfd)), - @ptrToInt(new), + @ptrToInt(newpath), ); } else { return syscall5( SYS_renameat2, @bitCast(usize, @as(isize, oldfd)), - @ptrToInt(old), + @ptrToInt(oldpath), @bitCast(usize, @as(isize, newfd)), - @ptrToInt(new), + @ptrToInt(newpath), 0, ); } diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index 6c9a1f24b7..f5acb70adb 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -88,6 +88,82 @@ pub fn CreateFileW( return result; } +pub const OpenError = error{ + IsDir, + FileNotFound, + NoDevice, + SharingViolation, + AccessDenied, + PipeBusy, + PathAlreadyExists, + Unexpected, + NameTooLong, +}; + +/// TODO rename to CreateFileW +/// TODO actually we don't need the path parameter to be null terminated +pub fn OpenFileW( + dir: ?HANDLE, + sub_path_w: [*:0]const u16, + sa: ?*SECURITY_ATTRIBUTES, + access_mask: ACCESS_MASK, + creation: ULONG, +) OpenError!HANDLE { + if (sub_path_w[0] == '.' and sub_path_w[1] == 0) { + return error.IsDir; + } + if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) { + return error.IsDir; + } + + var result: HANDLE = undefined; + + const path_len_bytes = math.cast(u16, mem.toSliceConst(u16, sub_path_w).len * 2) catch |err| switch (err) { + error.Overflow => return error.NameTooLong, + }; + var nt_name = UNICODE_STRING{ + .Length = path_len_bytes, + .MaximumLength = path_len_bytes, + .Buffer = @intToPtr([*]u16, @ptrToInt(sub_path_w)), + }; + var attr = OBJECT_ATTRIBUTES{ + .Length = @sizeOf(OBJECT_ATTRIBUTES), + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else dir, + .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. + .ObjectName = &nt_name, + .SecurityDescriptor = if (sa) |ptr| ptr.lpSecurityDescriptor else null, + .SecurityQualityOfService = null, + }; + var io: IO_STATUS_BLOCK = undefined; + const rc = ntdll.NtCreateFile( + &result, + access_mask, + &attr, + &io, + null, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, + creation, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + null, + 0, + ); + switch (rc) { + .SUCCESS => return result, + .OBJECT_NAME_INVALID => unreachable, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, + .NO_MEDIA_IN_DEVICE => return error.NoDevice, + .INVALID_PARAMETER => unreachable, + .SHARING_VIOLATION => return error.SharingViolation, + .ACCESS_DENIED => return error.AccessDenied, + .PIPE_BUSY => return error.PipeBusy, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + .OBJECT_NAME_COLLISION => return error.PathAlreadyExists, + else => return unexpectedStatus(rc), + } +} + pub const CreatePipeError = error{Unexpected}; pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void { diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index 1e49b903cb..16cc6d7441 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -242,6 +242,13 @@ pub const FILE_NAME_INFORMATION = extern struct { FileName: [1]WCHAR, }; +pub const FILE_RENAME_INFORMATION = extern struct { + ReplaceIfExists: BOOLEAN, + RootDirectory: ?HANDLE, + FileNameLength: ULONG, + FileName: [1]WCHAR, +}; + pub const IO_STATUS_BLOCK = extern struct { // "DUMMYUNIONNAME" expands to "u" u: extern union { diff --git a/src/main.cpp b/src/main.cpp index 66138dd049..06d132da8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1290,6 +1290,7 @@ static int main0(int argc, char **argv) { if (g->enable_cache) { #if defined(ZIG_OS_WINDOWS) buf_replace(&g->bin_file_output_path, '/', '\\'); + buf_replace(g->output_dir, '/', '\\'); #endif if (final_output_dir_step != nullptr) { Buf *dest_basename = buf_alloc(); @@ -1303,7 +1304,7 @@ static int main0(int argc, char **argv) { return main_exit(root_progress_node, EXIT_FAILURE); } } else { - if (g->emit_bin && printf("%s\n", buf_ptr(&g->bin_file_output_path)) < 0) + if (printf("%s\n", buf_ptr(g->output_dir)) < 0) return main_exit(root_progress_node, EXIT_FAILURE); } } From 66d7370facc63648eb85fb7f1b94753ab0823ff3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 13 Mar 2020 23:59:36 -0400 Subject: [PATCH 05/79] special case when doing build-obj with just one source file When building an object file from only one source file, instead of having a two-stage cache system, we special case it and use the cache directory that the .o file is output to as the final cache directory for all the build artifacts. When there are more than 1 source file, the linker has to merge objects into one, and so the two stage approach makes sens. But in the case of only one source file, this prevents needlessly copying the object file. This commit fixes an issue with the previous one, where zig with cache enabled would print a directory that actually did not have any build artifacts in it. --- src/codegen.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index aba8a49032..924ea9baa6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -10482,10 +10482,6 @@ static void resolve_out_paths(CodeGen *g) { case OutTypeUnknown: zig_unreachable(); case OutTypeObj: - if (g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g)) { - buf_init_from_buf(&g->bin_file_output_path, g->link_objects.at(0)); - return; - } if (need_llvm_module(g) && g->link_objects.length != 0 && !g->enable_cache && buf_eql_buf(o_basename, out_basename)) { @@ -10580,6 +10576,20 @@ static void output_type_information(CodeGen *g) { } } +static bool main_output_dir_is_just_one_c_object(CodeGen *g) { + return g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g); +} + +static void init_output_dir(CodeGen *g, Buf *digest) { + if (main_output_dir_is_just_one_c_object(g)) { + g->output_dir = buf_alloc(); + os_path_dirname(g->link_objects.at(0), g->output_dir); + } else { + g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", + buf_ptr(g->cache_dir), buf_ptr(digest)); + } +} + void codegen_build_and_link(CodeGen *g) { Error err; assert(g->out_type != OutTypeUnknown); @@ -10622,8 +10632,7 @@ void codegen_build_and_link(CodeGen *g) { } if (g->enable_cache && buf_len(&digest) != 0) { - g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", - buf_ptr(g->cache_dir), buf_ptr(&digest)); + init_output_dir(g, &digest); resolve_out_paths(g); } else { if (need_llvm_module(g)) { @@ -10644,8 +10653,7 @@ void codegen_build_and_link(CodeGen *g) { exit(1); } } - g->output_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR OS_SEP "%s", - buf_ptr(g->cache_dir), buf_ptr(&digest)); + init_output_dir(g, &digest); if ((err = os_make_path(g->output_dir))) { fprintf(stderr, "Unable to create output directory: %s\n", err_str(err)); From faa3c40b542f7e6f4d98e8ca542bb47dd603e358 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 14 Mar 2020 00:46:40 -0400 Subject: [PATCH 06/79] fix docgen, which relied on stdout being path to binary --- doc/docgen.zig | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 4d2625f54f..4b9b94dbe4 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -1096,6 +1096,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var try build_args.append("-lc"); try out.print(" -lc", .{}); } + const target = try std.zig.CrossTarget.parse(.{ + .arch_os_abi = code.target_str orelse "native", + }); if (code.target_str) |triple| { try build_args.appendSlice(&[_][]const u8{ "-target", triple }); if (!code.is_inline) { @@ -1150,7 +1153,15 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } } - const path_to_exe = mem.trim(u8, exec_result.stdout, " \r\n"); + const path_to_exe_dir = mem.trim(u8, exec_result.stdout, " \r\n"); + const path_to_exe_basename = try std.fmt.allocPrint(allocator, "{}{}", .{ + code.name, + target.exeFileExt(), + }); + const path_to_exe = try fs.path.join(allocator, &[_][]const u8{ + path_to_exe_dir, + path_to_exe_basename, + }); const run_args = &[_][]const u8{path_to_exe}; var exited_with_signal = false; @@ -1486,7 +1497,12 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var } fn exec(allocator: *mem.Allocator, env_map: *std.BufMap, args: []const []const u8) !ChildProcess.ExecResult { - const result = try ChildProcess.exec(allocator, args, null, env_map, max_doc_file_size); + const result = try ChildProcess.exec2(.{ + .allocator = allocator, + .argv = args, + .env_map = env_map, + .max_output_bytes = max_doc_file_size, + }); switch (result.term) { .Exited => |exit_code| { if (exit_code != 0) { From 4a8e766ef5d0c98b27ffad7907c6ce30c54a1ba8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 14 Mar 2020 01:26:49 -0400 Subject: [PATCH 07/79] fix mismatch between expected and actual output name --- src/link.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/link.cpp b/src/link.cpp index 5b6d3a4fdb..3f7772bb08 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -566,6 +566,7 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil Stage2ProgressNode *progress_node) { CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr, name, progress_node); + child_gen->root_out_name = buf_create_from_str(name); ZigList c_source_files = {0}; c_source_files.append(c_file); child_gen->c_source_files = c_source_files; From a77386eb9847a121bc15af33e5a40bd62f3a67e5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 14 Mar 2020 17:11:51 -0400 Subject: [PATCH 08/79] for build-obj with only 1 C file, name .o file after root_out_name --- src/codegen.cpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 924ea9baa6..dc6fe04cb4 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9650,6 +9650,21 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose return ErrorNone; } +static bool need_llvm_module(CodeGen *g) { + return buf_len(&g->main_pkg->root_src_path) != 0; +} + +// before gen_c_objects +static bool main_output_dir_is_just_one_c_object_pre(CodeGen *g) { + return g->enable_cache && g->c_source_files.length == 1 && !need_llvm_module(g) && + g->out_type == OutTypeObj && g->link_objects.length == 0; +} + +// after gen_c_objects +static bool main_output_dir_is_just_one_c_object_post(CodeGen *g) { + return g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g) && g->out_type == OutTypeObj; +} + // returns true if it was a cache miss static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { Error err; @@ -9667,7 +9682,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { buf_len(c_source_basename), 0); Buf *final_o_basename = buf_alloc(); - os_path_extname(c_source_basename, final_o_basename, nullptr); + // We special case when doing build-obj for just one C file + if (main_output_dir_is_just_one_c_object_pre(g)) { + buf_init_from_buf(final_o_basename, g->root_out_name); + } else { + os_path_extname(c_source_basename, final_o_basename, nullptr); + } buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); CacheHash *cache_hash; @@ -10467,10 +10487,6 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { return ErrorNone; } -static bool need_llvm_module(CodeGen *g) { - return buf_len(&g->main_pkg->root_src_path) != 0; -} - static void resolve_out_paths(CodeGen *g) { assert(g->output_dir != nullptr); assert(g->root_out_name != nullptr); @@ -10576,12 +10592,8 @@ static void output_type_information(CodeGen *g) { } } -static bool main_output_dir_is_just_one_c_object(CodeGen *g) { - return g->enable_cache && g->link_objects.length == 1 && !need_llvm_module(g); -} - static void init_output_dir(CodeGen *g, Buf *digest) { - if (main_output_dir_is_just_one_c_object(g)) { + if (main_output_dir_is_just_one_c_object_post(g)) { g->output_dir = buf_alloc(); os_path_dirname(g->link_objects.at(0), g->output_dir); } else { From 5e5dee829dd0098e00821d2717841950957ebb96 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Mar 2020 01:02:33 +0200 Subject: [PATCH 09/79] remove .Cancel correct merge err set parsing --- lib/std/zig/ast.zig | 2 -- lib/std/zig/parse.zig | 2 +- lib/std/zig/render.zig | 1 - 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 8ae219a998..e87d62b73c 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1591,7 +1591,6 @@ pub const Node = struct { Await, BitNot, BoolNot, - Cancel, OptionalType, Negation, NegationWrap, @@ -1661,7 +1660,6 @@ pub const Node = struct { Op.Await, Op.BitNot, Op.BoolNot, - Op.Cancel, Op.OptionalType, Op.Negation, Op.NegationWrap, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 9a574c6231..dbaff44415 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -2181,7 +2181,7 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = nextToken(it); const op = switch (token.ptr.id) { - .PipePipe => ops{ .BoolOr = {} }, + .PipePipe => ops{ .MergeErrorSets = {} }, .Asterisk => ops{ .Mul = {} }, .Slash => ops{ .Div = {} }, .Percent => ops{ .Mod = {} }, diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 1a221bd5b3..a3a72fb23f 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -583,7 +583,6 @@ fn renderExpression( }, .Try, - .Cancel, .Resume, => { try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.Space); From 57f9f0755814ab4170b6f770510fe3fb8db2c1e3 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 15 Mar 2020 01:07:01 +0200 Subject: [PATCH 10/79] use anon literals in ast.zig and parse.zig --- lib/std/zig/ast.zig | 156 ++++------ lib/std/zig/parse.zig | 687 +++++++++++++++++++++--------------------- 2 files changed, 402 insertions(+), 441 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index e87d62b73c..8caaad2d4f 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -740,11 +740,11 @@ pub const Node = struct { var i = index; switch (self.init_arg_expr) { - InitArg.Type => |t| { + .Type => |t| { if (i < 1) return t; i -= 1; }, - InitArg.None, InitArg.Enum => {}, + .None, .Enum => {}, } if (i < self.fields_and_decls.len) return self.fields_and_decls.at(i).*; @@ -904,12 +904,7 @@ pub const Node = struct { } switch (self.return_type) { - // TODO allow this and next prong to share bodies since the types are the same - ReturnType.Explicit => |node| { - if (i < 1) return node; - i -= 1; - }, - ReturnType.InferErrorSet => |node| { + .Explicit, .InferErrorSet => |node| { if (i < 1) return node; i -= 1; }, @@ -934,9 +929,7 @@ pub const Node = struct { pub fn lastToken(self: *const FnProto) TokenIndex { if (self.body_node) |body_node| return body_node.lastToken(); switch (self.return_type) { - // TODO allow this and next prong to share bodies since the types are the same - ReturnType.Explicit => |node| return node.lastToken(), - ReturnType.InferErrorSet => |node| return node.lastToken(), + .Explicit, .InferErrorSet => |node| return node.lastToken(), } } }; @@ -1512,55 +1505,55 @@ pub const Node = struct { i -= 1; switch (self.op) { - Op.Catch => |maybe_payload| { + .Catch => |maybe_payload| { if (maybe_payload) |payload| { if (i < 1) return payload; i -= 1; } }, - Op.Add, - Op.AddWrap, - Op.ArrayCat, - Op.ArrayMult, - Op.Assign, - Op.AssignBitAnd, - Op.AssignBitOr, - Op.AssignBitShiftLeft, - Op.AssignBitShiftRight, - Op.AssignBitXor, - Op.AssignDiv, - Op.AssignSub, - Op.AssignSubWrap, - Op.AssignMod, - Op.AssignAdd, - Op.AssignAddWrap, - Op.AssignMul, - Op.AssignMulWrap, - Op.BangEqual, - Op.BitAnd, - Op.BitOr, - Op.BitShiftLeft, - Op.BitShiftRight, - Op.BitXor, - Op.BoolAnd, - Op.BoolOr, - Op.Div, - Op.EqualEqual, - Op.ErrorUnion, - Op.GreaterOrEqual, - Op.GreaterThan, - Op.LessOrEqual, - Op.LessThan, - Op.MergeErrorSets, - Op.Mod, - Op.Mul, - Op.MulWrap, - Op.Period, - Op.Range, - Op.Sub, - Op.SubWrap, - Op.UnwrapOptional, + .Add, + .AddWrap, + .ArrayCat, + .ArrayMult, + .Assign, + .AssignBitAnd, + .AssignBitOr, + .AssignBitShiftLeft, + .AssignBitShiftRight, + .AssignBitXor, + .AssignDiv, + .AssignSub, + .AssignSubWrap, + .AssignMod, + .AssignAdd, + .AssignAddWrap, + .AssignMul, + .AssignMulWrap, + .BangEqual, + .BitAnd, + .BitOr, + .BitShiftLeft, + .BitShiftRight, + .BitXor, + .BoolAnd, + .BoolOr, + .Div, + .EqualEqual, + .ErrorUnion, + .GreaterOrEqual, + .GreaterThan, + .LessOrEqual, + .LessThan, + .MergeErrorSets, + .Mod, + .Mul, + .MulWrap, + .Period, + .Range, + .Sub, + .SubWrap, + .UnwrapOptional, => {}, } @@ -1627,8 +1620,7 @@ pub const Node = struct { var i = index; switch (self.op) { - // TODO https://github.com/ziglang/zig/issues/1107 - Op.SliceType => |addr_of_info| { + .PtrType, .SliceType => |addr_of_info| { if (addr_of_info.sentinel) |sentinel| { if (i < 1) return sentinel; i -= 1; @@ -1640,14 +1632,7 @@ pub const Node = struct { } }, - Op.PtrType => |addr_of_info| { - if (addr_of_info.align_info) |align_info| { - if (i < 1) return align_info.node; - i -= 1; - } - }, - - Op.ArrayType => |array_info| { + .ArrayType => |array_info| { if (i < 1) return array_info.len_expr; i -= 1; if (array_info.sentinel) |sentinel| { @@ -1656,15 +1641,15 @@ pub const Node = struct { } }, - Op.AddressOf, - Op.Await, - Op.BitNot, - Op.BoolNot, - Op.OptionalType, - Op.Negation, - Op.NegationWrap, - Op.Try, - Op.Resume, + .AddressOf, + .Await, + .BitNot, + .BoolNot, + .OptionalType, + .Negation, + .NegationWrap, + .Try, + .Resume, => {}, } @@ -1848,19 +1833,14 @@ pub const Node = struct { var i = index; switch (self.kind) { - Kind.Break => |maybe_label| { + .Break, + .Continue => |maybe_label| { if (maybe_label) |label| { if (i < 1) return label; i -= 1; } }, - Kind.Continue => |maybe_label| { - if (maybe_label) |label| { - if (i < 1) return label; - i -= 1; - } - }, - Kind.Return => {}, + .Return => {}, } if (self.rhs) |rhs| { @@ -1881,17 +1861,13 @@ pub const Node = struct { } switch (self.kind) { - Kind.Break => |maybe_label| { + .Break, + .Continue => |maybe_label| { if (maybe_label) |label| { return label.lastToken(); } }, - Kind.Continue => |maybe_label| { - if (maybe_label) |label| { - return label.lastToken(); - } - }, - Kind.Return => return self.ltoken, + .Return => return self.ltoken, } return self.ltoken; @@ -2132,11 +2108,11 @@ pub const Node = struct { i -= 1; switch (self.kind) { - Kind.Variable => |variable_name| { + .Variable => |variable_name| { if (i < 1) return &variable_name.base; i -= 1; }, - Kind.Return => |return_type| { + .Return => |return_type| { if (i < 1) return return_type; i -= 1; }, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index dbaff44415..b0c3e6d759 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -23,7 +23,7 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { var arena = std.heap.ArenaAllocator.init(allocator); errdefer arena.deinit(); const tree = try arena.allocator.create(ast.Tree); - tree.* = ast.Tree{ + tree.* = .{ .source = source, .root_node = undefined, .arena_allocator = arena, @@ -66,10 +66,10 @@ pub fn parse(allocator: *Allocator, source: []const u8) Allocator.Error!*Tree { /// Root <- skip ContainerMembers eof fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!*Node.Root { const node = try arena.create(Node.Root); - node.* = Node.Root{ + node.* = .{ .decls = try parseContainerMembers(arena, it, tree), .eof_token = eatToken(it, .Eof) orelse { - try tree.errors.push(AstError{ + try tree.errors.push(.{ .ExpectedContainerMembers = .{ .token = it.index }, }); return error.ParseError; @@ -139,8 +139,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No } if (visib_token != null) { - try tree.errors.push(AstError{ - .ExpectedPubItem = AstError.ExpectedPubItem{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedPubItem = .{ .token = it.index }, }); return error.ParseError; } @@ -157,8 +157,8 @@ fn parseContainerMembers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !No // Dangling doc comment if (doc_comments != null) { - try tree.errors.push(AstError{ - .UnattachedDocComment = AstError.UnattachedDocComment{ .token = doc_comments.?.firstToken() }, + try tree.errors.push(.{ + .UnattachedDocComment = .{ .token = doc_comments.?.firstToken() }, }); } break; @@ -177,7 +177,7 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) if (lines.len == 0) return null; const node = try arena.create(Node.DocComment); - node.* = Node.DocComment{ + node.* = .{ .lines = lines, }; return &node.base; @@ -186,15 +186,15 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const test_token = eatToken(it, .Keyword_test) orelse return null; - const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, AstError{ - .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, + const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, .{ + .ExpectedStringLiteral = .{ .token = it.index }, }); - const block_node = try expectNode(arena, it, tree, parseBlock, AstError{ - .ExpectedLBrace = AstError.ExpectedLBrace{ .token = it.index }, + const block_node = try expectNode(arena, it, tree, parseBlock, .{ + .ExpectedLBrace = .{ .token = it.index }, }); const test_node = try arena.create(Node.TestDecl); - test_node.* = Node.TestDecl{ + test_node.* = .{ .doc_comments = null, .test_token = test_token, .name = name_node, @@ -211,12 +211,12 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* return null; }; putBackToken(it, lbrace); - const block_node = try expectNode(arena, it, tree, parseBlockExpr, AstError{ - .ExpectedLabelOrLBrace = AstError.ExpectedLabelOrLBrace{ .token = it.index }, + const block_node = try expectNode(arena, it, tree, parseBlockExpr, .{ + .ExpectedLabelOrLBrace = .{ .token = it.index }, }); const comptime_node = try arena.create(Node.Comptime); - comptime_node.* = Node.Comptime{ + comptime_node.* = .{ .doc_comments = null, .comptime_token = tok, .expr = block_node, @@ -250,8 +250,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn_node.body_node = body_node; return node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrLBrace = AstError.ExpectedSemiOrLBrace{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrLBrace = .{ .token = it.index }, }); return null; } @@ -277,8 +277,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (thread_local_token != null) { - try tree.errors.push(AstError{ - .ExpectedVarDecl = AstError.ExpectedVarDecl{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedVarDecl = .{ .token = it.index }, }); return error.ParseError; } @@ -291,8 +291,8 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } const use_node = (try parseUse(arena, it, tree)) orelse return null; - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const semicolon_token = try expectToken(it, tree, .Semicolon); const use_node_raw = use_node.cast(Node.Use).?; @@ -310,7 +310,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (fnCC == .Extern) { putBackToken(it, fnCC.Extern); // 'extern' is also used in ContainerDecl } else { - try tree.errors.push(AstError{ + try tree.errors.push(.{ .ExpectedToken = .{ .token = it.index, .expected_id = .Keyword_fn }, }); return error.ParseError; @@ -328,16 +328,16 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const exclamation_token = eatToken(it, .Bang); const return_type_expr = (try parseVarType(arena, it, tree)) orelse - try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedReturnType = AstError.ExpectedReturnType{ .token = it.index }, + try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedReturnType = .{ .token = it.index }, }); - const return_type = if (exclamation_token != null) - Node.FnProto.ReturnType{ + const return_type: Node.FnProto.ReturnType = if (exclamation_token != null) + .{ .InferErrorSet = return_type_expr, } else - Node.FnProto.ReturnType{ + .{ .Explicit = return_type_expr, }; @@ -347,7 +347,7 @@ fn parseFnProto(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { null; const fn_proto_node = try arena.create(Node.FnProto); - fn_proto_node.* = Node.FnProto{ + fn_proto_node.* = .{ .doc_comments = null, .visib_token = null, .fn_token = fn_token, @@ -382,8 +382,8 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const name_token = try expectToken(it, tree, .Identifier); const type_node = if (eatToken(it, .Colon) != null) - try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }) else null; @@ -391,14 +391,14 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const section_node = try parseLinkSection(arena, it, tree); const eq_token = eatToken(it, .Equal); const init_node = if (eq_token != null) blk: { - break :blk try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + break :blk try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); } else null; const semicolon_token = try expectToken(it, tree, .Semicolon); const node = try arena.create(Node.VarDecl); - node.* = Node.VarDecl{ + node.* = .{ .doc_comments = null, .visib_token = null, .thread_local_token = null, @@ -433,22 +433,22 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No node.* = .{ .token = var_tok }; type_expr = &node.base; } else { - type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); align_expr = try parseByteAlign(arena, it, tree); } } const value_expr = if (eatToken(it, .Equal)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }) else null; const node = try arena.create(Node.ContainerField); - node.* = Node.ContainerField{ + node.* = .{ .doc_comments = null, .comptime_token = comptime_token, .name_token = name_token, @@ -481,12 +481,12 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No } if (comptime_token) |token| { - const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ - .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, + const block_expr = try expectNode(arena, it, tree, parseBlockExprStatement, .{ + .ExpectedBlockOrAssignment = .{ .token = it.index }, }); const node = try arena.create(Node.Comptime); - node.* = Node.Comptime{ + node.* = .{ .doc_comments = null, .comptime_token = token, .expr = block_expr, @@ -511,13 +511,13 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const semicolon = eatToken(it, .Semicolon); const body_node = if (semicolon == null) blk: { - break :blk try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ - .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, + break :blk try expectNode(arena, it, tree, parseBlockExprStatement, .{ + .ExpectedBlockOrExpression = .{ .token = it.index }, }); } else null; const node = try arena.create(Node.Suspend); - node.* = Node.Suspend{ + node.* = .{ .suspend_token = suspend_token, .body = body_node, }; @@ -526,11 +526,11 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); if (defer_token) |token| { - const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, AstError{ - .ExpectedBlockOrExpression = AstError.ExpectedBlockOrExpression{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{ + .ExpectedBlockOrExpression = .{ .token = it.index }, }); const node = try arena.create(Node.Defer); - node.* = Node.Defer{ + node.* = .{ .defer_token = token, .expr = expr_node, }; @@ -561,8 +561,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } else null; if (block_expr == null and assign_expr == null) { - try tree.errors.push(AstError{ - .ExpectedBlockOrAssignment = AstError.ExpectedBlockOrAssignment{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedBlockOrAssignment = .{ .token = it.index }, }); return error.ParseError; } @@ -572,12 +572,12 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const else_node = if (semicolon == null) blk: { const else_token = eatToken(it, .Keyword_else) orelse break :blk null; const payload = try parsePayload(arena, it, tree); - const else_body = try expectNode(arena, it, tree, parseStatement, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const else_body = try expectNode(arena, it, tree, parseStatement, .{ + .InvalidToken = .{ .token = it.index }, }); const node = try arena.create(Node.Else); - node.* = Node.Else{ + node.* = .{ .else_token = else_token, .payload = payload, .body = else_body, @@ -599,8 +599,8 @@ fn parseIfStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if_prefix.@"else" = else_node; return if_node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrElse = .{ .token = it.index }, }); return error.ParseError; } @@ -628,8 +628,8 @@ fn parseLabeledStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* } if (label_token != null) { - try tree.errors.push(AstError{ - .ExpectedLabelable = AstError.ExpectedLabelable{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedLabelable = .{ .token = it.index }, }); return error.ParseError; } @@ -665,12 +665,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node for_prefix.body = block_expr_node; if (eatToken(it, .Keyword_else)) |else_token| { - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .InvalidToken = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = statement_node, @@ -689,12 +689,12 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (eatToken(it, .Semicolon) != null) return node; if (eatToken(it, .Keyword_else)) |else_token| { - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .ExpectedStatement = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = statement_node, @@ -703,8 +703,8 @@ fn parseForStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrElse = .{ .token = it.index }, }); return null; } @@ -725,12 +725,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .InvalidToken = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = statement_node, @@ -751,12 +751,12 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const statement_node = try expectNode(arena, it, tree, parseStatement, AstError{ - .ExpectedStatement = AstError.ExpectedStatement{ .token = it.index }, + const statement_node = try expectNode(arena, it, tree, parseStatement, .{ + .ExpectedStatement = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = statement_node, @@ -765,8 +765,8 @@ fn parseWhileStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No return node; } - try tree.errors.push(AstError{ - .ExpectedSemiOrElse = AstError.ExpectedSemiOrElse{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSemiOrElse = .{ .token = it.index }, }); return null; } @@ -894,8 +894,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_comptime)) |token| { - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.Comptime); node.* = .{ @@ -907,8 +907,8 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_noasync)) |token| { - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.Noasync); node.* = .{ @@ -930,13 +930,13 @@ fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_resume)) |token| { - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.PrefixOp); node.* = .{ .op_token = token, - .op = Node.PrefixOp.Op.Resume, + .op = .Resume, .rhs = expr_node, }; return &node.base; @@ -992,7 +992,7 @@ fn parseBlock(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const rbrace = try expectToken(it, tree, .RBrace); const block_node = try arena.create(Node.Block); - block_node.* = Node.Block{ + block_node.* = .{ .label = null, .lbrace = lbrace, .statements = statements, @@ -1019,8 +1019,8 @@ fn parseLoopExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (inline_token == null) return null; // If we've seen "inline", there should have been a "for" or "while" - try tree.errors.push(AstError{ - .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedInlinable = .{ .token = it.index }, }); return error.ParseError; } @@ -1030,18 +1030,18 @@ fn parseForExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = (try parseForPrefix(arena, it, tree)) orelse return null; const for_prefix = node.cast(Node.For).?; - const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); for_prefix.body = body_node; if (eatToken(it, .Keyword_else)) |else_token| { - const body = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = body, @@ -1058,19 +1058,19 @@ fn parseWhileExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; const while_prefix = node.cast(Node.While).?; - const body_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); while_prefix.body = body_node; if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const body = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const body = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = body, @@ -1098,14 +1098,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf const lbrace = eatToken(it, .LBrace) orelse return null; var init_list = Node.SuffixOp.Op.InitList.init(arena); - const op = blk: { + const op: Node.SuffixOp.Op = blk: { if (try parseFieldInit(arena, it, tree)) |field_init| { try init_list.push(field_init); while (eatToken(it, .Comma)) |_| { const next = (try parseFieldInit(arena, it, tree)) orelse break; try init_list.push(next); } - break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; + break :blk .{ .StructInitializer = init_list }; } if (try parseExpr(arena, it, tree)) |expr| { @@ -1114,14 +1114,14 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf const next = (try parseExpr(arena, it, tree)) orelse break; try init_list.push(next); } - break :blk Node.SuffixOp.Op{ .ArrayInitializer = init_list }; + break :blk .{ .ArrayInitializer = init_list }; } - break :blk Node.SuffixOp.Op{ .StructInitializer = init_list }; + break :blk .{ .StructInitializer = init_list }; }; const node = try arena.create(Node.SuffixOp); - node.* = Node.SuffixOp{ + node.* = .{ .lhs = .{ .node = undefined }, // set by caller .op = op, .rtoken = try expectToken(it, tree, .RBrace), @@ -1140,8 +1140,8 @@ fn parseErrorUnionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No if (try SimpleBinOpParseFn(.Bang, Node.InfixOp.Op.ErrorUnion)(arena, it, tree)) |node| { const error_union = node.cast(Node.InfixOp).?; - const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); error_union.lhs = suffix_expr; error_union.rhs = type_expr; @@ -1168,8 +1168,8 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { return parsePrimaryTypeExpr(arena, it, tree); } // TODO: Implement hack for parsing `async fn ...` in ast_parse_suffix_expr - var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, AstError{ - .ExpectedPrimaryTypeExpr = AstError.ExpectedPrimaryTypeExpr{ .token = it.index }, + var res = try expectNode(arena, it, tree, parsePrimaryTypeExpr, .{ + .ExpectedPrimaryTypeExpr = .{ .token = it.index }, }); while (try parseSuffixOp(arena, it, tree)) |node| { @@ -1182,16 +1182,16 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } const params = (try parseFnCallArguments(arena, it, tree)) orelse { - try tree.errors.push(AstError{ - .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedParamList = .{ .token = it.index }, }); return null; }; const node = try arena.create(Node.SuffixOp); - node.* = Node.SuffixOp{ + node.* = .{ .lhs = .{ .node = res }, - .op = Node.SuffixOp.Op{ - .Call = Node.SuffixOp.Op.Call{ + .op = .{ + .Call = .{ .params = params.list, .async_token = async_token, }, @@ -1215,10 +1215,10 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } if (try parseFnCallArguments(arena, it, tree)) |params| { const call = try arena.create(Node.SuffixOp); - call.* = Node.SuffixOp{ + call.* = .{ .lhs = .{ .node = res }, - .op = Node.SuffixOp.Op{ - .Call = Node.SuffixOp.Op.Call{ + .op = .{ + .Call = .{ .params = params.list, .async_token = null, }, @@ -1264,7 +1264,7 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N if (try parseBuiltinCall(arena, it, tree)) |node| return node; if (eatToken(it, .CharLiteral)) |token| { const node = try arena.create(Node.CharLiteral); - node.* = Node.CharLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -1300,15 +1300,15 @@ fn parsePrimaryTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*N } if (eatToken(it, .Keyword_error)) |token| { const period = try expectToken(it, tree, .Period); - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const global_error_set = try createLiteral(arena, Node.ErrorType, token); const node = try arena.create(Node.InfixOp); node.* = .{ .op_token = period, .lhs = global_error_set, - .op = Node.InfixOp.Op.Period, + .op = .Period, .rhs = identifier, }; return &node.base; @@ -1358,7 +1358,7 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const rbrace = try expectToken(it, tree, .RBrace); const node = try arena.create(Node.ErrorSetDecl); - node.* = Node.ErrorSetDecl{ + node.* = .{ .error_token = error_token, .decls = decls, .rbrace_token = rbrace, @@ -1369,13 +1369,13 @@ fn parseErrorSetDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node /// GroupedExpr <- LPAREN Expr RPAREN fn parseGroupedExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lparen = eatToken(it, .LParen) orelse return null; - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const rparen = try expectToken(it, tree, .RParen); const node = try arena.create(Node.GroupedExpression); - node.* = Node.GroupedExpression{ + node.* = .{ .lparen = lparen, .expr = expr, .rparen = rparen, @@ -1435,8 +1435,8 @@ fn parseLoopTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (inline_token == null) return null; // If we've seen "inline", there should have been a "for" or "while" - try tree.errors.push(AstError{ - .ExpectedInlinable = AstError.ExpectedInlinable{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedInlinable = .{ .token = it.index }, }); return error.ParseError; } @@ -1446,18 +1446,18 @@ fn parseForTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = (try parseForPrefix(arena, it, tree)) orelse return null; const for_prefix = node.cast(Node.For).?; - const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); for_prefix.body = type_expr; if (eatToken(it, .Keyword_else)) |else_token| { - const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = else_expr, @@ -1474,20 +1474,20 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod const node = (try parseWhilePrefix(arena, it, tree)) orelse return null; const while_prefix = node.cast(Node.While).?; - const type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const type_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); while_prefix.body = type_expr; if (eatToken(it, .Keyword_else)) |else_token| { const payload = try parsePayload(arena, it, tree); - const else_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const else_expr = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = null, .body = else_expr, @@ -1503,8 +1503,8 @@ fn parseWhileTypeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const switch_token = eatToken(it, .Keyword_switch) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); _ = try expectToken(it, tree, .LBrace); @@ -1512,7 +1512,7 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const rbrace = try expectToken(it, tree, .RBrace); const node = try arena.create(Node.Switch); - node.* = Node.Switch{ + node.* = .{ .switch_token = switch_token, .expr = expr_node, .cases = cases, @@ -1526,12 +1526,12 @@ fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const asm_token = eatToken(it, .Keyword_asm) orelse return null; const volatile_token = eatToken(it, .Keyword_volatile); _ = try expectToken(it, tree, .LParen); - const template = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const template = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.Asm); - node.* = Node.Asm{ + node.* = .{ .asm_token = asm_token, .volatile_token = volatile_token, .template = template, @@ -1553,7 +1553,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node // anon enum literal if (eatToken(it, .Identifier)) |name| { const node = try arena.create(Node.EnumLiteral); - node.* = Node.EnumLiteral{ + node.* = .{ .dot = dot, .name = name, }; @@ -1580,32 +1580,32 @@ fn parseAsmOutput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: /// AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN fn parseAsmOutputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmOutput { const lbracket = eatToken(it, .LBracket) orelse return null; - const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const name = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RBracket); - const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ - .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, + const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ + .ExpectedStringLiteral = .{ .token = it.index }, }); _ = try expectToken(it, tree, .LParen); - const kind = blk: { + const kind: Node.AsmOutput.Kind = blk: { if (eatToken(it, .Arrow) != null) { - const return_ident = try expectNode(arena, it, tree, parseTypeExpr, AstError{ - .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, + const return_ident = try expectNode(arena, it, tree, parseTypeExpr, .{ + .ExpectedTypeExpr = .{ .token = it.index }, }); - break :blk Node.AsmOutput.Kind{ .Return = return_ident }; + break :blk .{ .Return = return_ident }; } - const variable = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const variable = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); - break :blk Node.AsmOutput.Kind{ .Variable = variable.cast(Node.Identifier).? }; + break :blk .{ .Variable = variable.cast(Node.Identifier).? }; }; const rparen = try expectToken(it, tree, .RParen); const node = try arena.create(Node.AsmOutput); - node.* = Node.AsmOutput{ + node.* = .{ .lbracket = lbracket, .symbolic_name = name, .constraint = constraint, @@ -1625,23 +1625,23 @@ fn parseAsmInput(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node: * /// AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN fn parseAsmInputItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.AsmInput { const lbracket = eatToken(it, .LBracket) orelse return null; - const name = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const name = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RBracket); - const constraint = try expectNode(arena, it, tree, parseStringLiteral, AstError{ - .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, + const constraint = try expectNode(arena, it, tree, parseStringLiteral, .{ + .ExpectedStringLiteral = .{ .token = it.index }, }); _ = try expectToken(it, tree, .LParen); - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const rparen = try expectToken(it, tree, .RParen); const node = try arena.create(Node.AsmInput); - node.* = Node.AsmInput{ + node.* = .{ .lbracket = lbracket, .symbolic_name = name, .constraint = constraint, @@ -1664,8 +1664,8 @@ fn parseAsmClobbers(arena: *Allocator, it: *TokenIterator, tree: *Tree, asm_node /// BreakLabel <- COLON IDENTIFIER fn parseBreakLabel(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Colon) orelse return null; - return try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + return try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); } @@ -1694,12 +1694,12 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { putBackToken(it, period_token); return null; }; - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.FieldInitializer); - node.* = Node.FieldInitializer{ + node.* = .{ .period_token = period_token, .name_token = name_token, .expr = expr_node, @@ -1711,8 +1711,8 @@ fn parseFieldInit(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Colon) orelse return null; _ = try expectToken(it, tree, .LParen); - const node = try expectNode(arena, it, tree, parseAssignExpr, AstError{ - .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, + const node = try expectNode(arena, it, tree, parseAssignExpr, .{ + .ExpectedExprOrAssignment = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return node; @@ -1722,8 +1722,8 @@ fn parseWhileContinueExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Keyword_linksection) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return expr_node; @@ -1733,8 +1733,8 @@ fn parseLinkSection(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn parseCallconv(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Keyword_callconv) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return expr_node; @@ -1775,14 +1775,14 @@ fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { comptime_token == null and name_token == null and doc_comments == null) return null; - try tree.errors.push(AstError{ - .ExpectedParamType = AstError.ExpectedParamType{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedParamType = .{ .token = it.index }, }); return error.ParseError; }; const param_decl = try arena.create(Node.ParamDecl); - param_decl.* = Node.ParamDecl{ + param_decl.* = .{ .doc_comments = doc_comments, .comptime_token = comptime_token, .noalias_token = noalias_token, @@ -1821,14 +1821,14 @@ const ParamType = union(enum) { fn parseIfPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const if_token = eatToken(it, .Keyword_if) orelse return null; _ = try expectToken(it, tree, .LParen); - const condition = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const condition = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); const payload = try parsePtrPayload(arena, it, tree); const node = try arena.create(Node.If); - node.* = Node.If{ + node.* = .{ .if_token = if_token, .condition = condition, .payload = payload, @@ -1843,8 +1843,8 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const while_token = eatToken(it, .Keyword_while) orelse return null; _ = try expectToken(it, tree, .LParen); - const condition = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const condition = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); @@ -1852,7 +1852,7 @@ fn parseWhilePrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const continue_expr = try parseWhileContinueExpr(arena, it, tree); const node = try arena.create(Node.While); - node.* = Node.While{ + node.* = .{ .label = null, .inline_token = null, .while_token = while_token, @@ -1870,17 +1870,17 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const for_token = eatToken(it, .Keyword_for) orelse return null; _ = try expectToken(it, tree, .LParen); - const array_expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const array_expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); - const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, AstError{ - .ExpectedPayload = AstError.ExpectedPayload{ .token = it.index }, + const payload = try expectNode(arena, it, tree, parsePtrIndexPayload, .{ + .ExpectedPayload = .{ .token = it.index }, }); const node = try arena.create(Node.For); - node.* = Node.For{ + node.* = .{ .label = null, .inline_token = null, .for_token = for_token, @@ -1895,13 +1895,13 @@ fn parseForPrefix(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// Payload <- PIPE IDENTIFIER PIPE fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lpipe = eatToken(it, .Pipe) orelse return null; - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const rpipe = try expectToken(it, tree, .Pipe); const node = try arena.create(Node.Payload); - node.* = Node.Payload{ + node.* = .{ .lpipe = lpipe, .error_symbol = identifier, .rpipe = rpipe, @@ -1913,13 +1913,13 @@ fn parsePayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lpipe = eatToken(it, .Pipe) orelse return null; const asterisk = eatToken(it, .Asterisk); - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const rpipe = try expectToken(it, tree, .Pipe); const node = try arena.create(Node.PointerPayload); - node.* = Node.PointerPayload{ + node.* = .{ .lpipe = lpipe, .ptr_token = asterisk, .value_symbol = identifier, @@ -1932,21 +1932,21 @@ fn parsePtrPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parsePtrIndexPayload(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lpipe = eatToken(it, .Pipe) orelse return null; const asterisk = eatToken(it, .Asterisk); - const identifier = try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + const identifier = try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const index = if (eatToken(it, .Comma) == null) null else - try expectNode(arena, it, tree, parseIdentifier, AstError{ - .ExpectedIdentifier = AstError.ExpectedIdentifier{ .token = it.index }, + try expectNode(arena, it, tree, parseIdentifier, .{ + .ExpectedIdentifier = .{ .token = it.index }, }); const rpipe = try expectToken(it, tree, .Pipe); const node = try arena.create(Node.PointerIndexPayload); - node.* = Node.PointerIndexPayload{ + node.* = .{ .lpipe = lpipe, .ptr_token = asterisk, .value_symbol = identifier, @@ -1961,8 +1961,8 @@ fn parseSwitchProng(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node const node = (try parseSwitchCase(arena, it, tree)) orelse return null; const arrow = try expectToken(it, tree, .EqualAngleBracketRight); const payload = try parsePtrPayload(arena, it, tree); - const expr = try expectNode(arena, it, tree, parseAssignExpr, AstError{ - .ExpectedExprOrAssignment = AstError.ExpectedExprOrAssignment{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseAssignExpr, .{ + .ExpectedExprOrAssignment = .{ .token = it.index }, }); const switch_case = node.cast(Node.SwitchCase).?; @@ -1987,14 +1987,14 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { } } else if (eatToken(it, .Keyword_else)) |else_token| { const else_node = try arena.create(Node.SwitchElse); - else_node.* = Node.SwitchElse{ + else_node.* = .{ .token = else_token, }; try list.push(&else_node.base); } else return null; const node = try arena.create(Node.SwitchCase); - node.* = Node.SwitchCase{ + node.* = .{ .items = list, .arrow_token = undefined, // set by caller .payload = null, @@ -2007,15 +2007,15 @@ fn parseSwitchCase(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const expr = (try parseExpr(arena, it, tree)) orelse return null; if (eatToken(it, .Ellipsis3)) |token| { - const range_end = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const range_end = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = token, .lhs = expr, - .op = Node.InfixOp.Op{ .Range = {} }, + .op = .Range, .rhs = range_end, }; return &node.base; @@ -2039,24 +2039,22 @@ fn parseSwitchItem(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / MINUSPERCENTEQUAL /// / EQUAL fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const Op = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .AsteriskEqual => Op{ .AssignMul = {} }, - .SlashEqual => Op{ .AssignDiv = {} }, - .PercentEqual => Op{ .AssignMod = {} }, - .PlusEqual => Op{ .AssignAdd = {} }, - .MinusEqual => Op{ .AssignSub = {} }, - .AngleBracketAngleBracketLeftEqual => Op{ .AssignBitShiftLeft = {} }, - .AngleBracketAngleBracketRightEqual => Op{ .AssignBitShiftRight = {} }, - .AmpersandEqual => Op{ .AssignBitAnd = {} }, - .CaretEqual => Op{ .AssignBitXor = {} }, - .PipeEqual => Op{ .AssignBitOr = {} }, - .AsteriskPercentEqual => Op{ .AssignMulWrap = {} }, - .PlusPercentEqual => Op{ .AssignAddWrap = {} }, - .MinusPercentEqual => Op{ .AssignSubWrap = {} }, - .Equal => Op{ .Assign = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .AsteriskEqual => .AssignMul, + .SlashEqual => .AssignDiv, + .PercentEqual => .AssignMod, + .PlusEqual => .AssignAdd, + .MinusEqual => .AssignSub, + .AngleBracketAngleBracketLeftEqual => .AssignBitShiftLeft, + .AngleBracketAngleBracketRightEqual => .AssignBitShiftRight, + .AmpersandEqual => .AssignBitAnd, + .CaretEqual => .AssignBitXor, + .PipeEqual => .AssignBitOr, + .AsteriskPercentEqual => .AssignMulWrap, + .PlusPercentEqual => .AssignAddWrap, + .MinusPercentEqual => .AssignSubWrap, + .Equal => .Assign, else => { putBackToken(it, token.index); return null; @@ -2064,7 +2062,7 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = token.index, .lhs = undefined, // set by caller .op = op, @@ -2081,16 +2079,14 @@ fn parseAssignOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / LARROWEQUAL /// / RARROWEQUAL fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .EqualEqual => ops{ .EqualEqual = {} }, - .BangEqual => ops{ .BangEqual = {} }, - .AngleBracketLeft => ops{ .LessThan = {} }, - .AngleBracketRight => ops{ .GreaterThan = {} }, - .AngleBracketLeftEqual => ops{ .LessOrEqual = {} }, - .AngleBracketRightEqual => ops{ .GreaterOrEqual = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .EqualEqual => .EqualEqual, + .BangEqual => .BangEqual, + .AngleBracketLeft => .LessThan, + .AngleBracketRight => .GreaterThan, + .AngleBracketLeftEqual => .LessOrEqual, + .AngleBracketRightEqual => .GreaterOrEqual, else => { putBackToken(it, token.index); return null; @@ -2107,15 +2103,13 @@ fn parseCompareOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / KEYWORD_orelse /// / KEYWORD_catch Payload? fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .Ampersand => ops{ .BitAnd = {} }, - .Caret => ops{ .BitXor = {} }, - .Pipe => ops{ .BitOr = {} }, - .Keyword_orelse => ops{ .UnwrapOptional = {} }, - .Keyword_catch => ops{ .Catch = try parsePayload(arena, it, tree) }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .Ampersand => .BitAnd, + .Caret => .BitXor, + .Pipe => .BitOr, + .Keyword_orelse => .UnwrapOptional, + .Keyword_catch => .{ .Catch = try parsePayload(arena, it, tree) }, else => { putBackToken(it, token.index); return null; @@ -2129,12 +2123,10 @@ fn parseBitwiseOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// <- LARROW2 /// / RARROW2 fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .AngleBracketAngleBracketLeft => ops{ .BitShiftLeft = {} }, - .AngleBracketAngleBracketRight => ops{ .BitShiftRight = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .AngleBracketAngleBracketLeft => .BitShiftLeft, + .AngleBracketAngleBracketRight => .BitShiftRight, else => { putBackToken(it, token.index); return null; @@ -2151,15 +2143,13 @@ fn parseBitShiftOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / PLUSPERCENT /// / MINUSPERCENT fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .Plus => ops{ .Add = {} }, - .Minus => ops{ .Sub = {} }, - .PlusPlus => ops{ .ArrayCat = {} }, - .PlusPercent => ops{ .AddWrap = {} }, - .MinusPercent => ops{ .SubWrap = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .Plus => .Add, + .Minus => .Sub, + .PlusPlus => .ArrayCat, + .PlusPercent => .AddWrap, + .MinusPercent => .SubWrap, else => { putBackToken(it, token.index); return null; @@ -2177,16 +2167,14 @@ fn parseAdditionOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / ASTERISK2 /// / ASTERISKPERCENT fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.InfixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .PipePipe => ops{ .MergeErrorSets = {} }, - .Asterisk => ops{ .Mul = {} }, - .Slash => ops{ .Div = {} }, - .Percent => ops{ .Mod = {} }, - .AsteriskAsterisk => ops{ .ArrayMult = {} }, - .AsteriskPercent => ops{ .MulWrap = {} }, + const op: Node.InfixOp.Op = switch (token.ptr.id) { + .PipePipe => .MergeErrorSets, + .Asterisk => .Mul, + .Slash => .Div, + .Percent => .Mod, + .AsteriskAsterisk => .ArrayMult, + .AsteriskPercent => .MulWrap, else => { putBackToken(it, token.index); return null; @@ -2205,17 +2193,15 @@ fn parseMultiplyOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { /// / KEYWORD_try /// / KEYWORD_await fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const ops = Node.PrefixOp.Op; - const token = nextToken(it); - const op = switch (token.ptr.id) { - .Bang => ops{ .BoolNot = {} }, - .Minus => ops{ .Negation = {} }, - .Tilde => ops{ .BitNot = {} }, - .MinusPercent => ops{ .NegationWrap = {} }, - .Ampersand => ops{ .AddressOf = {} }, - .Keyword_try => ops{ .Try = {} }, - .Keyword_await => ops{ .Await = .{} }, + const op: Node.PrefixOp.Op = switch (token.ptr.id) { + .Bang => .BoolNot, + .Minus => .Negation, + .Tilde => .BitNot, + .MinusPercent => .NegationWrap, + .Ampersand => .AddressOf, + .Keyword_try => .Try, + .Keyword_await => .Await, else => { putBackToken(it, token.index); return null; @@ -2223,7 +2209,7 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = token.index, .op = op, .rhs = undefined, // set by caller @@ -2246,9 +2232,9 @@ fn parsePrefixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (eatToken(it, .QuestionMark)) |token| { const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = token, - .op = Node.PrefixOp.Op.OptionalType, + .op = .OptionalType, .rhs = undefined, // set by caller }; return &node.base; @@ -2264,7 +2250,7 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return null; }; const node = try arena.create(Node.AnyFrameType); - node.* = Node.AnyFrameType{ + node.* = .{ .anyframe_token = token, .result = Node.AnyFrameType.Result{ .arrow_token = arrow, @@ -2286,18 +2272,18 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node while (true) { if (eatToken(it, .Keyword_align)) |align_token| { const lparen = try expectToken(it, tree, .LParen); - const expr_node = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr_node = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); // Optional bit range const bit_range = if (eatToken(it, .Colon)) |_| bit_range_value: { - const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ - .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, + const range_start = try expectNode(arena, it, tree, parseIntegerLiteral, .{ + .ExpectedIntegerLiteral = .{ .token = it.index }, }); _ = try expectToken(it, tree, .Colon); - const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, AstError{ - .ExpectedIntegerLiteral = AstError.ExpectedIntegerLiteral{ .token = it.index }, + const range_end = try expectNode(arena, it, tree, parseIntegerLiteral, .{ + .ExpectedIntegerLiteral = .{ .token = it.index }, }); break :bit_range_value Node.PrefixOp.PtrInfo.Align.BitRange{ @@ -2340,8 +2326,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node while (true) { if (try parseByteAlign(arena, it, tree)) |align_expr| { if (slice_type.align_info != null) { - try tree.errors.push(AstError{ - .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraAlignQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2353,8 +2339,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_const)) |const_token| { if (slice_type.const_token != null) { - try tree.errors.push(AstError{ - .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraConstQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2363,8 +2349,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_volatile)) |volatile_token| { if (slice_type.volatile_token != null) { - try tree.errors.push(AstError{ - .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraVolatileQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2373,8 +2359,8 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { if (slice_type.allowzero_token != null) { - try tree.errors.push(AstError{ - .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index }, + try tree.errors.push(.{ + .ExtraAllowZeroQualifier = .{ .token = it.index }, }); return error.ParseError; } @@ -2398,15 +2384,14 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node /// / DOTASTERISK /// / DOTQUESTIONMARK fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const Op = Node.SuffixOp.Op; const OpAndToken = struct { op: Node.SuffixOp.Op, token: TokenIndex, }; - const op_and_token = blk: { + const op_and_token: OpAndToken = blk: { if (eatToken(it, .LBracket)) |_| { - const index_expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const index_expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); if (eatToken(it, .Ellipsis2) != null) { @@ -2415,9 +2400,9 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { try parseExpr(arena, it, tree) else null; - break :blk OpAndToken{ - .op = Op{ - .Slice = Op.Slice{ + break :blk .{ + .op = .{ + .Slice = .{ .start = index_expr, .end = end_expr, .sentinel = sentinel, @@ -2427,14 +2412,14 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; } - break :blk OpAndToken{ - .op = Op{ .ArrayAccess = index_expr }, + break :blk .{ + .op = .{ .ArrayAccess = index_expr }, .token = try expectToken(it, tree, .RBracket), }; } if (eatToken(it, .PeriodAsterisk)) |period_asterisk| { - break :blk OpAndToken{ .op = Op{ .Deref = {} }, .token = period_asterisk }; + break :blk .{ .op = .Deref, .token = period_asterisk }; } if (eatToken(it, .Period)) |period| { @@ -2443,19 +2428,19 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { // Should there be an ast.Node.SuffixOp.FieldAccess variant? Or should // this grammar rule be altered? const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = period, .lhs = undefined, // set by caller - .op = Node.InfixOp.Op.Period, + .op = .Period, .rhs = identifier, }; return &node.base; } if (eatToken(it, .QuestionMark)) |question_mark| { - break :blk OpAndToken{ .op = Op{ .UnwrapOptional = {} }, .token = question_mark }; + break :blk .{ .op = .UnwrapOptional, .token = question_mark }; } - try tree.errors.push(AstError{ - .ExpectedSuffixOp = AstError.ExpectedSuffixOp{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedSuffixOp = .{ .token = it.index }, }); return null; } @@ -2464,7 +2449,7 @@ fn parseSuffixOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { }; const node = try arena.create(Node.SuffixOp); - node.* = Node.SuffixOp{ + node.* = .{ .lhs = undefined, // set by caller .op = op_and_token.op, .rtoken = op_and_token.token, @@ -2491,22 +2476,22 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No const lbracket = eatToken(it, .LBracket) orelse return null; const expr = try parseExpr(arena, it, tree); const sentinel = if (eatToken(it, .Colon)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ + try expectNode(arena, it, tree, parseExpr, .{ .ExpectedExpr = .{ .token = it.index }, }) else null; const rbracket = try expectToken(it, tree, .RBracket); - const op = if (expr) |len_expr| - Node.PrefixOp.Op{ + const op: Node.PrefixOp.Op = if (expr) |len_expr| + .{ .ArrayType = .{ .len_expr = len_expr, .sentinel = sentinel, }, } else - Node.PrefixOp.Op{ + .{ .SliceType = Node.PrefixOp.PtrInfo{ .allowzero_token = null, .align_info = null, @@ -2517,7 +2502,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No }; const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = lbracket, .op = op, .rhs = undefined, // set by caller @@ -2533,7 +2518,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (eatToken(it, .Asterisk)) |asterisk| { const sentinel = if (eatToken(it, .Colon)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ + try expectNode(arena, it, tree, parseExpr, .{ .ExpectedExpr = .{ .token = it.index }, }) else @@ -2549,17 +2534,17 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = double_asterisk, - .op = Node.PrefixOp.Op{ .PtrType = .{} }, + .op = .{ .PtrType = .{} }, .rhs = undefined, // set by caller }; // Special case for **, which is its own token const child = try arena.create(Node.PrefixOp); - child.* = Node.PrefixOp{ + child.* = .{ .op_token = double_asterisk, - .op = Node.PrefixOp.Op{ .PtrType = .{} }, + .op = .{ .PtrType = .{} }, .rhs = undefined, // set by caller }; node.rhs = &child.base; @@ -2586,7 +2571,7 @@ fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node } } const sentinel = if (eatToken(it, .Colon)) |_| - try expectNode(arena, it, tree, parseExpr, AstError{ + try expectNode(arena, it, tree, parseExpr, .{ .ExpectedExpr = .{ .token = it.index }, }) else @@ -2629,8 +2614,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? .Keyword_struct => Node.ContainerDecl.InitArg{ .None = {} }, .Keyword_enum => blk: { if (eatToken(it, .LParen) != null) { - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); break :blk Node.ContainerDecl.InitArg{ .Type = expr }; @@ -2641,8 +2626,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? if (eatToken(it, .LParen) != null) { if (eatToken(it, .Keyword_enum) != null) { if (eatToken(it, .LParen) != null) { - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); _ = try expectToken(it, tree, .RParen); @@ -2651,8 +2636,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? _ = try expectToken(it, tree, .RParen); break :blk Node.ContainerDecl.InitArg{ .Enum = null }; } - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); break :blk Node.ContainerDecl.InitArg{ .Type = expr }; @@ -2666,7 +2651,7 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? }; const node = try arena.create(Node.ContainerDecl); - node.* = Node.ContainerDecl{ + node.* = .{ .layout_token = null, .kind_token = kind_token.index, .init_arg_expr = init_arg_expr, @@ -2681,8 +2666,8 @@ fn parseContainerDeclType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !? fn parseByteAlign(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { _ = eatToken(it, .Keyword_align) orelse return null; _ = try expectToken(it, tree, .LParen); - const expr = try expectNode(arena, it, tree, parseExpr, AstError{ - .ExpectedExpr = AstError.ExpectedExpr{ .token = it.index }, + const expr = try expectNode(arena, it, tree, parseExpr, .{ + .ExpectedExpr = .{ .token = it.index }, }); _ = try expectToken(it, tree, .RParen); return expr; @@ -2738,7 +2723,7 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No pub fn parse(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*Node { const op_token = eatToken(it, token) orelse return null; const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = op_token, .lhs = undefined, // set by caller .op = op, @@ -2754,13 +2739,13 @@ fn SimpleBinOpParseFn(comptime token: Token.Id, comptime op: Node.InfixOp.Op) No fn parseBuiltinCall(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Builtin) orelse return null; const params = (try parseFnCallArguments(arena, it, tree)) orelse { - try tree.errors.push(AstError{ - .ExpectedParamList = AstError.ExpectedParamList{ .token = it.index }, + try tree.errors.push(.{ + .ExpectedParamList = .{ .token = it.index }, }); return error.ParseError; }; const node = try arena.create(Node.BuiltinCall); - node.* = Node.BuiltinCall{ + node.* = .{ .builtin_token = token, .params = params.list, .rparen_token = params.rparen, @@ -2773,7 +2758,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Identifier) orelse return null; const node = try arena.create(Node.ErrorTag); - node.* = Node.ErrorTag{ + node.* = .{ .doc_comments = doc_comments, .name_token = token, }; @@ -2783,7 +2768,7 @@ fn parseErrorTag(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Identifier) orelse return null; const node = try arena.create(Node.Identifier); - node.* = Node.Identifier{ + node.* = .{ .token = token, }; return &node.base; @@ -2792,7 +2777,7 @@ fn parseIdentifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseVarType(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_var) orelse return null; const node = try arena.create(Node.VarType); - node.* = Node.VarType{ + node.* = .{ .token = token, }; return &node.base; @@ -2810,7 +2795,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { if (eatToken(it, .StringLiteral)) |token| { const node = try arena.create(Node.StringLiteral); - node.* = Node.StringLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -2824,7 +2809,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { const node = try arena.create(Node.MultilineStringLiteral); - node.* = Node.MultilineStringLiteral{ + node.* = .{ .lines = Node.MultilineStringLiteral.LineList.init(arena), }; try node.lines.push(first_line); @@ -2840,7 +2825,7 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .IntegerLiteral) orelse return null; const node = try arena.create(Node.IntegerLiteral); - node.* = Node.IntegerLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -2849,7 +2834,7 @@ fn parseIntegerLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .FloatLiteral) orelse return null; const node = try arena.create(Node.FloatLiteral); - node.* = Node.FloatLiteral{ + node.* = .{ .token = token, }; return &node.base; @@ -2858,9 +2843,9 @@ fn parseFloatLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_try) orelse return null; const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ + node.* = .{ .op_token = token, - .op = Node.PrefixOp.Op.Try, + .op = .Try, .rhs = undefined, // set by caller }; return &node.base; @@ -2869,7 +2854,7 @@ fn parseTry(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn parseUse(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const token = eatToken(it, .Keyword_usingnamespace) orelse return null; const node = try arena.create(Node.Use); - node.* = Node.Use{ + node.* = .{ .doc_comments = null, .visib_token = null, .use_token = token, @@ -2884,17 +2869,17 @@ fn parseIf(arena: *Allocator, it: *TokenIterator, tree: *Tree, bodyParseFn: Node const node = (try parseIfPrefix(arena, it, tree)) orelse return null; const if_prefix = node.cast(Node.If).?; - if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + if_prefix.body = try expectNode(arena, it, tree, bodyParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); const else_token = eatToken(it, .Keyword_else) orelse return node; const payload = try parsePayload(arena, it, tree); - const else_expr = try expectNode(arena, it, tree, bodyParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const else_expr = try expectNode(arena, it, tree, bodyParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); const else_node = try arena.create(Node.Else); - else_node.* = Node.Else{ + else_node.* = .{ .else_token = else_token, .payload = payload, .body = else_expr, @@ -2914,7 +2899,7 @@ fn parseDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.D if (lines.len == 0) return null; const node = try arena.create(Node.DocComment); - node.* = Node.DocComment{ + node.* = .{ .lines = lines, }; return node; @@ -2925,7 +2910,7 @@ fn parseAppendedDocComment(arena: *Allocator, it: *TokenIterator, tree: *Tree, a const comment_token = eatToken(it, .DocComment) orelse return null; if (tree.tokensOnSameLine(after_token, comment_token)) { const node = try arena.create(Node.DocComment); - node.* = Node.DocComment{ + node.* = .{ .lines = Node.DocComment.LineList.init(arena), }; try node.lines.push(comment_token); @@ -2974,14 +2959,14 @@ fn parsePrefixOpExpr( switch (rightmost_op.id) { .PrefixOp => { const prefix_op = rightmost_op.cast(Node.PrefixOp).?; - prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + prefix_op.rhs = try expectNode(arena, it, tree, childParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); }, .AnyFrameType => { const prom = rightmost_op.cast(Node.AnyFrameType).?; - prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + prom.result.?.return_type = try expectNode(arena, it, tree, childParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); }, else => unreachable, @@ -3010,8 +2995,8 @@ fn parseBinOpExpr( var res = (try childParseFn(arena, it, tree)) orelse return null; while (try opParseFn(arena, it, tree)) |node| { - const right = try expectNode(arena, it, tree, childParseFn, AstError{ - .InvalidToken = AstError.InvalidToken{ .token = it.index }, + const right = try expectNode(arena, it, tree, childParseFn, .{ + .InvalidToken = .{ .token = it.index }, }); const left = res; res = node; @@ -3031,7 +3016,7 @@ fn parseBinOpExpr( fn createInfixOp(arena: *Allocator, index: TokenIndex, op: Node.InfixOp.Op) !*Node { const node = try arena.create(Node.InfixOp); - node.* = Node.InfixOp{ + node.* = .{ .op_token = index, .lhs = undefined, // set by caller .op = op, @@ -3051,8 +3036,8 @@ fn eatAnnotatedToken(it: *TokenIterator, id: Token.Id) ?AnnotatedToken { fn expectToken(it: *TokenIterator, tree: *Tree, id: Token.Id) Error!TokenIndex { const token = nextToken(it); if (token.ptr.id != id) { - try tree.errors.push(AstError{ - .ExpectedToken = AstError.ExpectedToken{ .token = token.index, .expected_id = id }, + try tree.errors.push(.{ + .ExpectedToken = .{ .token = token.index, .expected_id = id }, }); return error.ParseError; } From 7aac21c6f59b70deea6ced617f7b6a550e92bab4 Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 15 Mar 2020 11:37:36 +1000 Subject: [PATCH 11/79] allow `_` separators in number literals (stage 1) * Underscores `_` may be placed between two digits in a int/float literal * Consecutive underscores are not allowed * Fixed parsing bug in exponents of hexadecimal float literals. Exponents should always be base 10, but hex characters would be parsed inside the exponent and everything after them would be ignored. eg: `0x1.0p1ab1` would be parsed as `0x1.0p1`. --- doc/langref.html.in | 11 ++ lib/std/special/compiler_rt/floatundisf.zig | 38 +++--- src/parse_f128.c | 79 ++++++++--- src/tokenizer.cpp | 137 ++++++++++++-------- test/compile_errors.zig | 96 ++++++++++++++ test/stage1/behavior/math.zig | 28 ++++ 6 files changed, 297 insertions(+), 92 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 3a7892fd45..616edd44eb 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -885,6 +885,12 @@ const hex_int = 0xff; const another_hex_int = 0xFF; const octal_int = 0o755; const binary_int = 0b11110000; + +// underscores may be placed between two digits as a visual separator +const one_billion = 1_000_000_000; +const binary_mask = 0b1_1111_1111; +const permissions = 0o7_5_5; +const big_address = 0xFF80_0000_0000_0000; {#code_end#} {#header_close#} {#header_open|Runtime Integer Values#} @@ -947,6 +953,11 @@ const yet_another = 123.0e+77; const hex_floating_point = 0x103.70p-5; const another_hex_float = 0x103.70; const yet_another_hex_float = 0x103.70P-5; + +// underscores may be placed between two digits as a visual separator +const lightspeed = 299_792_458.000_000; +const nanosecond = 0.000_000_001; +const more_hex = 0x1234_5678.9ABC_CDEFp-10; {#code_end#}

There is no syntax for NaN, infinity, or negative infinity. For these special values, diff --git a/lib/std/special/compiler_rt/floatundisf.zig b/lib/std/special/compiler_rt/floatundisf.zig index 41ff02daee..ff242721d6 100644 --- a/lib/std/special/compiler_rt/floatundisf.zig +++ b/lib/std/special/compiler_rt/floatundisf.zig @@ -69,23 +69,23 @@ test "floatundisf" { test__floatundisf(0, 0.0); test__floatundisf(1, 1.0); test__floatundisf(2, 2.0); - test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62F); - test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62F); - test__floatundisf(0x8000008000000000, 0x1p+63F); - test__floatundisf(0x8000010000000000, 0x1.000002p+63F); - test__floatundisf(0x8000000000000000, 0x1p+63F); - test__floatundisf(0x8000000000000001, 0x1p+63F); - test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64F); - test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64F); - test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50F); - test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50F); - test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50F); + test__floatundisf(0x7FFFFF8000000000, 0x1.FFFFFEp+62); + test__floatundisf(0x7FFFFF0000000000, 0x1.FFFFFCp+62); + test__floatundisf(0x8000008000000000, 0x1p+63); + test__floatundisf(0x8000010000000000, 0x1.000002p+63); + test__floatundisf(0x8000000000000000, 0x1p+63); + test__floatundisf(0x8000000000000001, 0x1p+63); + test__floatundisf(0xFFFFFFFFFFFFFFFE, 0x1p+64); + test__floatundisf(0xFFFFFFFFFFFFFFFF, 0x1p+64); + test__floatundisf(0x0007FB72E8000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EA000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EB000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EBFFFFFF, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72EC000000, 0x1.FEDCBCp+50); + test__floatundisf(0x0007FB72E8000001, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E6000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E7000000, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E7FFFFFF, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E4000001, 0x1.FEDCBAp+50); + test__floatundisf(0x0007FB72E4000000, 0x1.FEDCB8p+50); } diff --git a/src/parse_f128.c b/src/parse_f128.c index cffb3796b4..9b5c287a3c 100644 --- a/src/parse_f128.c +++ b/src/parse_f128.c @@ -165,22 +165,36 @@ static long long scanexp(struct MuslFILE *f, int pok) int x; long long y; int neg = 0; - + c = shgetc(f); if (c=='+' || c=='-') { neg = (c=='-'); c = shgetc(f); if (c-'0'>=10U && pok) shunget(f); } - if (c-'0'>=10U) { + if (c-'0'>=10U && c!='_') { shunget(f); return LLONG_MIN; } - for (x=0; c-'0'<10U && xdata.int_lit.bigint, 0); - bigint_init_unsigned(&t.specified_exponent, 0); break; case DIGIT_NON_ZERO: t.state = TokenizeStateNumber; begin_token(&t, TokenIdIntLiteral); + t.is_trailing_underscore = false; t.radix = 10; - t.exp_add_amt = 1; - t.exponent_in_bin_or_dec = 0; bigint_init_unsigned(&t.cur_tok->data.int_lit.bigint, get_digit_value(c)); - bigint_init_unsigned(&t.specified_exponent, 0); break; case '"': begin_token(&t, TokenIdStringLiteral); @@ -1189,17 +1184,15 @@ void tokenize(Buf *buf, Tokenization *out) { switch (c) { case 'b': t.radix = 2; - t.state = TokenizeStateNumber; + t.state = TokenizeStateNumberNoUnderscore; break; case 'o': t.radix = 8; - t.exp_add_amt = 3; - t.state = TokenizeStateNumber; + t.state = TokenizeStateNumberNoUnderscore; break; case 'x': t.radix = 16; - t.exp_add_amt = 4; - t.state = TokenizeStateNumber; + t.state = TokenizeStateNumberNoUnderscore; break; default: // reinterpret as normal number @@ -1208,9 +1201,27 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; + case TokenizeStateNumberNoUnderscore: + if (c == '_') { + invalid_char_error(&t, c); + break; + } else if (get_digit_value(c) < t.radix) { + t.is_trailing_underscore = false; + t.state = TokenizeStateNumber; + } + // fall through case TokenizeStateNumber: { + if (c == '_') { + t.is_trailing_underscore = true; + t.state = TokenizeStateNumberNoUnderscore; + break; + } if (c == '.') { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (t.radix != 16 && t.radix != 10) { invalid_char_error(&t, c); } @@ -1222,13 +1233,18 @@ void tokenize(Buf *buf, Tokenization *out) { invalid_char_error(&t, c); } t.state = TokenizeStateFloatExponentUnsigned; + t.radix = 10; // exponent is always base 10 assert(t.cur_tok->id == TokenIdIntLiteral); - bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint); set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); break; } uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } + if (is_symbol_char(c)) { invalid_char_error(&t, c); } @@ -1259,20 +1275,37 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } t.pos -= 1; - t.state = TokenizeStateFloatFraction; + t.state = TokenizeStateFloatFractionNoUnderscore; assert(t.cur_tok->id == TokenIdIntLiteral); - bigint_init_bigint(&t.significand, &t.cur_tok->data.int_lit.bigint); set_token_id(&t, t.cur_tok, TokenIdFloatLiteral); continue; } + case TokenizeStateFloatFractionNoUnderscore: + if (c == '_') { + invalid_char_error(&t, c); + } else if (get_digit_value(c) < t.radix) { + t.is_trailing_underscore = false; + t.state = TokenizeStateFloatFraction; + } + // fall through case TokenizeStateFloatFraction: { + if (c == '_') { + t.is_trailing_underscore = true; + t.state = TokenizeStateFloatFractionNoUnderscore; + break; + } if (is_exponent_signifier(c, t.radix)) { t.state = TokenizeStateFloatExponentUnsigned; + t.radix = 10; // exponent is always base 10 break; } uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (is_symbol_char(c)) { invalid_char_error(&t, c); } @@ -1282,46 +1315,47 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateStart; continue; } - t.exponent_in_bin_or_dec -= t.exp_add_amt; - if (t.radix == 10) { - // For now we use strtod to parse decimal floats, so we just have to get to the - // end of the token. - break; - } - BigInt digit_value_bi; - bigint_init_unsigned(&digit_value_bi, digit_value); - BigInt radix_bi; - bigint_init_unsigned(&radix_bi, t.radix); - - BigInt multiplied; - bigint_mul(&multiplied, &t.significand, &radix_bi); - - bigint_add(&t.significand, &multiplied, &digit_value_bi); - break; + // we use parse_f128 to generate the float literal, so just + // need to get to the end of the token } + break; case TokenizeStateFloatExponentUnsigned: switch (c) { case '+': - t.is_exp_negative = false; - t.state = TokenizeStateFloatExponentNumber; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; break; case '-': - t.is_exp_negative = true; - t.state = TokenizeStateFloatExponentNumber; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; break; default: // reinterpret as normal exponent number t.pos -= 1; - t.is_exp_negative = false; - t.state = TokenizeStateFloatExponentNumber; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; continue; } break; + case TokenizeStateFloatExponentNumberNoUnderscore: + if (c == '_') { + invalid_char_error(&t, c); + } else if (get_digit_value(c) < t.radix) { + t.is_trailing_underscore = false; + t.state = TokenizeStateFloatExponentNumber; + } + // fall through case TokenizeStateFloatExponentNumber: { + if (c == '_') { + t.is_trailing_underscore = true; + t.state = TokenizeStateFloatExponentNumberNoUnderscore; + break; + } uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (is_symbol_char(c)) { invalid_char_error(&t, c); } @@ -1331,21 +1365,9 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateStart; continue; } - if (t.radix == 10) { - // For now we use strtod to parse decimal floats, so we just have to get to the - // end of the token. - break; - } - BigInt digit_value_bi; - bigint_init_unsigned(&digit_value_bi, digit_value); - BigInt radix_bi; - bigint_init_unsigned(&radix_bi, 10); - - BigInt multiplied; - bigint_mul(&multiplied, &t.specified_exponent, &radix_bi); - - bigint_add(&t.specified_exponent, &multiplied, &digit_value_bi); + // we use parse_f128 to generate the float literal, so just + // need to get to the end of the token } break; case TokenizeStateSawDash: @@ -1399,6 +1421,9 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateStart: case TokenizeStateError: break; + case TokenizeStateNumberNoUnderscore: + case TokenizeStateFloatFractionNoUnderscore: + case TokenizeStateFloatExponentNumberNoUnderscore: case TokenizeStateNumberDot: tokenize_error(&t, "unterminated number literal"); break; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f894a152a7..83fe1def62 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -389,6 +389,102 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:5:29: error: invalid token: '.'", }); + cases.add("invalid underscore placement in float literal - 1", + \\fn main() void { + \\ var bad: f128 = 0._0; + \\}) + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 2", + \\fn main() void { + \\ var bad: f128 = 0_.0; + \\}) + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '.'", + }); + + cases.add("invalid underscore placement in float literal - 3", + \\fn main() void { + \\ var bad: f128 = 0.0_; + \\}) + , &[_][]const u8{ + "tmp.zig:2:25: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in float literal - 4", + \\fn main() void { + \\ var bad: f128 = 1.0e_1; + \\}) + , &[_][]const u8{ + "tmp.zig:2:25: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 5", + \\fn main() void { + \\ var bad: f128 = 1.0e+_1; + \\}) + , &[_][]const u8{ + "tmp.zig:2:26: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 6", + \\fn main() void { + \\ var bad: f128 = 1.0e-_1; + \\}) + , &[_][]const u8{ + "tmp.zig:2:26: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 7", + \\fn main() void { + \\ var bad: f128 = 1.0e-1_; + \\}) + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in float literal - 9", + \\fn main() void { + \\ var bad: f128 = 1__0.0e-1; + \\}) + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 10", + \\fn main() void { + \\ var bad: f128 = 1.0__0e-1; + \\}) + , &[_][]const u8{ + "tmp.zig:2:25: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 11", + \\fn main() void { + \\ var bad: f128 = 1.0e-1__0; + \\}) + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: '_'", + }); + + cases.add("invalid underscore placement in float literal - 12", + \\fn main() void { + \\ var bad: f128 = 0_x0.0; + \\}) + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: 'x'", + }); + + cases.add("invalid underscore placement in float literal - 13", + \\fn main() void { + \\ var bad: f128 = 0x_0.0; + \\}) + , &[_][]const u8{ + "tmp.zig:2:23: error: invalid character: '_'", + }); + cases.add("var args without c calling conv", \\fn foo(args: ...) void {} \\comptime { diff --git a/test/stage1/behavior/math.zig b/test/stage1/behavior/math.zig index fb70fb7e44..b342597acf 100644 --- a/test/stage1/behavior/math.zig +++ b/test/stage1/behavior/math.zig @@ -411,6 +411,34 @@ test "quad hex float literal parsing accurate" { comptime S.doTheTest(); } +test "underscore separator parsing" { + expect(0_0_0_0 == 0); + expect(1_234_567 == 1234567); + expect(001_234_567 == 1234567); + expect(0_0_1_2_3_4_5_6_7 == 1234567); + + expect(0b0_0_0_0 == 0); + expect(0b1010_1010 == 0b10101010); + expect(0b0000_1010_1010 == 0b10101010); + expect(0b1_0_1_0_1_0_1_0 == 0b10101010); + + expect(0o0_0_0_0 == 0); + expect(0o1010_1010 == 0o10101010); + expect(0o0000_1010_1010 == 0o10101010); + expect(0o1_0_1_0_1_0_1_0 == 0o10101010); + + expect(0x0_0_0_0 == 0); + expect(0x1010_1010 == 0x10101010); + expect(0x0000_1010_1010 == 0x10101010); + expect(0x1_0_1_0_1_0_1_0 == 0x10101010); + + expect(123_456.789_000e1_0 == 123456.789000e10); + expect(0_1_2_3_4_5_6.7_8_9_0_0_0e0_0_1_0 == 123456.789000e10); + + expect(0x1234_5678.9ABC_DEF0p-1_0 == 0x12345678.9ABCDEF0p-10); + expect(0x1_2_3_4_5_6_7_8.9_A_B_C_D_E_F_0p-0_0_0_1_0 == 0x12345678.9ABCDEF0p-10); +} + test "hex float literal within range" { const a = 0x1.0p16383; const b = 0x0.1p16387; From 925f71085269a8072ea9c49025a534fa47fbec44 Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 15 Mar 2020 13:05:24 +1000 Subject: [PATCH 12/79] make parsing `0.0_e1` an error --- src/tokenizer.cpp | 8 ++++++++ test/compile_errors.zig | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 73efae2037..22d63568bf 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -1229,6 +1229,10 @@ void tokenize(Buf *buf, Tokenization *out) { break; } if (is_exponent_signifier(c, t.radix)) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } if (t.radix != 16 && t.radix != 10) { invalid_char_error(&t, c); } @@ -1296,6 +1300,10 @@ void tokenize(Buf *buf, Tokenization *out) { break; } if (is_exponent_signifier(c, t.radix)) { + if (t.is_trailing_underscore) { + invalid_char_error(&t, c); + break; + } t.state = TokenizeStateFloatExponentUnsigned; t.radix = 10; // exponent is always base 10 break; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 83fe1def62..2b40fec106 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -485,6 +485,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:23: error: invalid character: '_'", }); + cases.add("invalid underscore placement in float literal - 14", + \\fn main() void { + \\ var bad: f128 = 0x0.0_p1; + \\}) + , &[_][]const u8{ + "tmp.zig:2:27: error: invalid character: 'p'", + }); + cases.add("var args without c calling conv", \\fn foo(args: ...) void {} \\comptime { From 47f7e6658077fb4f55c36e9c62ed5012ef8aace2 Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 15 Mar 2020 23:42:29 +1000 Subject: [PATCH 13/79] add more test cases for invalid number literals --- test/compile_errors.zig | 76 +++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 14 deletions(-) diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 2b40fec106..73bf60216e 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -384,15 +384,31 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var bad_float :f32 = 0.0; \\ bad_float = bad_float + .20; \\ std.debug.assert(bad_float < 1.0); - \\}) + \\} , &[_][]const u8{ "tmp.zig:5:29: error: invalid token: '.'", }); + cases.add("invalid exponent in float literal - 1", + \\fn main() void { + \\ var bad: f128 = 0x1.0p1ab1; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: 'a'", + }); + + cases.add("invalid exponent in float literal - 2", + \\fn main() void { + \\ var bad: f128 = 0x1.0p50F; + \\} + , &[_][]const u8{ + "tmp.zig:2:29: error: invalid character: 'F'", + }); + cases.add("invalid underscore placement in float literal - 1", \\fn main() void { \\ var bad: f128 = 0._0; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:23: error: invalid character: '_'", }); @@ -400,7 +416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 2", \\fn main() void { \\ var bad: f128 = 0_.0; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:23: error: invalid character: '.'", }); @@ -408,7 +424,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 3", \\fn main() void { \\ var bad: f128 = 0.0_; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:25: error: invalid character: ';'", }); @@ -416,7 +432,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 4", \\fn main() void { \\ var bad: f128 = 1.0e_1; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:25: error: invalid character: '_'", }); @@ -424,7 +440,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 5", \\fn main() void { \\ var bad: f128 = 1.0e+_1; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:26: error: invalid character: '_'", }); @@ -432,7 +448,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 6", \\fn main() void { \\ var bad: f128 = 1.0e-_1; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:26: error: invalid character: '_'", }); @@ -440,7 +456,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 7", \\fn main() void { \\ var bad: f128 = 1.0e-1_; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:28: error: invalid character: ';'", }); @@ -448,7 +464,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 9", \\fn main() void { \\ var bad: f128 = 1__0.0e-1; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:23: error: invalid character: '_'", }); @@ -456,7 +472,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 10", \\fn main() void { \\ var bad: f128 = 1.0__0e-1; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:25: error: invalid character: '_'", }); @@ -464,7 +480,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 11", \\fn main() void { \\ var bad: f128 = 1.0e-1__0; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:28: error: invalid character: '_'", }); @@ -472,7 +488,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 12", \\fn main() void { \\ var bad: f128 = 0_x0.0; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:23: error: invalid character: 'x'", }); @@ -480,7 +496,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 13", \\fn main() void { \\ var bad: f128 = 0x_0.0; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:23: error: invalid character: '_'", }); @@ -488,11 +504,43 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add("invalid underscore placement in float literal - 14", \\fn main() void { \\ var bad: f128 = 0x0.0_p1; - \\}) + \\} , &[_][]const u8{ "tmp.zig:2:27: error: invalid character: 'p'", }); + cases.add("invalid underscore placement in int literal - 1", + \\fn main() void { + \\ var bad: u128 = 0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:26: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in int literal - 2", + \\fn main() void { + \\ var bad: u128 = 0b0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in int literal - 3", + \\fn main() void { + \\ var bad: u128 = 0o0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + + cases.add("invalid underscore placement in int literal - 4", + \\fn main() void { + \\ var bad: u128 = 0x0010_; + \\} + , &[_][]const u8{ + "tmp.zig:2:28: error: invalid character: ';'", + }); + cases.add("var args without c calling conv", \\fn foo(args: ...) void {} \\comptime { From 880d8fc38089a406c6b3225148a6f50ae452cb6b Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 15 Mar 2020 16:09:28 +1000 Subject: [PATCH 14/79] fix Serializer to work with new OutStream API --- lib/std/io/serialization.zig | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/std/io/serialization.zig b/lib/std/io/serialization.zig index 4aa462aab8..4aea4ed892 100644 --- a/lib/std/io/serialization.zig +++ b/lib/std/io/serialization.zig @@ -1,6 +1,10 @@ const std = @import("../std.zig"); const builtin = std.builtin; const io = std.io; +const assert = std.debug.assert; +const math = std.math; +const meta = std.meta; +const trait = meta.trait; pub const Packing = enum { /// Pack data to byte alignment @@ -252,7 +256,7 @@ pub fn Serializer(comptime endian: builtin.Endian, comptime packing: Packing, co byte.* = if (t_bit_count < u8_bit_count) v else @truncate(u8, v); } - try self.out_stream.write(&buffer); + try self.out_stream.writeAll(&buffer); } /// Serializes the passed value into the stream From 701aaf0ddf618edffa182db1e888172b6cae4ab1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Mar 2020 14:46:09 -0400 Subject: [PATCH 15/79] renameatW: handle more windows nt status codes --- lib/std/os.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/std/os.zig b/lib/std/os.zig index 0186e1b0bf..9f18f1225f 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1683,6 +1683,11 @@ pub fn renameatW( switch (rc) { .SUCCESS => return, .INVALID_HANDLE => unreachable, + .INVALID_PARAMETER => unreachable, + .OBJECT_PATH_SYNTAX_BAD => unreachable, + .ACCESS_DENIED => return error.AccessDenied, + .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, + .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, else => return windows.unexpectedStatus(rc), } } From 6c2b23593b97aef6f375bd7d81beeaf0f66f5682 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Mar 2020 15:46:56 -0400 Subject: [PATCH 16/79] fix std.mem.span handling of sentinel-terminated arrays previously this function would use the array length, but now it scans the array looking for the first sentinel that occurs. --- lib/std/mem.zig | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index c767765652..07fbebfb3b 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -567,12 +567,20 @@ test "span" { /// Takes a pointer to an array, an array, a sentinel-terminated pointer, /// or a slice, and returns the length. +/// In the case of a sentinel-terminated array, it scans the array +/// for a sentinel and uses that for the length, rather than using the array length. pub fn len(ptr: var) usize { return switch (@typeInfo(@TypeOf(ptr))) { - .Array => |info| info.len, + .Array => |info| if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, &ptr) + else + info.len, .Pointer => |info| switch (info.size) { .One => switch (@typeInfo(info.child)) { - .Array => |x| x.len, + .Array => |x| if (x.sentinel) |sentinel| + indexOfSentinel(x.child, sentinel, ptr) + else + ptr.len, else => @compileError("invalid type given to std.mem.length"), }, .Many => if (info.sentinel) |sentinel| @@ -597,6 +605,12 @@ test "len" { const ptr = array[0..2 :0].ptr; testing.expect(len(ptr) == 2); } + { + var array: [5:0]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + testing.expect(len(&array) == 5); + array[2] = 0; + testing.expect(len(&array) == 2); + } } pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { From e36978906214cb8c3dba693a073914394a90d0d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Mar 2020 15:47:42 -0400 Subject: [PATCH 17/79] fix std.os.renameatW Ask for DELETE access when opening the source file. Additionally, when the source and dest dir are the same, pass null for RootDirectory. --- lib/std/os.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 9f18f1225f..5a56224e61 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1650,7 +1650,7 @@ pub fn renameatW( new_path_w: [*:0]const u16, ReplaceIfExists: windows.BOOLEAN, ) RenameError!void { - const access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE; + const access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE; const src_fd = try windows.OpenFileW(old_dir_fd, old_path, null, access_mask, windows.FILE_OPEN); defer windows.CloseHandle(src_fd); @@ -1664,7 +1664,7 @@ pub fn renameatW( rename_info.* = .{ .ReplaceIfExists = ReplaceIfExists, - .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd, + .RootDirectory = if (old_dir_fd == new_dir_fd or std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd, .FileNameLength = @intCast(u32, new_path.len * 2), // already checked error.NameTooLong .FileName = undefined, }; From 7e45a3ef6ac9a5a24276d26cde11fdbf94e373e4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Mar 2020 15:57:51 -0400 Subject: [PATCH 18/79] fix typo in new mem.len test --- lib/std/mem.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 07fbebfb3b..9d2232d3eb 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -606,7 +606,7 @@ test "len" { testing.expect(len(ptr) == 2); } { - var array: [5:0]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; testing.expect(len(&array) == 5); array[2] = 0; testing.expect(len(&array) == 2); From a27a8561e9387b22d7c694af924e8f2ed0f17290 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Mar 2020 17:26:29 -0400 Subject: [PATCH 19/79] adjust renameatW to always supply dest root dir this fixes tests for wine --- lib/std/mem.zig | 2 +- lib/std/os.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 9d2232d3eb..438c15c2eb 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -116,7 +116,7 @@ pub const Allocator = struct { pub fn allocSentinel(self: *Allocator, comptime Elem: type, n: usize, comptime sentinel: Elem) Error![:sentinel]Elem { var ptr = try self.alloc(Elem, n + 1); ptr[n] = sentinel; - return ptr[0 .. n :sentinel]; + return ptr[0..n :sentinel]; } pub fn alignedAlloc( diff --git a/lib/std/os.zig b/lib/std/os.zig index 5a56224e61..377f7d7077 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1664,7 +1664,7 @@ pub fn renameatW( rename_info.* = .{ .ReplaceIfExists = ReplaceIfExists, - .RootDirectory = if (old_dir_fd == new_dir_fd or std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd, + .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(new_path_w)) null else new_dir_fd, .FileNameLength = @intCast(u32, new_path.len * 2), // already checked error.NameTooLong .FileName = undefined, }; From 582991a5a818179881f7923c7e6cff10de50dfcf Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 16 Mar 2020 09:54:11 +0100 Subject: [PATCH 20/79] build: Expose function-sections switch --- lib/std/build.zig | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 8fb5eaeeb0..e5d83f22b9 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1157,8 +1157,14 @@ pub const LibExeObjStep = struct { valgrind_support: ?bool = null, + /// Create a .eh_frame_hdr section and a PT_GNU_EH_FRAME segment in the ELF + /// file. link_eh_frame_hdr: bool = false, + /// Place every function in its own section so that unused ones may be + /// safely garbage-collected during the linking phase. + link_function_sections: bool = false, + /// Uses system Wine installation to run cross compiled Windows build artifacts. enable_wine: bool = false, @@ -1884,7 +1890,9 @@ pub const LibExeObjStep = struct { if (self.link_eh_frame_hdr) { try zig_args.append("--eh-frame-hdr"); } - + if (self.link_function_sections) { + try zig_args.append("-ffunction-sections"); + } if (self.single_threaded) { try zig_args.append("--single-threaded"); } From 6a15d668ee1fd3cfc72b409e56a72b93ca46e1be Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Mon, 16 Mar 2020 22:10:07 +0100 Subject: [PATCH 21/79] Change the default stdin behavior of RunStep to .Inherit This behaves the same as stdout and stderr behavior which also default to .inherit. Also adds a field to RunStep to change the behavior. Since this is a breaking change, previous behavior can be restored by doing: `RunStep.stdin_behavior = .Ignore`. --- lib/std/build/run.zig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/std/build/run.zig b/lib/std/build/run.zig index 91ecd56c3a..3276de9d19 100644 --- a/lib/std/build/run.zig +++ b/lib/std/build/run.zig @@ -29,6 +29,8 @@ pub const RunStep = struct { stdout_action: StdIoAction = .inherit, stderr_action: StdIoAction = .inherit, + stdin_behavior: std.ChildProcess.StdIo = .Inherit, + expected_exit_code: u8 = 0, pub const StdIoAction = union(enum) { @@ -159,7 +161,7 @@ pub const RunStep = struct { child.cwd = cwd; child.env_map = self.env_map orelse self.builder.env_map; - child.stdin_behavior = .Ignore; + child.stdin_behavior = self.stdin_behavior; child.stdout_behavior = stdIoActionToBehavior(self.stdout_action); child.stderr_behavior = stdIoActionToBehavior(self.stderr_action); From 7251eb1681d269ef5672193a608b580e371981fb Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Tue, 17 Mar 2020 01:28:20 -0600 Subject: [PATCH 22/79] fix a couple sockfds to be fd_t rather than i32 Using i32 causes compile errors on Windows because it uses *c_void rather than i32 for it's fd_t type. --- lib/std/os.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 377f7d7077..3333a91788 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2184,7 +2184,7 @@ const ListenError = error{ OperationNotSupported, } || UnexpectedError; -pub fn listen(sockfd: i32, backlog: u32) ListenError!void { +pub fn listen(sockfd: fd_t, backlog: u32) ListenError!void { const rc = system.listen(sockfd, backlog); switch (errno(rc)) { 0 => return, @@ -2475,7 +2475,7 @@ pub fn connect(sockfd: fd_t, sock_addr: *const sockaddr, len: socklen_t) Connect } } -pub fn getsockoptError(sockfd: i32) ConnectError!void { +pub fn getsockoptError(sockfd: fd_t) ConnectError!void { var err_code: u32 = undefined; var size: u32 = @sizeOf(u32); const rc = system.getsockopt(sockfd, SOL_SOCKET, SO_ERROR, @ptrCast([*]u8, &err_code), &size); From dbde5df568597c63e28bb1244d695156afbad5d0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 23:03:45 -0400 Subject: [PATCH 23/79] clean up some self-hosted bitrot + don't assume libstdc++ closes #4682 The self-hosted compiler is still bit rotted and still not compiling successfully yet. I have a more serious rework of the code in a different branch. --- build.zig | 14 ++-- lib/std/math/big/int.zig | 4 +- src-self-hosted/c_int.zig | 8 +-- src-self-hosted/compilation.zig | 30 +++++---- src-self-hosted/errmsg.zig | 11 ++-- src-self-hosted/ir.zig | 2 +- src-self-hosted/link.zig | 112 +++++++++++++++----------------- src-self-hosted/main.zig | 101 +++++++++++++++------------- src-self-hosted/util.zig | 15 ++++- 9 files changed, 158 insertions(+), 139 deletions(-) diff --git a/build.zig b/build.zig index 7de4f50702..6a41e6ef64 100644 --- a/build.zig +++ b/build.zig @@ -298,10 +298,14 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { dependOnLib(b, exe, ctx.llvm); if (exe.target.getOsTag() == .linux) { - try addCxxKnownPath(b, ctx, exe, "libstdc++.a", - \\Unable to determine path to libstdc++.a - \\On Fedora, install libstdc++-static and try again. - ); + // First we try to static link against gcc libstdc++. If that doesn't work, + // we fall back to -lc++ and cross our fingers. + addCxxKnownPath(b, ctx, exe, "libstdc++.a", "") catch |err| switch (err) { + error.RequiredLibraryNotFound => { + exe.linkSystemLibrary("c++"); + }, + else => |e| return e, + }; exe.linkSystemLibrary("pthread"); } else if (exe.target.isFreeBSD()) { @@ -320,7 +324,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void { // System compiler, not gcc. exe.linkSystemLibrary("c++"); }, - else => return err, + else => |e| return e, } } diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 95d0764f68..2a3c9d508a 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -520,13 +520,13 @@ pub const Int = struct { comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var, - ) FmtError!void { + ) !void { self.assertWritable(); // TODO look at fmt and support other bases // TODO support read-only fixed integers const str = self.toString(self.allocator.?, 10) catch @panic("TODO make this non allocating"); defer self.allocator.?.free(str); - return out_stream.print(str); + return out_stream.writeAll(str); } /// Returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively. diff --git a/src-self-hosted/c_int.zig b/src-self-hosted/c_int.zig index 1ee27c7596..e61a5bf657 100644 --- a/src-self-hosted/c_int.zig +++ b/src-self-hosted/c_int.zig @@ -69,9 +69,9 @@ pub const CInt = struct { }; pub fn sizeInBits(cint: CInt, self: Target) u32 { - const arch = self.getArch(); + const arch = self.cpu.arch; switch (self.os.tag) { - .freestanding, .other => switch (self.getArch()) { + .freestanding, .other => switch (self.cpu.arch) { .msp430 => switch (cint.id) { .Short, .UShort, @@ -94,7 +94,7 @@ pub const CInt = struct { => return 32, .Long, .ULong, - => return self.getArchPtrBitWidth(), + => return self.cpu.arch.ptrBitWidth(), .LongLong, .ULongLong, => return 64, @@ -114,7 +114,7 @@ pub const CInt = struct { => return 32, .Long, .ULong, - => return self.getArchPtrBitWidth(), + => return self.cpu.arch.ptrBitWidth(), .LongLong, .ULongLong, => return 64, diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index 7a45bb3c37..d9f635ebbc 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -95,7 +95,7 @@ pub const ZigCompiler = struct { pub fn getNativeLibC(self: *ZigCompiler) !*LibCInstallation { if (self.native_libc.start()) |ptr| return ptr; - try self.native_libc.data.findNative(self.allocator); + self.native_libc.data = try LibCInstallation.findNative(.{ .allocator = self.allocator }); self.native_libc.resolve(); return &self.native_libc.data; } @@ -126,7 +126,7 @@ pub const Compilation = struct { name: Buffer, llvm_triple: Buffer, root_src_path: ?[]const u8, - target: Target, + target: std.Target, llvm_target: *llvm.Target, build_mode: builtin.Mode, zig_lib_dir: []const u8, @@ -338,7 +338,7 @@ pub const Compilation = struct { zig_compiler: *ZigCompiler, name: []const u8, root_src_path: ?[]const u8, - target: Target, + target: std.zig.CrossTarget, kind: Kind, build_mode: builtin.Mode, is_static: bool, @@ -370,13 +370,18 @@ pub const Compilation = struct { zig_compiler: *ZigCompiler, name: []const u8, root_src_path: ?[]const u8, - target: Target, + cross_target: std.zig.CrossTarget, kind: Kind, build_mode: builtin.Mode, is_static: bool, zig_lib_dir: []const u8, ) !void { const allocator = zig_compiler.allocator; + + // TODO merge this line with stage2.zig crossTargetToTarget + const target_info = try std.zig.system.NativeTargetInfo.detect(std.heap.c_allocator, cross_target); + const target = target_info.target; + var comp = Compilation{ .arena_allocator = std.heap.ArenaAllocator.init(allocator), .zig_compiler = zig_compiler, @@ -419,7 +424,7 @@ pub const Compilation = struct { .target_machine = undefined, .target_data_ref = undefined, .target_layout_str = undefined, - .target_ptr_bits = target.getArchPtrBitWidth(), + .target_ptr_bits = target.cpu.arch.ptrBitWidth(), .root_package = undefined, .std_package = undefined, @@ -440,7 +445,7 @@ pub const Compilation = struct { } comp.name = try Buffer.init(comp.arena(), name); - comp.llvm_triple = try util.getTriple(comp.arena(), target); + comp.llvm_triple = try util.getLLVMTriple(comp.arena(), target); comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple); comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" }); @@ -451,17 +456,12 @@ pub const Compilation = struct { const reloc_mode = if (is_static) llvm.RelocStatic else llvm.RelocPIC; - // LLVM creates invalid binaries on Windows sometimes. - // See https://github.com/ziglang/zig/issues/508 - // As a workaround we do not use target native features on Windows. var target_specific_cpu_args: ?[*:0]u8 = null; var target_specific_cpu_features: ?[*:0]u8 = null; defer llvm.DisposeMessage(target_specific_cpu_args); defer llvm.DisposeMessage(target_specific_cpu_features); - if (target == Target.Native and !target.isWindows()) { - target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory; - target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory; - } + + // TODO detect native CPU & features here comp.target_machine = llvm.CreateTargetMachine( comp.llvm_target, @@ -1125,7 +1125,9 @@ pub const Compilation = struct { self.libc_link_lib = link_lib; // get a head start on looking for the native libc - if (self.target == Target.Native and self.override_libc == null) { + // TODO this is missing a bunch of logic related to whether the target is native + // and whether we can build libc + if (self.override_libc == null) { try self.deinit_group.call(startFindingNativeLibC, .{self}); } } diff --git a/src-self-hosted/errmsg.zig b/src-self-hosted/errmsg.zig index c1ebf0058e..606c8c4b3a 100644 --- a/src-self-hosted/errmsg.zig +++ b/src-self-hosted/errmsg.zig @@ -164,8 +164,7 @@ pub const Msg = struct { const realpath_copy = try mem.dupe(comp.gpa(), u8, tree_scope.root().realpath); errdefer comp.gpa().free(realpath_copy); - var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; - try parse_error.render(&tree_scope.tree.tokens, out_stream); + try parse_error.render(&tree_scope.tree.tokens, text_buf.outStream()); const msg = try comp.gpa().create(Msg); msg.* = Msg{ @@ -204,8 +203,7 @@ pub const Msg = struct { const realpath_copy = try mem.dupe(allocator, u8, realpath); errdefer allocator.free(realpath_copy); - var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; - try parse_error.render(&tree.tokens, out_stream); + try parse_error.render(&tree.tokens, text_buf.outStream()); const msg = try allocator.create(Msg); msg.* = Msg{ @@ -272,7 +270,7 @@ pub const Msg = struct { }); try stream.writeByteNTimes(' ', start_loc.column); try stream.writeByteNTimes('~', last_token.end - first_token.start); - try stream.write("\n"); + try stream.writeAll("\n"); } pub fn printToFile(msg: *const Msg, file: fs.File, color: Color) !void { @@ -281,7 +279,6 @@ pub const Msg = struct { .On => true, .Off => false, }; - var stream = &file.outStream().stream; - return msg.printToStream(stream, color_on); + return msg.printToStream(file.outStream(), color_on); } }; diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 2e65962d41..7453f6fbd7 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -1099,7 +1099,6 @@ pub const Builder = struct { .Await => return error.Unimplemented, .BitNot => return error.Unimplemented, .BoolNot => return error.Unimplemented, - .Cancel => return error.Unimplemented, .OptionalType => return error.Unimplemented, .Negation => return error.Unimplemented, .NegationWrap => return error.Unimplemented, @@ -1188,6 +1187,7 @@ pub const Builder = struct { .ParamDecl => return error.Unimplemented, .FieldInitializer => return error.Unimplemented, .EnumLiteral => return error.Unimplemented, + .Noasync => return error.Unimplemented, } } diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 1efa15574a..e67b307097 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -56,12 +56,13 @@ pub fn link(comp: *Compilation) !void { if (comp.haveLibC()) { // TODO https://github.com/ziglang/zig/issues/3190 var libc = ctx.comp.override_libc orelse blk: { - switch (comp.target) { - Target.Native => { - break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; - }, - else => return error.LibCRequiredButNotProvidedOrFound, - } + @panic("this code has bitrotted"); + //switch (comp.target) { + // Target.Native => { + // break :blk comp.zig_compiler.getNativeLibC() catch return error.LibCRequiredButNotProvidedOrFound; + // }, + // else => return error.LibCRequiredButNotProvidedOrFound, + //} }; ctx.libc = libc; } @@ -155,11 +156,11 @@ fn constructLinkerArgsElf(ctx: *Context) !void { //bool shared = !g->is_static && is_lib; //Buf *soname = nullptr; if (ctx.comp.is_static) { - if (util.isArmOrThumb(ctx.comp.target)) { - try ctx.args.append("-Bstatic"); - } else { - try ctx.args.append("-static"); - } + //if (util.isArmOrThumb(ctx.comp.target)) { + // try ctx.args.append("-Bstatic"); + //} else { + // try ctx.args.append("-static"); + //} } //} else if (shared) { // lj->args.append("-shared"); @@ -176,29 +177,24 @@ fn constructLinkerArgsElf(ctx: *Context) !void { if (ctx.link_in_crt) { const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o"; - const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o"; - try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o); - try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o"); - try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino); + try addPathJoin(ctx, ctx.libc.crt_dir.?, crt1o); + try addPathJoin(ctx, ctx.libc.crt_dir.?, "crti.o"); } if (ctx.comp.haveLibC()) { try ctx.args.append("-L"); // TODO addNullByte should probably return [:0]u8 - try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr)); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.crt_dir.?)).ptr)); - try ctx.args.append("-L"); - try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr)); - - if (!ctx.comp.is_static) { - const dl = blk: { - if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; - if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; - return error.LibCMissingDynamicLinker; - }; - try ctx.args.append("-dynamic-linker"); - try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); - } + //if (!ctx.comp.is_static) { + // const dl = blk: { + // //if (ctx.libc.dynamic_linker_path) |dl| break :blk dl; + // //if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; + // return error.LibCMissingDynamicLinker; + // }; + // try ctx.args.append("-dynamic-linker"); + // try ctx.args.append(@ptrCast([*:0]const u8, (try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr)); + //} } //if (shared) { @@ -265,13 +261,12 @@ fn constructLinkerArgsElf(ctx: *Context) !void { // crt end if (ctx.link_in_crt) { - try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o"); - try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o"); + try addPathJoin(ctx, ctx.libc.crt_dir.?, "crtn.o"); } - if (ctx.comp.target != Target.Native) { - try ctx.args.append("--allow-shlib-undefined"); - } + //if (ctx.comp.target != Target.Native) { + // try ctx.args.append("--allow-shlib-undefined"); + //} } fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { @@ -287,7 +282,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { try ctx.args.append("-DEBUG"); } - switch (ctx.comp.target.getArch()) { + switch (ctx.comp.target.cpu.arch) { .i386 => try ctx.args.append("-MACHINE:X86"), .x86_64 => try ctx.args.append("-MACHINE:X64"), .aarch64 => try ctx.args.append("-MACHINE:ARM"), @@ -302,7 +297,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { if (ctx.comp.haveLibC()) { try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.msvc_lib_dir.?})).ptr)); try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.kernel32_lib_dir.?})).ptr)); - try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.lib_dir.?})).ptr)); + try ctx.args.append(@ptrCast([*:0]const u8, (try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", .{ctx.libc.crt_dir.?})).ptr)); } if (ctx.link_in_crt) { @@ -417,7 +412,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } }, .IPhoneOS => { - if (ctx.comp.target.getArch() == .aarch64) { + if (ctx.comp.target.cpu.arch == .aarch64) { // iOS does not need any crt1 files for arm64 } else if (platform.versionLessThan(3, 1)) { try ctx.args.append("-lcrt1.o"); @@ -435,28 +430,29 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } try addFnObjects(ctx); - if (ctx.comp.target == Target.Native) { - for (ctx.comp.link_libs_list.toSliceConst()) |lib| { - if (mem.eql(u8, lib.name, "c")) { - // on Darwin, libSystem has libc in it, but also you have to use it - // to make syscalls because the syscall numbers are not documented - // and change between versions. - // so we always link against libSystem - try ctx.args.append("-lSystem"); - } else { - if (mem.indexOfScalar(u8, lib.name, '/') == null) { - const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); - try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); - } else { - const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); - try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); - } - } - } - } else { - try ctx.args.append("-undefined"); - try ctx.args.append("dynamic_lookup"); - } + // TODO + //if (ctx.comp.target == Target.Native) { + // for (ctx.comp.link_libs_list.toSliceConst()) |lib| { + // if (mem.eql(u8, lib.name, "c")) { + // // on Darwin, libSystem has libc in it, but also you have to use it + // // to make syscalls because the syscall numbers are not documented + // // and change between versions. + // // so we always link against libSystem + // try ctx.args.append("-lSystem"); + // } else { + // if (mem.indexOfScalar(u8, lib.name, '/') == null) { + // const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", .{lib.name}); + // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); + // } else { + // const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name); + // try ctx.args.append(@ptrCast([*:0]const u8, arg.ptr)); + // } + // } + // } + //} else { + // try ctx.args.append("-undefined"); + // try ctx.args.append("dynamic_lookup"); + //} if (platform.kind == .MacOS) { if (platform.versionLessThan(10, 5)) { diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 20e39bd2a1..42a0873483 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -18,10 +18,6 @@ const Target = std.Target; const errmsg = @import("errmsg.zig"); const LibCInstallation = @import("libc_installation.zig").LibCInstallation; -var stderr_file: fs.File = undefined; -var stderr: *io.OutStream(fs.File.WriteError) = undefined; -var stdout: *io.OutStream(fs.File.WriteError) = undefined; - pub const io_mode = .evented; pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB @@ -51,17 +47,14 @@ const Command = struct { pub fn main() !void { const allocator = std.heap.c_allocator; - stdout = &std.io.getStdOut().outStream().stream; - - stderr_file = std.io.getStdErr(); - stderr = &stderr_file.outStream().stream; + const stderr = io.getStdErr().outStream(); const args = try process.argsAlloc(allocator); defer process.argsFree(allocator, args); if (args.len <= 1) { - try stderr.write("expected command argument\n\n"); - try stderr.write(usage); + try stderr.writeAll("expected command argument\n\n"); + try stderr.writeAll(usage); process.exit(1); } @@ -78,8 +71,8 @@ pub fn main() !void { } else if (mem.eql(u8, cmd, "libc")) { return cmdLibC(allocator, cmd_args); } else if (mem.eql(u8, cmd, "targets")) { - const info = try std.zig.system.NativeTargetInfo.detect(allocator); - defer info.deinit(allocator); + const info = try std.zig.system.NativeTargetInfo.detect(allocator, .{}); + const stdout = io.getStdOut().outStream(); return @import("print_targets.zig").cmdTargets(allocator, cmd_args, stdout, info.target); } else if (mem.eql(u8, cmd, "version")) { return cmdVersion(allocator, cmd_args); @@ -91,7 +84,7 @@ pub fn main() !void { return cmdInternal(allocator, cmd_args); } else { try stderr.print("unknown command: {}\n\n", .{args[1]}); - try stderr.write(usage); + try stderr.writeAll(usage); process.exit(1); } } @@ -156,6 +149,8 @@ const usage_build_generic = ; fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Compilation.Kind) !void { + const stderr = io.getStdErr().outStream(); + var color: errmsg.Color = .Auto; var build_mode: std.builtin.Mode = .Debug; var emit_bin = true; @@ -208,11 +203,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "--help")) { - try stdout.write(usage_build_generic); + try io.getStdOut().writeAll(usage_build_generic); process.exit(0); } else if (mem.eql(u8, arg, "--color")) { if (i + 1 >= args.len) { - try stderr.write("expected [auto|on|off] after --color\n"); + try stderr.writeAll("expected [auto|on|off] after --color\n"); process.exit(1); } i += 1; @@ -229,7 +224,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co } } else if (mem.eql(u8, arg, "--mode")) { if (i + 1 >= args.len) { - try stderr.write("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n"); + try stderr.writeAll("expected [Debug|ReleaseSafe|ReleaseFast|ReleaseSmall] after --mode\n"); process.exit(1); } i += 1; @@ -248,49 +243,49 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co } } else if (mem.eql(u8, arg, "--name")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --name\n"); + try stderr.writeAll("expected parameter after --name\n"); process.exit(1); } i += 1; provided_name = args[i]; } else if (mem.eql(u8, arg, "--ver-major")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --ver-major\n"); + try stderr.writeAll("expected parameter after --ver-major\n"); process.exit(1); } i += 1; version.major = try std.fmt.parseInt(u32, args[i], 10); } else if (mem.eql(u8, arg, "--ver-minor")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --ver-minor\n"); + try stderr.writeAll("expected parameter after --ver-minor\n"); process.exit(1); } i += 1; version.minor = try std.fmt.parseInt(u32, args[i], 10); } else if (mem.eql(u8, arg, "--ver-patch")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --ver-patch\n"); + try stderr.writeAll("expected parameter after --ver-patch\n"); process.exit(1); } i += 1; version.patch = try std.fmt.parseInt(u32, args[i], 10); } else if (mem.eql(u8, arg, "--linker-script")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --linker-script\n"); + try stderr.writeAll("expected parameter after --linker-script\n"); process.exit(1); } i += 1; linker_script = args[i]; } else if (mem.eql(u8, arg, "--libc")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after --libc\n"); + try stderr.writeAll("expected parameter after --libc\n"); process.exit(1); } i += 1; libc_arg = args[i]; } else if (mem.eql(u8, arg, "-mllvm")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after -mllvm\n"); + try stderr.writeAll("expected parameter after -mllvm\n"); process.exit(1); } i += 1; @@ -300,14 +295,14 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co try mllvm_flags.append(args[i]); } else if (mem.eql(u8, arg, "-mmacosx-version-min")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after -mmacosx-version-min\n"); + try stderr.writeAll("expected parameter after -mmacosx-version-min\n"); process.exit(1); } i += 1; macosx_version_min = args[i]; } else if (mem.eql(u8, arg, "-mios-version-min")) { if (i + 1 >= args.len) { - try stderr.write("expected parameter after -mios-version-min\n"); + try stderr.writeAll("expected parameter after -mios-version-min\n"); process.exit(1); } i += 1; @@ -348,7 +343,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co linker_rdynamic = true; } else if (mem.eql(u8, arg, "--pkg-begin")) { if (i + 2 >= args.len) { - try stderr.write("expected [name] [path] after --pkg-begin\n"); + try stderr.writeAll("expected [name] [path] after --pkg-begin\n"); process.exit(1); } i += 1; @@ -363,7 +358,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co if (cur_pkg.parent) |parent| { cur_pkg = parent; } else { - try stderr.write("encountered --pkg-end with no matching --pkg-begin\n"); + try stderr.writeAll("encountered --pkg-end with no matching --pkg-begin\n"); process.exit(1); } } else if (mem.startsWith(u8, arg, "-l")) { @@ -411,18 +406,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co var it = mem.separate(basename, "."); break :blk it.next() orelse basename; } else { - try stderr.write("--name [name] not provided and unable to infer\n"); + try stderr.writeAll("--name [name] not provided and unable to infer\n"); process.exit(1); } }; if (root_src_file == null and link_objects.len == 0 and assembly_files.len == 0) { - try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); + try stderr.writeAll("Expected source file argument or at least one --object or --assembly argument\n"); process.exit(1); } if (out_type == Compilation.Kind.Obj and link_objects.len != 0) { - try stderr.write("When building an object file, --object arguments are invalid\n"); + try stderr.writeAll("When building an object file, --object arguments are invalid\n"); process.exit(1); } @@ -440,7 +435,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co &zig_compiler, root_name, root_src_file, - Target.Native, + .{}, out_type, build_mode, !is_dynamic, @@ -478,7 +473,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co comp.linker_rdynamic = linker_rdynamic; if (macosx_version_min != null and ios_version_min != null) { - try stderr.write("-mmacosx-version-min and -mios-version-min options not allowed together\n"); + try stderr.writeAll("-mmacosx-version-min and -mios-version-min options not allowed together\n"); process.exit(1); } @@ -501,6 +496,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co } fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { + const stderr_file = io.getStdErr(); + const stderr = stderr_file.outStream(); var count: usize = 0; while (!comp.cancelled) { const build_event = comp.events.get(); @@ -551,7 +548,8 @@ const Fmt = struct { }; fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void { - libc.parse(allocator, libc_paths_file, stderr) catch |err| { + const stderr = io.getStdErr().outStream(); + libc.* = LibCInstallation.parse(allocator, libc_paths_file, stderr) catch |err| { stderr.print("Unable to parse libc path file '{}': {}.\n" ++ "Try running `zig libc` to see an example for the native target.\n", .{ libc_paths_file, @@ -562,6 +560,7 @@ fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_fil } fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { + const stderr = io.getStdErr().outStream(); switch (args.len) { 0 => {}, 1 => { @@ -582,10 +581,12 @@ fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void { stderr.print("unable to find libc: {}\n", .{@errorName(err)}) catch {}; process.exit(1); }; - libc.render(stdout) catch process.exit(1); + libc.render(io.getStdOut().outStream()) catch process.exit(1); } fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { + const stderr_file = io.getStdErr(); + const stderr = stderr_file.outStream(); var color: errmsg.Color = .Auto; var stdin_flag: bool = false; var check_flag: bool = false; @@ -597,11 +598,12 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { const arg = args[i]; if (mem.startsWith(u8, arg, "-")) { if (mem.eql(u8, arg, "--help")) { - try stdout.write(usage_fmt); + const stdout = io.getStdOut().outStream(); + try stdout.writeAll(usage_fmt); process.exit(0); } else if (mem.eql(u8, arg, "--color")) { if (i + 1 >= args.len) { - try stderr.write("expected [auto|on|off] after --color\n"); + try stderr.writeAll("expected [auto|on|off] after --color\n"); process.exit(1); } i += 1; @@ -632,14 +634,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { if (stdin_flag) { if (input_files.len != 0) { - try stderr.write("cannot use --stdin with positional arguments\n"); + try stderr.writeAll("cannot use --stdin with positional arguments\n"); process.exit(1); } - var stdin_file = io.getStdIn(); - var stdin = stdin_file.inStream(); + const stdin = io.getStdIn().inStream(); - const source_code = try stdin.stream.readAllAlloc(allocator, max_src_size); + const source_code = try stdin.readAllAlloc(allocator, max_src_size); defer allocator.free(source_code); const tree = std.zig.parse(allocator, source_code) catch |err| { @@ -653,7 +654,7 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, tree, ""); defer msg.destroy(); - try msg.printToFile(stderr_file, color); + try msg.printToFile(io.getStdErr(), color); } if (tree.errors.len != 0) { process.exit(1); @@ -664,12 +665,13 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { process.exit(code); } + const stdout = io.getStdOut().outStream(); _ = try std.zig.render(allocator, stdout, tree); return; } if (input_files.len == 0) { - try stderr.write("expected at least one source file argument\n"); + try stderr.writeAll("expected at least one source file argument\n"); process.exit(1); } @@ -713,6 +715,9 @@ const FmtError = error{ } || fs.File.OpenError; async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtError!void { + const stderr_file = io.getStdErr(); + const stderr = stderr_file.outStream(); + const file_path = try std.mem.dupe(fmt.allocator, u8, file_path_ref); defer fmt.allocator.free(file_path); @@ -791,11 +796,13 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro } fn cmdVersion(allocator: *Allocator, args: []const []const u8) !void { + const stdout = io.getStdOut().outStream(); try stdout.print("{}\n", .{c.ZIG_VERSION_STRING}); } fn cmdHelp(allocator: *Allocator, args: []const []const u8) !void { - try stdout.write(usage); + const stdout = io.getStdOut(); + try stdout.writeAll(usage); } pub const info_zen = @@ -816,7 +823,7 @@ pub const info_zen = ; fn cmdZen(allocator: *Allocator, args: []const []const u8) !void { - try stdout.write(info_zen); + try io.getStdOut().writeAll(info_zen); } const usage_internal = @@ -829,8 +836,9 @@ const usage_internal = ; fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { + const stderr = io.getStdErr().outStream(); if (args.len == 0) { - try stderr.write(usage_internal); + try stderr.writeAll(usage_internal); process.exit(1); } @@ -849,10 +857,11 @@ fn cmdInternal(allocator: *Allocator, args: []const []const u8) !void { } try stderr.print("unknown sub command: {}\n\n", .{args[0]}); - try stderr.write(usage_internal); + try stderr.writeAll(usage_internal); } fn cmdInternalBuildInfo(allocator: *Allocator, args: []const []const u8) !void { + const stdout = io.getStdOut().outStream(); try stdout.print( \\ZIG_CMAKE_BINARY_DIR {} \\ZIG_CXX_COMPILER {} diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig index 2a7bf4d9cc..ec68823ebd 100644 --- a/src-self-hosted/util.zig +++ b/src-self-hosted/util.zig @@ -3,8 +3,7 @@ const Target = std.Target; const llvm = @import("llvm.zig"); pub fn getDarwinArchString(self: Target) [:0]const u8 { - const arch = self.getArch(); - switch (arch) { + switch (self.cpu.arch) { .aarch64 => return "arm64", .thumb, .arm, @@ -34,3 +33,15 @@ pub fn initializeAllTargets() void { llvm.InitializeAllAsmPrinters(); llvm.InitializeAllAsmParsers(); } + +pub fn getLLVMTriple(allocator: *std.mem.Allocator, target: std.Target) !std.Buffer { + var result = try std.Buffer.initSize(allocator, 0); + errdefer result.deinit(); + + try result.outStream().print( + "{}-unknown-{}-{}", + .{ @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi) }, + ); + + return result; +} From 013ada1b59e50bbbab19acab0a79dae72133999a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 18 Mar 2020 09:35:44 +0100 Subject: [PATCH 24/79] std: More type checks for Thread startFn return type Closes #4756 --- lib/std/thread.zig | 51 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/std/thread.zig b/lib/std/thread.zig index b2f8a44a47..596a8f3cd9 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -6,6 +6,8 @@ const windows = std.os.windows; const c = std.c; const assert = std.debug.assert; +const bad_startfn_ret = "expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"; + pub const Thread = struct { data: Data, @@ -158,15 +160,34 @@ pub const Thread = struct { }; fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; + switch (@typeInfo(@TypeOf(startFn).ReturnType)) { - .Int => { - return startFn(arg); + .NoReturn => { + startFn(arg); }, .Void => { startFn(arg); return 0; }, - else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"), + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_startfn_ret); + } + return startFn(arg); + }, + .ErrorUnion => |info| { + if (info.payload != void) { + @compileError(bad_startfn_ret); + } + startFn(arg) catch |err| { + std.debug.warn("error: {}\n", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + }; + return 0; + }, + else => @compileError(bad_startfn_ret), } } }; @@ -202,14 +223,32 @@ pub const Thread = struct { const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; switch (@typeInfo(@TypeOf(startFn).ReturnType)) { - .Int => { - return startFn(arg); + .NoReturn => { + startFn(arg); }, .Void => { startFn(arg); return 0; }, - else => @compileError("expected return type of startFn to be 'u8', 'noreturn', 'void', or '!void'"), + .Int => |info| { + if (info.bits != 8) { + @compileError(bad_startfn_ret); + } + return startFn(arg); + }, + .ErrorUnion => |info| { + if (info.payload != void) { + @compileError(bad_startfn_ret); + } + startFn(arg) catch |err| { + std.debug.warn("error: {}\n", .{@errorName(err)}); + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + }; + return 0; + }, + else => @compileError(bad_startfn_ret), } } fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { From 1479c28b496e7c1db134b51f23dd2eb934b123bb Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 16 Mar 2020 18:42:01 +0100 Subject: [PATCH 25/79] ir: Correct ABI size calculation for arrays Zero-length array with a sentinel may not have zero size. Closes #4749 --- src/analyze.cpp | 17 +++++++---------- src/codegen.cpp | 4 +++- test/stage1/behavior/array.zig | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 33d28269b9..d0f8979c79 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -803,13 +803,7 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi } buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); - size_t full_array_size; - if (array_size == 0) { - full_array_size = 0; - } else { - full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); - } - + size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); entry->size_in_bits = child_type->size_in_bits * full_array_size; entry->abi_align = child_type->abi_align; entry->abi_size = child_type->abi_size * full_array_size; @@ -1197,7 +1191,8 @@ Error type_val_resolve_zero_bits(CodeGen *g, ZigValue *type_val, ZigType *parent LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_array_type->length < 1) { + // The sentinel counts as an extra element + if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) { *is_zero_bits = true; return ErrorNone; } @@ -1452,7 +1447,8 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV case LazyValueIdArrayType: { LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - if (lazy_array_type->length < 1) + // The sentinel counts as an extra element + if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) return OnePossibleValueYes; return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); } @@ -5739,7 +5735,8 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdUnreachable: return OnePossibleValueYes; case ZigTypeIdArray: - if (type_entry->data.array.len == 0) + // The sentinel counts as an extra element + if (type_entry->data.array.len == 0 && type_entry->data.array.sentinel == nullptr) return OnePossibleValueYes; return type_has_one_possible_value(g, type_entry->data.array.child_type); case ZigTypeIdStruct: diff --git a/src/codegen.cpp b/src/codegen.cpp index dc6fe04cb4..75f3223250 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3584,7 +3584,9 @@ static bool value_is_all_undef(CodeGen *g, ZigValue *const_val) { } return true; } else if (const_val->type->id == ZigTypeIdArray) { - return value_is_all_undef_array(g, const_val, const_val->type->data.array.len); + const size_t full_len = const_val->type->data.array.len + + (const_val->type->data.array.sentinel != nullptr); + return value_is_all_undef_array(g, const_val, full_len); } else if (const_val->type->id == ZigTypeIdVector) { return value_is_all_undef_array(g, const_val, const_val->type->data.vector.len); } else { diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index da56864cc9..1f2d4a2f6b 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -376,3 +376,23 @@ test "type deduction for array subscript expression" { S.doTheTest(); comptime S.doTheTest(); } + +test "sentinel element count towards the ABI size calculation" { + const S = struct { + fn doTheTest() void { + const T = packed struct { + fill_pre: u8 = 0x55, + data: [0:0]u8 = undefined, + fill_post: u8 = 0xAA, + }; + var x = T{}; + var as_slice = mem.asBytes(&x); + expectEqual(@as(usize, 3), as_slice.len); + expectEqual(@as(u8, 0x55), as_slice[0]); + expectEqual(@as(u8, 0xAA), as_slice[2]); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} From 63a4dbc30d3ef3c7f8a8c6a2ba2087eaab8b830a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 11:11:41 -0400 Subject: [PATCH 26/79] array sentinel does not count towards type_has_one_possible_value --- src/analyze.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index d0f8979c79..fbd7d85ac1 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -1447,8 +1447,7 @@ static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ZigV case LazyValueIdArrayType: { LazyValueArrayType *lazy_array_type = reinterpret_cast(type_val->data.x_lazy); - // The sentinel counts as an extra element - if (lazy_array_type->length == 0 && lazy_array_type->sentinel == nullptr) + if (lazy_array_type->length == 0) return OnePossibleValueYes; return type_val_resolve_has_one_possible_value(g, lazy_array_type->elem_type->value); } @@ -5735,8 +5734,7 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { case ZigTypeIdUnreachable: return OnePossibleValueYes; case ZigTypeIdArray: - // The sentinel counts as an extra element - if (type_entry->data.array.len == 0 && type_entry->data.array.sentinel == nullptr) + if (type_entry->data.array.len == 0) return OnePossibleValueYes; return type_has_one_possible_value(g, type_entry->data.array.child_type); case ZigTypeIdStruct: From 11a4ce42c16c17422cd272f154c9c33231bcc61a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 28 Feb 2020 12:06:43 +0100 Subject: [PATCH 27/79] zig fmt: Respect trailing commas in error set declarations The logic is not perfect as it doesn't take into account the presence of doc comments, but it's an improvement over the status quo. --- lib/std/zig/parser_test.zig | 2 ++ lib/std/zig/render.zig | 58 ++++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index d00568e49f..e1fe07a57c 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1509,6 +1509,8 @@ test "zig fmt: error set declaration" { \\const Error = error{OutOfMemory}; \\const Error = error{}; \\ + \\const Error = error{ OutOfMemory, OutOfTime }; + \\ ); } diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index a3a72fb23f..23dc9e02ac 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -1268,25 +1268,51 @@ fn renderExpression( } try renderToken(tree, stream, err_set_decl.error_token, indent, start_col, Space.None); // error - try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { - const new_indent = indent + indent_delta; - var it = err_set_decl.decls.iterator(0); - while (it.next()) |node| { - try stream.writeByteNTimes(' ', new_indent); + const src_has_trailing_comma = blk: { + const maybe_comma = tree.prevToken(err_set_decl.rbrace_token); + break :blk tree.tokens.at(maybe_comma).id == .Comma; + }; - if (it.peek()) |next_node| { - try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); - try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , + if (src_has_trailing_comma) { + try renderToken(tree, stream, lbrace, indent, start_col, Space.Newline); // { + const new_indent = indent + indent_delta; - try renderExtraNewline(tree, stream, start_col, next_node.*); - } else { - try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); + var it = err_set_decl.decls.iterator(0); + while (it.next()) |node| { + try stream.writeByteNTimes(' ', new_indent); + + if (it.peek()) |next_node| { + try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.None); + try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, start_col, Space.Newline); // , + + try renderExtraNewline(tree, stream, start_col, next_node.*); + } else { + try renderExpression(allocator, stream, tree, new_indent, start_col, node.*, Space.Comma); + } } - } - try stream.writeByteNTimes(' ', indent); - return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } + try stream.writeByteNTimes(' ', indent); + return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } + } else { + try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); // { + + var it = err_set_decl.decls.iterator(0); + while (it.next()) |node| { + if (it.peek()) |next_node| { + try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); + + const comma_token = tree.nextToken(node.*.lastToken()); + assert(tree.tokens.at(comma_token).id == .Comma); + try renderToken(tree, stream, comma_token, indent, start_col, Space.Space); // , + try renderExtraNewline(tree, stream, start_col, next_node.*); + } else { + try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Space); + } + } + + return renderToken(tree, stream, err_set_decl.rbrace_token, indent, start_col, space); // } + } }, .ErrorTag => { @@ -1589,8 +1615,7 @@ fn renderExpression( } } else { var it = switch_case.items.iterator(0); - while (true) { - const node = it.next().?; + while (it.next()) |node| { if (it.peek()) |next_node| { try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); @@ -1601,7 +1626,6 @@ fn renderExpression( } else { try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.Comma); try stream.writeByteNTimes(' ', indent); - break; } } } From 4843c3b4c386008418ff8ab7238feebab3711352 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 16 Mar 2020 11:39:18 +0100 Subject: [PATCH 28/79] std: Introduce fnctl wrapper --- lib/std/os.zig | 25 +++++++++++++++++++++++++ lib/std/os/bits/dragonfly.zig | 2 ++ lib/std/os/bits/freebsd.zig | 2 ++ lib/std/os/bits/linux.zig | 2 ++ lib/std/os/bits/netbsd.zig | 2 ++ lib/std/os/linux.zig | 4 ++++ lib/std/os/test.zig | 31 ++++++++++++++++++++++++++++++- 7 files changed, 67 insertions(+), 1 deletion(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 3333a91788..2dec2c4c1d 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -3163,6 +3163,31 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 { } } +pub const FcntlError = error{ + PermissionDenied, + FileBusy, + ProcessFdQuotaExceeded, + Locked, +} || UnexpectedError; + +pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize { + while (true) { + const rc = system.fcntl(fd, cmd, arg); + switch (errno(rc)) { + 0 => return @intCast(usize, rc), + EINTR => continue, + EACCES => return error.Locked, + EBADF => unreachable, + EBUSY => return error.FileBusy, + EINVAL => unreachable, // invalid parameters + EPERM => return error.PermissionDenied, + EMFILE => return error.ProcessFdQuotaExceeded, + ENOTDIR => unreachable, // invalid parameter + else => |err| return unexpectedErrno(err), + } + } +} + pub const RealPathError = error{ FileNotFound, AccessDenied, diff --git a/lib/std/os/bits/dragonfly.zig b/lib/std/os/bits/dragonfly.zig index 27b2733b76..4a9b51d472 100644 --- a/lib/std/os/bits/dragonfly.zig +++ b/lib/std/os/bits/dragonfly.zig @@ -283,6 +283,8 @@ pub const F_LOCK = 1; pub const F_TLOCK = 2; pub const F_TEST = 3; +pub const FD_CLOEXEC = 1; + pub const AT_FDCWD = -328243; pub const AT_SYMLINK_NOFOLLOW = 1; pub const AT_REMOVEDIR = 2; diff --git a/lib/std/os/bits/freebsd.zig b/lib/std/os/bits/freebsd.zig index 02fe7e75b3..6f97884e16 100644 --- a/lib/std/os/bits/freebsd.zig +++ b/lib/std/os/bits/freebsd.zig @@ -355,6 +355,8 @@ pub const F_GETOWN_EX = 16; pub const F_GETOWNER_UIDS = 17; +pub const FD_CLOEXEC = 1; + pub const SEEK_SET = 0; pub const SEEK_CUR = 1; pub const SEEK_END = 2; diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index 2a58c14490..89364909c9 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -136,6 +136,8 @@ pub const MAP_FIXED_NOREPLACE = 0x100000; /// For anonymous mmap, memory could be uninitialized pub const MAP_UNINITIALIZED = 0x4000000; +pub const FD_CLOEXEC = 1; + pub const F_OK = 0; pub const X_OK = 1; pub const W_OK = 2; diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig index 735485695a..4abd4c8c5e 100644 --- a/lib/std/os/bits/netbsd.zig +++ b/lib/std/os/bits/netbsd.zig @@ -312,6 +312,8 @@ pub const F_GETLK = 7; pub const F_SETLK = 8; pub const F_SETLKW = 9; +pub const FD_CLOEXEC = 1; + pub const SEEK_SET = 0; pub const SEEK_CUR = 1; pub const SEEK_END = 2; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index f3265eaa61..ae48d831cf 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -588,6 +588,10 @@ pub fn waitpid(pid: pid_t, status: *u32, flags: u32) usize { return syscall4(SYS_wait4, @bitCast(usize, @as(isize, pid)), @ptrToInt(status), flags, 0); } +pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) usize { + return syscall3(SYS_fcntl, @bitCast(usize, @as(isize, fd)), @bitCast(usize, @as(isize, cmd)), arg); +} + var vdso_clock_gettime = @ptrCast(?*const c_void, init_vdso_clock_gettime); // We must follow the C calling convention when we call into the VDSO diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 1ef6798b50..b0452f4d66 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -1,7 +1,8 @@ const std = @import("../std.zig"); const os = std.os; const testing = std.testing; -const expect = std.testing.expect; +const expect = testing.expect; +const expectEqual = testing.expectEqual; const io = std.io; const fs = std.fs; const mem = std.mem; @@ -446,3 +447,31 @@ test "getenv" { expect(os.getenvZ("BOGUSDOESNOTEXISTENVVAR") == null); } } + +test "fcntl" { + if (builtin.os.tag == .windows) + return error.SkipZigTest; + + const test_out_file = "os_tmp_test"; + + const file = try fs.cwd().createFile(test_out_file, .{}); + defer file.close(); + + // Note: The test assumes createFile opens the file with O_CLOEXEC + { + const flags = try os.fcntl(file.handle, os.F_GETFD, 0); + expect((flags & os.FD_CLOEXEC) != 0); + } + { + _ = try os.fcntl(file.handle, os.F_SETFD, 0); + const flags = try os.fcntl(file.handle, os.F_GETFD, 0); + expect((flags & os.FD_CLOEXEC) == 0); + } + { + _ = try os.fcntl(file.handle, os.F_SETFD, os.FD_CLOEXEC); + const flags = try os.fcntl(file.handle, os.F_GETFD, 0); + expect((flags & os.FD_CLOEXEC) != 0); + } + + try fs.cwd().deleteFile(test_out_file); +} From e15605e1c1f28e06035a6740619295151195dabb Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 16 Mar 2020 12:01:41 +0100 Subject: [PATCH 29/79] std: Safety check for iterate() Calling iterate() on a Dir object returned by openDirTraverse is always an error. --- lib/std/fs.zig | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 231235baf5..7e647230e6 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -555,6 +555,36 @@ pub const Dir = struct { }; pub fn iterate(self: Dir) Iterator { + // Make sure the directory was not open with openDirTraverse + if (std.debug.runtime_safety) { + var ok = true; + + if (builtin.os.tag == .windows) { + const w = os.windows; + + var io_status_block: w.IO_STATUS_BLOCK = undefined; + var info: w.FILE_ACCESS_INFORMATION = undefined; + + const rc = w.ntdll.NtQueryInformationFile( + self.fd, + &io_status_block, + &info, + @sizeOf(w.FILE_ACCESS_INFORMATION), + .FileAccessInformation, + ); + assert(rc == .SUCCESS); + + ok = (info.AccessFlags & w.FILE_LIST_DIRECTORY) != 0; + } else if (@hasDecl(os, "O_PATH")) { + const f = os.fcntl(self.fd, os.F_GETFL, 0) catch unreachable; + ok = (f & os.O_PATH) == 0; + } + + if (!ok) { + std.debug.panic("iterate() called on Dir open with openDirTraverse", .{}); + } + } + switch (builtin.os.tag) { .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{ .dir = self, From c45fe2759fdb882efb4caf89a35136b8b205ee7c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 16 Mar 2020 12:03:16 +0100 Subject: [PATCH 30/79] build: Fix silly bug in directory traversal --- lib/std/build.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index e5d83f22b9..1b80f5f061 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2156,10 +2156,10 @@ pub const LibExeObjStep = struct { const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); if (self.output_dir) |output_dir| { - var src_dir = try std.fs.cwd().openDirTraverse(build_output_dir); + var src_dir = try std.fs.cwd().openDirList(build_output_dir); defer src_dir.close(); - var dest_dir = try std.fs.cwd().openDirList(output_dir); + var dest_dir = try std.fs.cwd().openDirTraverse(output_dir); defer dest_dir.close(); var it = src_dir.iterate(); From 27affde592653ac7f92489cec404b4bf3e0d1b29 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 14:45:01 -0400 Subject: [PATCH 31/79] (breaking) clarify openDir API * remove deprecated `std.fs.Dir` APIs * `std.fs.Dir.openDir` now takes a options struct with bool fields for `access_sub_paths` and `iterate`. It's now much more clear how opening directories works. * fixed the std lib and various zig code calling the wrong openDir function. * the runtime safety check for dir flags is removed in favor of the cheaper option of putting a comment on the same line as handling EBADF / ACCESS_DENIED, since that will show up in stack traces. --- lib/std/build.zig | 4 +- lib/std/build/write_file.zig | 2 +- lib/std/fs.zig | 163 +++++++------------------- lib/std/os/test.zig | 11 +- lib/std/zig/system.zig | 2 +- src-self-hosted/libc_installation.zig | 10 +- src-self-hosted/main.zig | 2 +- src-self-hosted/print_targets.zig | 2 +- src-self-hosted/stage2.zig | 2 +- 9 files changed, 62 insertions(+), 136 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index 1b80f5f061..7585fe20e2 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -2156,10 +2156,10 @@ pub const LibExeObjStep = struct { const build_output_dir = mem.trimRight(u8, output_dir_nl, "\r\n"); if (self.output_dir) |output_dir| { - var src_dir = try std.fs.cwd().openDirList(build_output_dir); + var src_dir = try std.fs.cwd().openDir(build_output_dir, .{ .iterate = true }); defer src_dir.close(); - var dest_dir = try std.fs.cwd().openDirTraverse(output_dir); + var dest_dir = try std.fs.cwd().openDir(output_dir, .{}); defer dest_dir.close(); var it = src_dir.iterate(); diff --git a/lib/std/build/write_file.zig b/lib/std/build/write_file.zig index 60c54336e0..0c3f628457 100644 --- a/lib/std/build/write_file.zig +++ b/lib/std/build/write_file.zig @@ -78,7 +78,7 @@ pub const WriteFileStep = struct { warn("unable to make path {}: {}\n", .{ self.output_dir, @errorName(err) }); return err; }; - var dir = try fs.cwd().openDirTraverse(self.output_dir); + var dir = try fs.cwd().openDir(self.output_dir, .{}); defer dir.close(); for (self.files.toSliceConst()) |file| { dir.writeFile(file.basename, file.bytes) catch |err| { diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 7e647230e6..e12c35ab8e 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -274,7 +274,7 @@ pub fn deleteTree(full_path: []const u8) !void { CannotDeleteRootDirectory, }.CannotDeleteRootDirectory; - var dir = try cwd().openDirList(dirname); + var dir = try cwd().openDir(dirname, .{}); defer dir.close(); return dir.deleteTree(path.basename(full_path)); @@ -339,7 +339,7 @@ pub const Dir = struct { if (rc == 0) return null; if (rc < 0) { switch (os.errno(rc)) { - os.EBADF => unreachable, + os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability os.EFAULT => unreachable, os.ENOTDIR => unreachable, os.EINVAL => unreachable, @@ -388,7 +388,7 @@ pub const Dir = struct { ); switch (os.errno(rc)) { 0 => {}, - os.EBADF => unreachable, + os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability os.EFAULT => unreachable, os.ENOTDIR => unreachable, os.EINVAL => unreachable, @@ -444,7 +444,7 @@ pub const Dir = struct { const rc = os.linux.getdents64(self.dir.fd, &self.buf, self.buf.len); switch (os.linux.getErrno(rc)) { 0 => {}, - os.EBADF => unreachable, + os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability os.EFAULT => unreachable, os.ENOTDIR => unreachable, os.EINVAL => unreachable, @@ -555,36 +555,6 @@ pub const Dir = struct { }; pub fn iterate(self: Dir) Iterator { - // Make sure the directory was not open with openDirTraverse - if (std.debug.runtime_safety) { - var ok = true; - - if (builtin.os.tag == .windows) { - const w = os.windows; - - var io_status_block: w.IO_STATUS_BLOCK = undefined; - var info: w.FILE_ACCESS_INFORMATION = undefined; - - const rc = w.ntdll.NtQueryInformationFile( - self.fd, - &io_status_block, - &info, - @sizeOf(w.FILE_ACCESS_INFORMATION), - .FileAccessInformation, - ); - assert(rc == .SUCCESS); - - ok = (info.AccessFlags & w.FILE_LIST_DIRECTORY) != 0; - } else if (@hasDecl(os, "O_PATH")) { - const f = os.fcntl(self.fd, os.F_GETFL, 0) catch unreachable; - ok = (f & os.O_PATH) == 0; - } - - if (!ok) { - std.debug.panic("iterate() called on Dir open with openDirTraverse", .{}); - } - } - switch (builtin.os.tag) { .macosx, .ios, .freebsd, .netbsd, .dragonfly => return Iterator{ .dir = self, @@ -626,16 +596,6 @@ pub const Dir = struct { DeviceBusy, } || os.UnexpectedError; - /// Deprecated; call `cwd().openDirList` directly. - pub fn open(dir_path: []const u8) OpenError!Dir { - return cwd().openDirList(dir_path); - } - - /// Deprecated; call `cwd().openDirListC` directly. - pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { - return cwd().openDirListC(dir_path_c); - } - pub fn close(self: *Dir) void { if (need_async_thread) { std.event.Loop.instance.?.close(self.fd); @@ -822,79 +782,61 @@ pub const Dir = struct { try os.fchdir(self.fd); } - /// Deprecated; call `openDirList` directly. - pub fn openDir(self: Dir, sub_path: []const u8) OpenError!Dir { - return self.openDirList(sub_path); - } + pub const OpenDirOptions = struct { + /// `true` means the opened directory can be used as the `Dir` parameter + /// for functions which operate based on an open directory handle. When `false`, + /// such operations are Illegal Behavior. + access_sub_paths: bool = true, - /// Deprecated; call `openDirListC` directly. - pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { - return self.openDirListC(sub_path_c); - } + /// `true` means the opened directory can be scanned for the files and sub-directories + /// of the result. It means the `iterate` function can be called. + iterate: bool = false, + }; - /// Opens a directory at the given path with the ability to access subpaths - /// of the result. Calling `iterate` on the result is illegal behavior; to - /// list the contents of a directory, open it with `openDirList`. - /// - /// Call `close` on the result when done. + /// Opens a directory at the given path. The directory is a system resource that remains + /// open until `close` is called on the result. /// /// Asserts that the path parameter has no null bytes. - /// TODO collapse this and `openDirList` into one function with an options parameter - pub fn openDirTraverse(self: Dir, sub_path: []const u8) OpenError!Dir { + pub fn openDir(self: Dir, sub_path: []const u8, args: OpenDirOptions) OpenError!Dir { if (builtin.os.tag == .windows) { const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); - return self.openDirTraverseW(&sub_path_w); + return self.openDirW(&sub_path_w, args); + } else { + const sub_path_c = try os.toPosixPath(sub_path); + return self.openDirC(&sub_path_c, args); } - - const sub_path_c = try os.toPosixPath(sub_path); - return self.openDirTraverseC(&sub_path_c); } - /// Opens a directory at the given path with the ability to access subpaths and list contents - /// of the result. If the ability to list contents is unneeded, `openDirTraverse` acts the - /// same and may be more efficient. - /// - /// Call `close` on the result when done. - /// - /// Asserts that the path parameter has no null bytes. - /// TODO collapse this and `openDirTraverse` into one function with an options parameter - pub fn openDirList(self: Dir, sub_path: []const u8) OpenError!Dir { - if (builtin.os.tag == .windows) { - const sub_path_w = try os.windows.sliceToPrefixedFileW(sub_path); - return self.openDirListW(&sub_path_w); - } - - const sub_path_c = try os.toPosixPath(sub_path); - return self.openDirListC(&sub_path_c); - } - - /// Same as `openDirTraverse` except the parameter is null-terminated. - pub fn openDirTraverseC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { + /// Same as `openDir` except the parameter is null-terminated. + pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8, args: OpenDirOptions) OpenError!Dir { if (builtin.os.tag == .windows) { const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); - return self.openDirTraverseW(&sub_path_w); - } else { + return self.openDirW(&sub_path_w, args); + } else if (!args.iterate) { const O_PATH = if (@hasDecl(os, "O_PATH")) os.O_PATH else 0; - return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC | O_PATH); - } - } - - /// Same as `openDirList` except the parameter is null-terminated. - pub fn openDirListC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { - if (builtin.os.tag == .windows) { - const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); - return self.openDirListW(&sub_path_w); + return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC | O_PATH); } else { - return self.openDirFlagsC(sub_path_c, os.O_RDONLY | os.O_CLOEXEC); + return self.openDirFlagsC(sub_path_c, os.O_DIRECTORY | os.O_RDONLY | os.O_CLOEXEC); } } + /// Same as `openDir` except the path parameter is WTF-16 encoded, NT-prefixed. + /// This function asserts the target OS is Windows. + pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16, args: OpenDirOptions) OpenError!Dir { + const w = os.windows; + // TODO remove some of these flags if args.access_sub_paths is false + const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | + w.SYNCHRONIZE | w.FILE_TRAVERSE; + const flags: u32 = if (args.iterate) base_flags else base_flags | w.FILE_LIST_DIRECTORY; + return self.openDirAccessMaskW(sub_path_w, flags); + } + + /// `flags` must contain `os.O_DIRECTORY`. fn openDirFlagsC(self: Dir, sub_path_c: [*:0]const u8, flags: u32) OpenError!Dir { - const os_flags = flags | os.O_DIRECTORY; const result = if (need_async_thread) - std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, os_flags, 0) + std.event.Loop.instance.?.openatZ(self.fd, sub_path_c, flags, 0) else - os.openatC(self.fd, sub_path_c, os_flags, 0); + os.openatC(self.fd, sub_path_c, flags, 0); const fd = result catch |err| switch (err) { error.FileTooBig => unreachable, // can't happen for directories error.IsDir => unreachable, // we're providing O_DIRECTORY @@ -905,22 +847,6 @@ pub const Dir = struct { return Dir{ .fd = fd }; } - /// Same as `openDirTraverse` except the path parameter is UTF16LE, NT-prefixed. - /// This function is Windows-only. - pub fn openDirTraverseW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { - const w = os.windows; - - return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE); - } - - /// Same as `openDirList` except the path parameter is UTF16LE, NT-prefixed. - /// This function is Windows-only. - pub fn openDirListW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { - const w = os.windows; - - return self.openDirAccessMaskW(sub_path_w, w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE | w.FILE_LIST_DIRECTORY); - } - fn openDirAccessMaskW(self: Dir, sub_path_w: [*:0]const u16, access_mask: u32) OpenError!Dir { const w = os.windows; @@ -1141,7 +1067,7 @@ pub const Dir = struct { error.Unexpected, => |e| return e, } - var dir = self.openDirList(sub_path) catch |err| switch (err) { + var dir = self.openDir(sub_path, .{ .iterate = true }) catch |err| switch (err) { error.NotDir => { if (got_access_denied) { return error.AccessDenied; @@ -1174,7 +1100,6 @@ pub const Dir = struct { var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; var dir_name: []const u8 = sub_path; - var parent_dir = self; // Here we must avoid recursion, in order to provide O(1) memory guarantee of this function. // Go through each entry and if it is not a directory, delete it. If it is a directory, @@ -1206,7 +1131,7 @@ pub const Dir = struct { => |e| return e, } - const new_dir = dir.openDirList(entry.name) catch |err| switch (err) { + const new_dir = dir.openDir(entry.name, .{ .iterate = true }) catch |err| switch (err) { error.NotDir => { if (got_access_denied) { return error.AccessDenied; @@ -1491,7 +1416,7 @@ pub const Walker = struct { try self.name_buffer.appendByte(path.sep); try self.name_buffer.append(base.name); if (base.kind == .Directory) { - var new_dir = top.dir_it.dir.openDirList(base.name) catch |err| switch (err) { + var new_dir = top.dir_it.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) { error.NameTooLong => unreachable, // no path sep in base.name else => |e| return e, }; @@ -1529,7 +1454,7 @@ pub const Walker = struct { pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { assert(!mem.endsWith(u8, dir_path, path.sep_str)); - var dir = try cwd().openDirList(dir_path); + var dir = try cwd().openDir(dir_path, .{ .iterate = true }); errdefer dir.close(); var name_buffer = try std.Buffer.init(allocator, dir_path); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index b0452f4d66..ae1df6802b 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -21,7 +21,7 @@ test "makePath, put some files in it, deleteTree" { try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); try fs.deleteTree("os_test_tmp"); - if (fs.cwd().openDirTraverse("os_test_tmp")) |dir| { + if (fs.cwd().openDir("os_test_tmp", .{})) |dir| { @panic("expected error"); } else |err| { expect(err == error.FileNotFound); @@ -49,7 +49,7 @@ test "sendfile" { try fs.cwd().makePath("os_test_tmp"); defer fs.deleteTree("os_test_tmp") catch {}; - var dir = try fs.cwd().openDirList("os_test_tmp"); + var dir = try fs.cwd().openDir("os_test_tmp", .{}); defer dir.close(); const line1 = "line1\n"; @@ -455,7 +455,10 @@ test "fcntl" { const test_out_file = "os_tmp_test"; const file = try fs.cwd().createFile(test_out_file, .{}); - defer file.close(); + defer { + file.close(); + fs.cwd().deleteFile(test_out_file) catch {}; + } // Note: The test assumes createFile opens the file with O_CLOEXEC { @@ -472,6 +475,4 @@ test "fcntl" { const flags = try os.fcntl(file.handle, os.F_GETFD, 0); expect((flags & os.FD_CLOEXEC) != 0); } - - try fs.cwd().deleteFile(test_out_file); } diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 88b3022bb2..5c47b68838 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -754,7 +754,7 @@ pub const NativeTargetInfo = struct { const rpath_list = mem.toSliceConst(u8, @ptrCast([*:0]u8, strtab[rpoff..].ptr)); var it = mem.tokenize(rpath_list, ":"); while (it.next()) |rpath| { - var dir = fs.cwd().openDirList(rpath) catch |err| switch (err) { + var dir = fs.cwd().openDir(rpath, .{}) catch |err| switch (err) { error.NameTooLong => unreachable, error.InvalidUtf8 => unreachable, error.BadPathName => unreachable, diff --git a/src-self-hosted/libc_installation.zig b/src-self-hosted/libc_installation.zig index c07ef03b51..996f705060 100644 --- a/src-self-hosted/libc_installation.zig +++ b/src-self-hosted/libc_installation.zig @@ -280,7 +280,7 @@ pub const LibCInstallation = struct { // search in reverse order const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1); const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " "); - var search_dir = fs.cwd().openDirList(search_path) catch |err| switch (err) { + var search_dir = fs.cwd().openDir(search_path, .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -335,7 +335,7 @@ pub const LibCInstallation = struct { const stream = result_buf.outStream(); try stream.print("{}\\Include\\{}\\ucrt", .{ search.path, search.version }); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -382,7 +382,7 @@ pub const LibCInstallation = struct { const stream = result_buf.outStream(); try stream.print("{}\\Lib\\{}\\ucrt\\{}", .{ search.path, search.version, arch_sub_dir }); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -437,7 +437,7 @@ pub const LibCInstallation = struct { const stream = result_buf.outStream(); try stream.print("{}\\Lib\\{}\\um\\{}", .{ search.path, search.version, arch_sub_dir }); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, @@ -475,7 +475,7 @@ pub const LibCInstallation = struct { try result_buf.append("\\include"); - var dir = fs.cwd().openDirList(result_buf.toSliceConst()) catch |err| switch (err) { + var dir = fs.cwd().openDir(result_buf.toSliceConst(), .{}) catch |err| switch (err) { error.FileNotFound, error.NotDir, error.NoDevice, diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index 42a0873483..f5faa26615 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -734,7 +734,7 @@ async fn fmtPath(fmt: *Fmt, file_path_ref: []const u8, check_mode: bool) FmtErro max_src_size, ) catch |err| switch (err) { error.IsDir, error.AccessDenied => { - var dir = try fs.cwd().openDirList(file_path); + var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); defer dir.close(); var group = event.Group(FmtError!void).init(fmt.allocator); diff --git a/src-self-hosted/print_targets.zig b/src-self-hosted/print_targets.zig index ad506425d2..997cfcfddc 100644 --- a/src-self-hosted/print_targets.zig +++ b/src-self-hosted/print_targets.zig @@ -72,7 +72,7 @@ pub fn cmdTargets( }; defer allocator.free(zig_lib_dir); - var dir = try std.fs.cwd().openDirList(zig_lib_dir); + var dir = try std.fs.cwd().openDir(zig_lib_dir, .{}); defer dir.close(); const vers_txt = try dir.readFileAlloc(allocator, "libc/glibc/vers.txt", 10 * 1024); diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 38dfbaf072..5393310f9e 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -319,7 +319,7 @@ fn fmtPath(fmt: *Fmt, file_path: []const u8, check_mode: bool) FmtError!void { const source_code = io.readFileAlloc(fmt.allocator, file_path) catch |err| switch (err) { error.IsDir, error.AccessDenied => { // TODO make event based (and dir.next()) - var dir = try fs.cwd().openDirList(file_path); + var dir = try fs.cwd().openDir(file_path, .{ .iterate = true }); defer dir.close(); var dir_it = dir.iterate(); From 46ffc798b6d9bb7be8b016ef7529092d647151ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 16:09:06 -0400 Subject: [PATCH 32/79] fix swapped logic for Windows Remove `std.fs.deleteTree`. Callers instead should use `std.fs.cwd().deleteTree`. Add `std.fs.deleteTreeAbsolute` for when the caller has an absolute path. --- doc/docgen.zig | 2 +- lib/std/build.zig | 4 +-- lib/std/fs.zig | 48 ++++++++++++++++----------------- lib/std/fs/watch.zig | 2 +- lib/std/os/test.zig | 6 ++--- src-self-hosted/compilation.zig | 3 +-- src-self-hosted/test.zig | 4 +-- test/cli.zig | 2 +- 8 files changed, 34 insertions(+), 37 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 4b9b94dbe4..32ad0cdc5d 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -48,7 +48,7 @@ pub fn main() !void { var toc = try genToc(allocator, &tokenizer); try fs.cwd().makePath(tmp_dir_name); - defer fs.deleteTree(tmp_dir_name) catch {}; + defer fs.cwd().deleteTree(tmp_dir_name) catch {}; try genHtml(allocator, &tokenizer, &toc, buffered_out_stream.outStream(), zig_exe); try buffered_out_stream.flush(); diff --git a/lib/std/build.zig b/lib/std/build.zig index 7585fe20e2..fd727c321e 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -377,7 +377,7 @@ pub const Builder = struct { if (self.verbose) { warn("rm {}\n", .{full_path}); } - fs.deleteTree(full_path) catch {}; + fs.cwd().deleteTree(full_path) catch {}; } // TODO remove empty directories @@ -2365,7 +2365,7 @@ pub const RemoveDirStep = struct { const self = @fieldParentPtr(RemoveDirStep, "step", step); const full_path = self.builder.pathFromRoot(self.dir_path); - fs.deleteTree(full_path) catch |err| { + fs.cwd().deleteTree(full_path) catch |err| { warn("Unable to remove {}: {}\n", .{ full_path, @errorName(err) }); return err; }; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index e12c35ab8e..bc02fd0c91 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -261,28 +261,6 @@ pub fn deleteDirW(dir_path: [*:0]const u16) !void { return os.rmdirW(dir_path); } -/// Removes a symlink, file, or directory. -/// If `full_path` is relative, this is equivalent to `Dir.deleteTree` with the -/// current working directory as the open directory handle. -/// If `full_path` is absolute, this is equivalent to `Dir.deleteTree` with the -/// base directory. -pub fn deleteTree(full_path: []const u8) !void { - if (path.isAbsolute(full_path)) { - const dirname = path.dirname(full_path) orelse return error{ - /// Attempt to remove the root file system path. - /// This error is unreachable if `full_path` is relative. - CannotDeleteRootDirectory, - }.CannotDeleteRootDirectory; - - var dir = try cwd().openDir(dirname, .{}); - defer dir.close(); - - return dir.deleteTree(path.basename(full_path)); - } else { - return cwd().deleteTree(full_path); - } -} - pub const Dir = struct { fd: os.fd_t, @@ -518,7 +496,8 @@ pub const Dir = struct { self.end_index = io.Information; switch (rc) { .SUCCESS => {}, - .ACCESS_DENIED => return error.AccessDenied, + .ACCESS_DENIED => return error.AccessDenied, // Double-check that the Dir was opened with iteration ability + else => return w.unexpectedStatus(rc), } } @@ -827,7 +806,7 @@ pub const Dir = struct { // TODO remove some of these flags if args.access_sub_paths is false const base_flags = w.STANDARD_RIGHTS_READ | w.FILE_READ_ATTRIBUTES | w.FILE_READ_EA | w.SYNCHRONIZE | w.FILE_TRAVERSE; - const flags: u32 = if (args.iterate) base_flags else base_flags | w.FILE_LIST_DIRECTORY; + const flags: u32 = if (args.iterate) base_flags | w.FILE_LIST_DIRECTORY else base_flags; return self.openDirAccessMaskW(sub_path_w, flags); } @@ -1304,7 +1283,7 @@ pub const Dir = struct { } }; -/// Returns an handle to the current working directory that is open for traversal. +/// Returns an handle to the current working directory. It is not opened with iteration capability. /// Closing the returned `Dir` is checked illegal behavior. Iterating over the result is illegal behavior. /// On POSIX targets, this function is comptime-callable. pub fn cwd() Dir { @@ -1382,6 +1361,25 @@ pub fn deleteFileAbsoluteW(absolute_path_w: [*:0]const u16) DeleteFileError!void return cwd().deleteFileW(absolute_path_w); } +/// Removes a symlink, file, or directory. +/// This is equivalent to `Dir.deleteTree` with the base directory. +/// Asserts that the path is absolute. See `Dir.deleteTree` for a function that +/// operates on both absolute and relative paths. +/// Asserts that the path parameter has no null bytes. +pub fn deleteTreeAbsolute(absolute_path: []const u8) !void { + assert(path.isAbsolute(absolute_path)); + const dirname = path.dirname(absolute_path) orelse return error{ + /// Attempt to remove the root file system path. + /// This error is unreachable if `absolute_path` is relative. + CannotDeleteRootDirectory, + }.CannotDeleteRootDirectory; + + var dir = try cwd().openDir(dirname, .{}); + defer dir.close(); + + return dir.deleteTree(path.basename(absolute_path)); +} + pub const Walker = struct { stack: std.ArrayList(StackItem), name_buffer: std.Buffer, diff --git a/lib/std/fs/watch.zig b/lib/std/fs/watch.zig index 3180240a72..96fe1538e4 100644 --- a/lib/std/fs/watch.zig +++ b/lib/std/fs/watch.zig @@ -619,7 +619,7 @@ test "write a file, watch it, write it again" { if (true) return error.SkipZigTest; try fs.cwd().makePath(test_tmp_dir); - defer os.deleteTree(test_tmp_dir) catch {}; + defer fs.cwd().deleteTree(test_tmp_dir) catch {}; const allocator = std.heap.page_allocator; return testFsWatch(&allocator); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index ae1df6802b..14a865904b 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -20,7 +20,7 @@ test "makePath, put some files in it, deleteTree" { try fs.cwd().makePath("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "c" ++ fs.path.sep_str ++ "file.txt", "nonsense"); try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "b" ++ fs.path.sep_str ++ "file2.txt", "blah"); - try fs.deleteTree("os_test_tmp"); + try fs.cwd().deleteTree("os_test_tmp"); if (fs.cwd().openDir("os_test_tmp", .{})) |dir| { @panic("expected error"); } else |err| { @@ -38,7 +38,7 @@ test "access file" { try io.writeFile("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", ""); try os.access("os_test_tmp" ++ fs.path.sep_str ++ "file.txt", os.F_OK); - try fs.deleteTree("os_test_tmp"); + try fs.cwd().deleteTree("os_test_tmp"); } fn testThreadIdFn(thread_id: *Thread.Id) void { @@ -47,7 +47,7 @@ fn testThreadIdFn(thread_id: *Thread.Id) void { test "sendfile" { try fs.cwd().makePath("os_test_tmp"); - defer fs.deleteTree("os_test_tmp") catch {}; + defer fs.cwd().deleteTree("os_test_tmp") catch {}; var dir = try fs.cwd().openDir("os_test_tmp", .{}); defer dir.close(); diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index d9f635ebbc..03e71c102d 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -520,8 +520,7 @@ pub const Compilation = struct { if (comp.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| { - // TODO evented I/O? - fs.deleteTree(tmp_dir) catch {}; + fs.cwd().deleteTree(tmp_dir) catch {}; } else |_| {}; } diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig index e87164c9fb..b146d6607a 100644 --- a/src-self-hosted/test.zig +++ b/src-self-hosted/test.zig @@ -57,11 +57,11 @@ pub const TestContext = struct { errdefer allocator.free(self.zig_lib_dir); try std.fs.cwd().makePath(tmp_dir_name); - errdefer std.fs.deleteTree(tmp_dir_name) catch {}; + errdefer std.fs.cwd().deleteTree(tmp_dir_name) catch {}; } fn deinit(self: *TestContext) void { - std.fs.deleteTree(tmp_dir_name) catch {}; + std.fs.cwd().deleteTree(tmp_dir_name) catch {}; allocator.free(self.zig_lib_dir); self.zig_compiler.deinit(); } diff --git a/test/cli.zig b/test/cli.zig index 9bc4a21c90..4c067d16ae 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -36,7 +36,7 @@ pub fn main() !void { testMissingOutputPath, }; for (test_fns) |testFn| { - try fs.deleteTree(dir_path); + try fs.cwd().deleteTree(dir_path); try fs.cwd().makeDir(dir_path); try testFn(zig_exe, dir_path); } From e3c92d05328d7b40927bed66e7c2500a7853cdc8 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 19 Mar 2020 11:52:15 +0100 Subject: [PATCH 33/79] ir: More changes to sentinel-terminated const arrays * Don't add an extra slot for the sentinel. Most of the code keeps using the constant value from the type descriptor, let's harmonize all the code dealing with sentinels. * Properly write out sentinel values when reinterpreting pointers at comptime. * Allow the reading of the 0th element in a `[0:S]T` type. --- src/analyze.cpp | 7 +----- src/codegen.cpp | 39 +++++++++++++++++++--------------- src/ir.cpp | 8 +++---- test/stage1/behavior/array.zig | 18 ++++++++++++++++ 4 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index fbd7d85ac1..9ba247012d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5806,18 +5806,13 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { // The elements array cannot be left unpopulated ZigType *array_type = result->type; ZigType *elem_type = array_type->data.array.child_type; - ZigValue *sentinel_value = array_type->data.array.sentinel; - const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); + const size_t elem_count = array_type->data.array.len; result->data.x_array.data.s_none.elements = g->pass1_arena->allocate(elem_count); for (size_t i = 0; i < elem_count; i += 1) { ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); } - if (sentinel_value != nullptr) { - ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1]; - copy_const_val(g, last_elem_val, sentinel_value); - } } else if (result->type->id == ZigTypeIdPointer) { result->data.x_ptr.special = ConstPtrSpecialRef; result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); diff --git a/src/codegen.cpp b/src/codegen.cpp index 75f3223250..3343807691 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3584,9 +3584,7 @@ static bool value_is_all_undef(CodeGen *g, ZigValue *const_val) { } return true; } else if (const_val->type->id == ZigTypeIdArray) { - const size_t full_len = const_val->type->data.array.len + - (const_val->type->data.array.sentinel != nullptr); - return value_is_all_undef_array(g, const_val, full_len); + return value_is_all_undef_array(g, const_val, const_val->type->data.array.len); } else if (const_val->type->id == ZigTypeIdVector) { return value_is_all_undef_array(g, const_val, const_val->type->data.vector.len); } else { @@ -6792,6 +6790,22 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Zig used_bits += packed_bits_size; } } + + if (type_entry->data.array.sentinel != nullptr) { + ZigValue *elem_val = type_entry->data.array.sentinel; + LLVMValueRef child_val = pack_const_int(g, big_int_type_ref, elem_val); + + if (is_big_endian) { + LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, packed_bits_size, false); + val = LLVMConstShl(val, shift_amt); + val = LLVMConstOr(val, child_val); + } else { + LLVMValueRef shift_amt = LLVMConstInt(big_int_type_ref, used_bits, false); + LLVMValueRef child_val_shifted = LLVMConstShl(child_val, shift_amt); + val = LLVMConstOr(val, child_val_shifted); + used_bits += packed_bits_size; + } + } return val; } case ZigTypeIdVector: @@ -6858,20 +6872,11 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; assert(array_const_val->type->id == ZigTypeIdArray); if (!type_has_bits(g, array_const_val->type)) { - if (array_const_val->type->data.array.sentinel != nullptr) { - ZigValue *pointee = array_const_val->type->data.array.sentinel; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } else { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->llvm_value; - } + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), + get_llvm_type(g, const_val->type)); + return const_val->llvm_value; } size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); diff --git a/src/ir.cpp b/src/ir.cpp index b9875a7efe..ef75744576 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20578,11 +20578,6 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP } if (array_type->id == ZigTypeIdArray) { - if (array_type->data.array.len == 0) { - ir_add_error_node(ira, elem_ptr_instruction->base.base.source_node, - buf_sprintf("index 0 outside array of size 0")); - return ira->codegen->invalid_inst_gen; - } ZigType *child_type = array_type->data.array.child_type; if (ptr_type->data.pointer.host_int_bytes == 0) { return_type = get_pointer_to_type_extra(ira->codegen, child_type, @@ -27657,6 +27652,9 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ZigValue buf_write_value_bytes(codegen, &buf[buf_i], elem); buf_i += type_size(codegen, elem->type); } + if (val->type->id == ZigTypeIdArray && val->type->data.array.sentinel != nullptr) { + buf_write_value_bytes(codegen, &buf[buf_i], val->type->data.array.sentinel); + } } static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val) { diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index 1f2d4a2f6b..792c0e70d1 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -28,6 +28,24 @@ fn getArrayLen(a: []const u32) usize { return a.len; } +test "array with sentinels" { + const S = struct { + fn doTheTest(is_ct: bool) void { + var zero_sized: [0:0xde]u8 = [_:0xde]u8{}; + expectEqual(@as(u8, 0xde), zero_sized[0]); + // Disabled at runtime because of + // https://github.com/ziglang/zig/issues/4372 + if (is_ct) { + var reinterpreted = @ptrCast(*[1]u8, &zero_sized); + expectEqual(@as(u8, 0xde), reinterpreted[0]); + } + } + }; + + S.doTheTest(false); + comptime S.doTheTest(true); +} + test "void arrays" { var array: [4]void = undefined; array[0] = void{}; From 2182d28cb0917b8d869d13802a5955ee35b4537a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 15 Mar 2020 20:55:07 -0400 Subject: [PATCH 34/79] slicing with comptime start and end results in array implements #863 --- src/analyze.cpp | 5 +++- src/codegen.cpp | 72 +++++++++++++++++++++++++++++++++----------- src/ir.cpp | 79 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 119 insertions(+), 37 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 9ba247012d..e9b9f03704 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -791,7 +791,10 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi return existing_entry->value; } - assert(type_is_resolved(child_type, ResolveStatusSizeKnown)); + Error err; + if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { + codegen_report_errors_and_exit(g); + } ZigType *entry = new_type_table_entry(ZigTypeIdArray); diff --git a/src/codegen.cpp b/src/codegen.cpp index 3343807691..5a0965507d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5422,8 +5422,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); - ZigType *res_slice_ptr_type = instruction->base.value->type->data.structure.fields[slice_ptr_index]->type_entry; - ZigValue *sentinel = res_slice_ptr_type->data.pointer.sentinel; + ZigType *result_type = instruction->base.value->type; + if (!type_has_bits(g, result_type)) { + return nullptr; + } + + ZigValue *sentinel = nullptr; + if (result_type->id == ZigTypeIdPointer) { + ZigType *result_array_type = result_type->data.pointer.child_type; + ir_assert(result_array_type->id == ZigTypeIdArray, &instruction->base); + sentinel = result_array_type->data.array.sentinel; + } else if (result_type->id == ZigTypeIdStruct) { + ZigType *res_slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry; + sentinel = res_slice_ptr_type->data.pointer.sentinel; + } else { + zig_unreachable(); + } if (array_type->id == ZigTypeIdArray || (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) @@ -5466,18 +5480,24 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI return tmp_struct_ptr; } - - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); LLVMValueRef indices[] = { LLVMConstNull(g->builtin_types.entry_usize->llvm_type), start_val, }; LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + if (result_type->id == ZigTypeIdPointer) { + LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); + LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); + gen_store_untyped(g, bitcasted, tmp_struct_ptr, 0, false); + return slice_start_ptr; + } else { + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); - LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + } return tmp_struct_ptr; } else if (array_type->id == ZigTypeIdPointer) { @@ -5493,14 +5513,21 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); + if (result_type->id == ZigTypeIdPointer) { + LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); + LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); + gen_store_untyped(g, bitcasted, tmp_struct_ptr, 0, false); + return bitcasted; + } + if (type_has_bits(g, array_type)) { - size_t gen_ptr_index = instruction->base.value->type->data.structure.fields[slice_ptr_index]->gen_index; + size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); } - size_t gen_len_index = instruction->base.value->type->data.structure.fields[slice_len_index]->gen_index; + size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); gen_store_untyped(g, len_value, len_field_ptr, 0, false); @@ -5510,7 +5537,9 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI assert(array_type->data.structure.special == StructSpecialSlice); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); - assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); + if (result_type->id != ZigTypeIdPointer) { + assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); + } size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; assert(ptr_index != SIZE_MAX); @@ -5547,15 +5576,22 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + if (result_type->id == ZigTypeIdPointer) { + LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); + LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); + gen_store_untyped(g, bitcasted, tmp_struct_ptr, 0, false); + return bitcasted; + } else { + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); - LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); - return tmp_struct_ptr; + return tmp_struct_ptr; + } } else { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index ef75744576..c52b7c3d74 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -849,11 +849,6 @@ static bool is_slice(ZigType *type) { return type->id == ZigTypeIdStruct && type->data.structure.special == StructSpecialSlice; } -static bool slice_is_const(ZigType *type) { - assert(is_slice(type)); - return type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; -} - // This function returns true when you can change the type of a ZigValue and the // value remains meaningful. static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { @@ -26206,7 +26201,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return ira->codegen->invalid_inst_gen; } - ZigType *return_type; ZigValue *sentinel_val = nullptr; if (instruction->sentinel) { IrInstGen *uncasted_sentinel = instruction->sentinel->child; @@ -26218,6 +26212,46 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); if (sentinel_val == nullptr) return ira->codegen->invalid_inst_gen; + } + + // If start index and end index are both comptime known, then the result type is a pointer to array + // not a slice. + ZigType *return_type; + + if (value_is_comptime(casted_start->value) && + ((end != nullptr && value_is_comptime(end->value)) || array_type->id == ZigTypeIdArray )) + { + ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); + if (!start_val) + return ira->codegen->invalid_inst_gen; + + uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); + + uint64_t end_scalar; + if (end != nullptr) { + ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); + if (!end_val) + return ira->codegen->invalid_inst_gen; + end_scalar = bigint_as_u64(&end_val->data.x_bigint); + } else { + end_scalar = array_type->data.array.len; + } + ZigValue *array_sentinel = (array_type->id == ZigTypeIdArray && end_scalar == array_type->data.array.len) + ? sentinel_val : nullptr; + + if (start_scalar > end_scalar) { + ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice")); + return ira->codegen->invalid_inst_gen; + } + + ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, + array_sentinel); + return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, + non_sentinel_slice_ptr_type->data.pointer.is_const, + non_sentinel_slice_ptr_type->data.pointer.is_volatile, + PtrLenSingle, + 0, 0, 0, false); + } else if (sentinel_val != nullptr) { ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else { @@ -26401,15 +26435,25 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } IrInstGen *result = ir_const(ira, &instruction->base.base, return_type); - ZigValue *out_val = result->value; - out_val->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); - ZigValue *ptr_val = out_val->data.x_struct.fields[slice_ptr_index]; + ZigValue *ptr_val; + if (return_type->id == ZigTypeIdPointer) { + // pointer to array + ptr_val = result->value; + } else { + // slice + result->value->data.x_struct.fields = alloc_const_vals_ptrs(ira->codegen, 2); + ptr_val = result->value->data.x_struct.fields[slice_ptr_index]; + + ZigValue *len_val = result->value->data.x_struct.fields[slice_len_index]; + init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); + } + + bool return_type_is_const = non_sentinel_slice_ptr_type->data.pointer.is_const; if (array_val) { size_t index = abs_offset + start_scalar; - bool is_const = slice_is_const(return_type); - init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown); + init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); if (array_type->id == ZigTypeIdArray) { ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; } else if (is_slice(array_type)) { @@ -26419,15 +26463,15 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } } else if (ptr_is_undef) { ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, - slice_is_const(return_type)); + return_type_is_const); ptr_val->special = ConstValSpecialUndef; } else switch (parent_ptr->data.x_ptr.special) { case ConstPtrSpecialInvalid: case ConstPtrSpecialDiscard: zig_unreachable(); case ConstPtrSpecialRef: - init_const_ptr_ref(ira->codegen, ptr_val, - parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type)); + init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, + return_type_is_const); break; case ConstPtrSpecialBaseArray: zig_unreachable(); @@ -26443,7 +26487,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i init_const_ptr_hard_coded_addr(ira->codegen, ptr_val, parent_ptr->type->data.pointer.child_type, parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar, - slice_is_const(return_type)); + return_type_is_const); break; case ConstPtrSpecialFunction: zig_panic("TODO"); @@ -26451,9 +26495,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i zig_panic("TODO"); } - ZigValue *len_val = out_val->data.x_struct.fields[slice_len_index]; - init_const_usize(ira->codegen, len_val, end_scalar - start_scalar); - + // In the case of pointer-to-array, we must restore this because above it overwrites ptr_val->type + result->value->type = return_type; return result; } From 0707be8de88823ff943c3fbd7d0035f88d32dd87 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 16 Mar 2020 21:41:46 -0400 Subject: [PATCH 35/79] fixes in semantic analysis needed to support this feature --- lib/std/mem.zig | 4 +- src-self-hosted/stage2.zig | 2 +- src/all_types.hpp | 5 + src/analyze.cpp | 7 ++ src/codegen.cpp | 31 +++---- src/ir.cpp | 155 ++++++++++++++++++++++--------- test/stage1/behavior/align.zig | 21 +++-- test/stage1/behavior/cast.zig | 3 +- test/stage1/behavior/eval.zig | 2 +- test/stage1/behavior/misc.zig | 14 ++- test/stage1/behavior/ptrcast.zig | 2 +- test/stage1/behavior/slice.zig | 10 +- test/stage1/behavior/struct.zig | 4 +- 13 files changed, 172 insertions(+), 88 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 438c15c2eb..2ffac680c7 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -560,7 +560,7 @@ pub fn span(ptr: var) Span(@TypeOf(ptr)) { test "span" { var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; - const ptr = array[0..2 :3].ptr; + const ptr = @as([*:3]u16, array[0..2 :3]); testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); } @@ -602,7 +602,7 @@ test "len" { testing.expect(len(&array) == 5); testing.expect(len(array[0..3]) == 3); array[2] = 0; - const ptr = array[0..2 :0].ptr; + const ptr = @as([*:0]u16, array[0..2 :0]); testing.expect(len(ptr) == 2); } { diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 5393310f9e..a1d741bc9b 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -128,7 +128,7 @@ export fn stage2_translate_c( args_end: [*]?[*]const u8, resources_path: [*:0]const u8, ) Error { - var errors = @as([*]translate_c.ClangErrMsg, undefined)[0..0]; + var errors: []translate_c.ClangErrMsg = &[0]translate_c.ClangErrMsg{}; out_ast.* = translate_c.translate(std.heap.c_allocator, args_begin, args_end, &errors, resources_path) catch |err| switch (err) { error.SemanticAnalyzeFail => { out_errors_ptr.* = errors.ptr; diff --git a/src/all_types.hpp b/src/all_types.hpp index 53aae9e236..5025ff7cb5 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -231,6 +231,7 @@ enum ConstPtrSpecial { // The pointer is a reference to a single object. ConstPtrSpecialRef, // The pointer points to an element in an underlying array. + // Not to be confused with ConstPtrSpecialSubArray. ConstPtrSpecialBaseArray, // The pointer points to a field in an underlying struct. ConstPtrSpecialBaseStruct, @@ -257,6 +258,10 @@ enum ConstPtrSpecial { // types to be the same, so all optionals of pointer types use x_ptr // instead of x_optional. ConstPtrSpecialNull, + // The pointer points to a sub-array (not an individual element). + // Not to be confused with ConstPtrSpecialBaseArray. However, it uses the same + // union payload struct (base_array). + ConstPtrSpecialSubArray, }; enum ConstPtrMut { diff --git a/src/analyze.cpp b/src/analyze.cpp index e9b9f03704..afffe47c82 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5280,6 +5280,11 @@ static uint32_t hash_const_val_ptr(ZigValue *const_val) { hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); return hash_val; + case ConstPtrSpecialSubArray: + hash_val += (uint32_t)2643358777; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + return hash_val; case ConstPtrSpecialBaseStruct: hash_val += (uint32_t)3518317043; hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); @@ -6746,6 +6751,7 @@ bool const_values_equal_ptr(ZigValue *a, ZigValue *b) { return false; return true; case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val) { return false; } @@ -7003,6 +7009,7 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ZigValue *const_val, ZigT render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: buf_appendf(buf, "*"); // TODO we need a source node for const_ptr_pointee because it can generate compile errors render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); diff --git a/src/codegen.cpp b/src/codegen.cpp index 5a0965507d..24e9e1017d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5418,8 +5418,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI ZigType *array_type = array_ptr_type->data.pointer.child_type; LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); - bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); ZigType *result_type = instruction->base.value->type; @@ -5472,6 +5470,8 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } if (!type_has_bits(g, array_type)) { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); // TODO if runtime safety is on, store 0xaaaaaaa in ptr field @@ -5486,20 +5486,20 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI }; LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); if (result_type->id == ZigTypeIdPointer) { + ir_assert(instruction->result_loc == nullptr, &instruction->base); LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); - gen_store_untyped(g, bitcasted, tmp_struct_ptr, 0, false); - return slice_start_ptr; + return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); } else { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_ptr_index, ""); gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, slice_len_index, ""); LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); gen_store_untyped(g, len_value, len_field_ptr, 0, false); - } - return tmp_struct_ptr; + return tmp_struct_ptr; + } } else if (array_type->id == ZigTypeIdPointer) { assert(array_type->data.pointer.ptr_len != PtrLenSingle); LLVMValueRef start_val = ir_llvm_value(g, instruction->start); @@ -5515,12 +5515,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); if (result_type->id == ZigTypeIdPointer) { + ir_assert(instruction->result_loc == nullptr, &instruction->base); LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); - gen_store_untyped(g, bitcasted, tmp_struct_ptr, 0, false); - return bitcasted; + return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); } + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); if (type_has_bits(g, array_type)) { size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); @@ -5537,9 +5537,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI assert(array_type->data.structure.special == StructSpecialSlice); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); - if (result_type->id != ZigTypeIdPointer) { - assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(tmp_struct_ptr))) == LLVMStructTypeKind); - } size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index; assert(ptr_index != SIZE_MAX); @@ -5578,11 +5575,11 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, 1, ""); if (result_type->id == ZigTypeIdPointer) { + ir_assert(instruction->result_loc == nullptr, &instruction->base); LLVMTypeRef result_ptr_type = get_llvm_type(g, result_type); - LLVMValueRef bitcasted = LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); - gen_store_untyped(g, bitcasted, tmp_struct_ptr, 0, false); - return bitcasted; + return LLVMBuildBitCast(g->builder, slice_start_ptr, result_ptr_type, ""); } else { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, (unsigned)ptr_index, ""); gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); @@ -6676,7 +6673,6 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ZigValue *array_co }; return LLVMConstInBoundsGEP(base_ptr, indices, 2); } else { - assert(parent->id == ConstParentIdScalar); return base_ptr; } } @@ -6904,6 +6900,7 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha return const_val->llvm_value; } case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: { ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; assert(array_const_val->type->id == ZigTypeIdArray); diff --git a/src/ir.cpp b/src/ir.cpp index c52b7c3d74..6ff067e096 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -784,14 +784,32 @@ static ZigValue *const_ptr_pointee_unchecked_no_isf(CodeGen *g, ZigValue *const_ break; case ConstPtrSpecialBaseArray: { ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) { + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + if (elem_index == array_val->type->data.array.len) { result = array_val->type->data.array.sentinel; } else { expand_undef_array(g, array_val); - result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; + result = &array_val->data.x_array.data.s_none.elements[elem_index]; } break; } + case ConstPtrSpecialSubArray: { + ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + + // TODO handle sentinel terminated arrays + expand_undef_array(g, array_val); + result = g->pass1_arena->create(); + result->special = array_val->special; + result->type = get_array_type(g, array_val->type->data.array.child_type, + array_val->type->data.array.len - elem_index, nullptr); + result->data.x_array.special = ConstArraySpecialNone; + result->data.x_array.data.s_none.elements = &array_val->data.x_array.data.s_none.elements[elem_index]; + result->parent.id = ConstParentIdArray; + result->parent.data.p_array.array_val = array_val; + result->parent.data.p_array.elem_index = elem_index; + break; + } case ConstPtrSpecialBaseStruct: { ZigValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; expand_undef_struct(g, struct_val); @@ -3727,8 +3745,8 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); ir_ref_inst_gen(start, ira->new_irb.current_basic_block); - if (end) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); - ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); + if (end != nullptr) ir_ref_inst_gen(end, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_inst_gen(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -12672,40 +12690,63 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc Error err; assert(array_ptr->value->type->id == ZigTypeIdPointer); + assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); + + ZigType *array_type = array_ptr->value->type->data.pointer.child_type; + const size_t array_len = array_type->data.array.len; + + // A zero-sized array can be casted regardless of the destination alignment, or + // whether the pointer is undefined, and the result is always comptime known. + if (array_len == 0) { + ZigValue *undef_array = ira->codegen->pass1_arena->create(); + undef_array->special = ConstValSpecialUndef; + undef_array->type = array_type; + + IrInstGen *result = ir_const(ira, source_instr, wanted_type); + init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; + result->value->type = wanted_type; + return result; + } if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { return ira->codegen->invalid_inst_gen; } - assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); - - const size_t array_len = array_ptr->value->type->data.pointer.child_type->data.array.len; - - // A zero-sized array can always be casted irregardless of the destination - // alignment - if (array_len != 0) { - wanted_type = adjust_slice_align(ira->codegen, wanted_type, - get_ptr_align(ira->codegen, array_ptr->value->type)); - } + wanted_type = adjust_slice_align(ira->codegen, wanted_type, + get_ptr_align(ira->codegen, array_ptr->value->type)); if (instr_is_comptime(array_ptr)) { ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); if (array_ptr_val == nullptr) return ira->codegen->invalid_inst_gen; - ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); - if (pointee == nullptr) - return ira->codegen->invalid_inst_gen; - if (pointee->special != ConstValSpecialRuntime) { - assert(array_ptr_val->type->id == ZigTypeIdPointer); - ZigType *array_type = array_ptr_val->type->data.pointer.child_type; - assert(is_slice(wanted_type)); - bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; + ir_assert(is_slice(wanted_type), source_instr); + bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; + // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee + if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) { + ZigValue *array_val = array_ptr_val->data.x_ptr.data.base_array.array_val; + if (array_val->special != ConstValSpecialRuntime) { + IrInstGen *result = ir_const(ira, source_instr, wanted_type); + init_const_slice(ira->codegen, result->value, array_val, + array_ptr_val->data.x_ptr.data.base_array.elem_index, + array_type->data.array.len, wanted_const); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; + result->value->type = wanted_type; + return result; + } + } else { + ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); + if (pointee == nullptr) + return ira->codegen->invalid_inst_gen; + if (pointee->special != ConstValSpecialRuntime) { + assert(array_ptr_val->type->id == ZigTypeIdPointer); - IrInstGen *result = ir_const(ira, source_instr, wanted_type); - init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, is_const); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; - result->value->type = wanted_type; - return result; + IrInstGen *result = ir_const(ira, source_instr, wanted_type); + init_const_slice(ira->codegen, result->value, pointee, 0, array_type->data.array.len, wanted_const); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr_val->data.x_ptr.mut; + result->value->type = wanted_type; + return result; + } } } @@ -19931,6 +19972,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source dst_size, buf_ptr(&pointee->type->name), src_size)); return ErrorSemanticAnalyzeFail; } + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; assert(array_val->type->id == ZigTypeIdArray); @@ -20814,6 +20856,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP } break; case ConstPtrSpecialBaseArray: + case ConstPtrSpecialSubArray: { size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; new_index = offset + index; @@ -20884,6 +20927,7 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP out_val->data.x_ptr.special = ConstPtrSpecialRef; out_val->data.x_ptr.data.ref.pointee = ptr_field->data.x_ptr.data.ref.pointee; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index; @@ -25894,6 +25938,7 @@ static IrInstGen *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstSrcMemset start = 0; bound_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; @@ -26027,6 +26072,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy dest_start = 0; dest_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; @@ -26070,6 +26116,7 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy src_start = 0; src_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: { ZigValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; @@ -26219,7 +26266,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i ZigType *return_type; if (value_is_comptime(casted_start->value) && - ((end != nullptr && value_is_comptime(end->value)) || array_type->id == ZigTypeIdArray )) + ((end != nullptr && value_is_comptime(end->value)) || + (end == nullptr && array_type->id == ZigTypeIdArray))) { ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); if (!start_val) @@ -26244,13 +26292,16 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return ira->codegen->invalid_inst_gen; } + // TODO in the case of non-zero start index, the byte alignment should be smarter here. + // we should be able to use the same logic as indexing. + uint32_t ptr_byte_alignment = ((end_scalar - start_scalar != 0) && start_scalar == 0) ? + non_sentinel_slice_ptr_type->data.pointer.explicit_alignment : 0; ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, array_sentinel); return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, non_sentinel_slice_ptr_type->data.pointer.is_const, non_sentinel_slice_ptr_type->data.pointer.is_volatile, - PtrLenSingle, - 0, 0, 0, false); + PtrLenSingle, ptr_byte_alignment, 0, 0, false); } else if (sentinel_val != nullptr) { ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); return_type = get_slice_type(ira->codegen, slice_ptr_type); @@ -26283,6 +26334,10 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i abs_offset = 0; rel_end = SIZE_MAX; ptr_is_undef = true; + } else if (parent_ptr->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { + array_val = nullptr; + abs_offset = 0; + rel_end = SIZE_MAX; } else { array_val = const_ptr_pointee(ira, ira->codegen, parent_ptr, instruction->base.base.source_node); if (array_val == nullptr) @@ -26325,6 +26380,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i rel_end = 1; } break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: array_val = parent_ptr->data.x_ptr.data.base_array.array_val; abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; @@ -26375,6 +26431,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i abs_offset = SIZE_MAX; rel_end = 1; break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: array_val = parent_ptr->data.x_ptr.data.base_array.array_val; abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; @@ -26454,6 +26511,9 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i if (array_val) { size_t index = abs_offset + start_scalar; init_const_ptr_array(ira->codegen, ptr_val, array_val, index, return_type_is_const, PtrLenUnknown); + if (return_type->id == ZigTypeIdPointer) { + ptr_val->data.x_ptr.special = ConstPtrSpecialSubArray; + } if (array_type->id == ZigTypeIdArray) { ptr_val->data.x_ptr.mut = ptr_ptr->value->data.x_ptr.mut; } else if (is_slice(array_type)) { @@ -26463,7 +26523,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } } else if (ptr_is_undef) { ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type, - return_type_is_const); + return_type_is_const); ptr_val->special = ConstValSpecialUndef; } else switch (parent_ptr->data.x_ptr.special) { case ConstPtrSpecialInvalid: @@ -26473,6 +26533,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i init_const_ptr_ref(ira->codegen, ptr_val, parent_ptr->data.x_ptr.data.ref.pointee, return_type_is_const); break; + case ConstPtrSpecialSubArray: case ConstPtrSpecialBaseArray: zig_unreachable(); case ConstPtrSpecialBaseStruct: @@ -26500,20 +26561,6 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return result; } - IrInstGen *result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, - return_type, nullptr, true, true); - if (result_loc != nullptr) { - if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { - return result_loc; - } - IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type); - dummy_value->value->special = ConstValSpecialRuntime; - IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base, - dummy_value, result_loc->value->type->data.pointer.child_type); - if (type_is_invalid(dummy_result->value->type)) - return ira->codegen->invalid_inst_gen; - } - if (generate_non_null_assert) { IrInstGen *ptr_val = ir_get_deref(ira, &instruction->base.base, ptr_ptr, nullptr); @@ -26523,6 +26570,24 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i ir_build_assert_non_null(ira, &instruction->base.base, ptr_val); } + IrInstGen *result_loc = nullptr; + + if (return_type->id != ZigTypeIdPointer) { + result_loc = ir_resolve_result(ira, &instruction->base.base, instruction->result_loc, + return_type, nullptr, true, true); + if (result_loc != nullptr) { + if (type_is_invalid(result_loc->value->type) || result_loc->value->type->id == ZigTypeIdUnreachable) { + return result_loc; + } + IrInstGen *dummy_value = ir_const(ira, &instruction->base.base, return_type); + dummy_value->value->special = ConstValSpecialRuntime; + IrInstGen *dummy_result = ir_implicit_cast2(ira, &instruction->base.base, + dummy_value, result_loc->value->type->data.pointer.child_type); + if (type_is_invalid(dummy_result->value->type)) + return ira->codegen->invalid_inst_gen; + } + } + return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc); } diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index 5a5138d567..d3dd282e59 100644 --- a/test/stage1/behavior/align.zig +++ b/test/stage1/behavior/align.zig @@ -171,18 +171,19 @@ test "runtime known array index has best alignment possible" { // because pointer is align 2 and u32 align % 2 == 0 we can assume align 2 var smaller align(2) = [_]u32{ 1, 2, 3, 4 }; - comptime expect(@TypeOf(smaller[0..]) == []align(2) u32); - comptime expect(@TypeOf(smaller[0..].ptr) == [*]align(2) u32); - testIndex(smaller[0..].ptr, 0, *align(2) u32); - testIndex(smaller[0..].ptr, 1, *align(2) u32); - testIndex(smaller[0..].ptr, 2, *align(2) u32); - testIndex(smaller[0..].ptr, 3, *align(2) u32); + var runtime_zero: usize = 0; + comptime expect(@TypeOf(smaller[runtime_zero..]) == []align(2) u32); + comptime expect(@TypeOf(smaller[runtime_zero..].ptr) == [*]align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 0, *align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 1, *align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 2, *align(2) u32); + testIndex(smaller[runtime_zero..].ptr, 3, *align(2) u32); // has to use ABI alignment because index known at runtime only - testIndex2(array[0..].ptr, 0, *u8); - testIndex2(array[0..].ptr, 1, *u8); - testIndex2(array[0..].ptr, 2, *u8); - testIndex2(array[0..].ptr, 3, *u8); + testIndex2(array[runtime_zero..].ptr, 0, *u8); + testIndex2(array[runtime_zero..].ptr, 1, *u8); + testIndex2(array[runtime_zero..].ptr, 2, *u8); + testIndex2(array[runtime_zero..].ptr, 3, *u8); } fn testIndex(smaller: [*]align(2) u32, index: usize, comptime T: type) void { comptime expect(@TypeOf(&smaller[index]) == T); diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 0304ddfa9c..f1936069f1 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -435,7 +435,8 @@ fn incrementVoidPtrValue(value: ?*c_void) void { test "implicit cast from [*]T to ?*c_void" { var a = [_]u8{ 3, 2, 1 }; - incrementVoidPtrArray(a[0..].ptr, 3); + var runtime_zero: usize = 0; + incrementVoidPtrArray(a[runtime_zero..].ptr, 3); expect(std.mem.eql(u8, &a, &[_]u8{ 4, 3, 2 })); } diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 55ace6198c..2af34eaf7e 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -524,7 +524,7 @@ test "comptime slice of slice preserves comptime var" { test "comptime slice of pointer preserves comptime var" { comptime { var buff: [10]u8 = undefined; - var a = buff[0..].ptr; + var a = @ptrCast([*]u8, &buff); a[0..1][0] = 1; expect(buff[0..][0..][0] == 1); } diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 44a8334b5d..9eeb989622 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -102,8 +102,8 @@ test "memcpy and memset intrinsics" { var foo: [20]u8 = undefined; var bar: [20]u8 = undefined; - @memset(foo[0..].ptr, 'A', foo.len); - @memcpy(bar[0..].ptr, foo[0..].ptr, bar.len); + @memset(&foo, 'A', foo.len); + @memcpy(&bar, &foo, bar.len); if (bar[11] != 'A') unreachable; } @@ -565,12 +565,16 @@ test "volatile load and store" { expect(ptr.* == 1235); } -test "slice string literal has type []const u8" { +test "slice string literal has correct type" { comptime { - expect(@TypeOf("aoeu"[0..]) == []const u8); + expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8); const array = [_]i32{ 1, 2, 3, 4 }; - expect(@TypeOf(array[0..]) == []const i32); + expect(@TypeOf(array[0..]) == *const [4]i32); } + var runtime_zero: usize = 0; + expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); + const array = [_]i32{ 1, 2, 3, 4 }; + expect(@TypeOf(array[runtime_zero..]) == []const u8); } test "pointer child field" { diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index 1c1cf251a0..3925325e61 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -13,7 +13,7 @@ fn testReinterpretBytesAsInteger() void { builtin.Endian.Little => 0xab785634, builtin.Endian.Big => 0x345678ab, }; - expect(@ptrCast(*align(1) const u32, bytes[1..5].ptr).* == expected); + expect(@ptrCast(*align(1) const u32, bytes[1..5]).* == expected); } test "reinterpret bytes of an array into an extern struct" { diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index 9dd57f474e..0d0e33079e 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -7,7 +7,7 @@ const mem = std.mem; const x = @intToPtr([*]i32, 0x1000)[0..0x500]; const y = x[0x100..]; test "compile time slice of pointer to hard coded address" { - expect(@ptrToInt(x.ptr) == 0x1000); + expect(@ptrToInt(x) == 0x1000); expect(x.len == 0x500); expect(@ptrToInt(y.ptr) == 0x1100); @@ -47,7 +47,9 @@ test "C pointer slice access" { var buf: [10]u32 = [1]u32{42} ** 10; const c_ptr = @ptrCast([*c]const u32, &buf); - comptime expectEqual([]const u32, @TypeOf(c_ptr[0..1])); + var runtime_zero: usize = 0; + comptime expectEqual([]const u32, @TypeOf(c_ptr[runtime_zero..1])); + comptime expectEqual(*const [1]u32, @TypeOf(c_ptr[0..1])); for (c_ptr[0..5]) |*cl| { expectEqual(@as(u32, 42), cl.*); @@ -107,7 +109,9 @@ test "obtaining a null terminated slice" { const ptr2 = buf[0..runtime_len :0]; // ptr2 is a null-terminated slice comptime expect(@TypeOf(ptr2) == [:0]u8); - comptime expect(@TypeOf(ptr2[0..2]) == []u8); + comptime expect(@TypeOf(ptr2[0..2]) == *[2]u8); + var runtime_zero: usize = 0; + comptime expect(@TypeOf(ptr2[runtime_zero..2]) == []u8); } test "empty array to slice" { diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index ecec7fe5d6..0365991ed3 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -409,8 +409,8 @@ const Bitfields = packed struct { test "native bit field understands endianness" { var all: u64 = 0x7765443322221111; var bytes: [8]u8 = undefined; - @memcpy(bytes[0..].ptr, @ptrCast([*]u8, &all), 8); - var bitfields = @ptrCast(*Bitfields, bytes[0..].ptr).*; + @memcpy(&bytes, @ptrCast([*]u8, &all), 8); + var bitfields = @ptrCast(*Bitfields, &bytes).*; expect(bitfields.f1 == 0x1111); expect(bitfields.f2 == 0x2222); From c896c5001f55c67ba2379505464f85dcabb3f3f2 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 14:23:02 -0400 Subject: [PATCH 36/79] fix slice of string literal having the wrong type --- src/ir.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 6ff067e096..5558560606 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26261,13 +26261,16 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return ira->codegen->invalid_inst_gen; } + ZigType *child_array_type = (array_type->id == ZigTypeIdPointer && + array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type; + // If start index and end index are both comptime known, then the result type is a pointer to array // not a slice. ZigType *return_type; if (value_is_comptime(casted_start->value) && ((end != nullptr && value_is_comptime(end->value)) || - (end == nullptr && array_type->id == ZigTypeIdArray))) + (end == nullptr && child_array_type->id == ZigTypeIdArray))) { ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); if (!start_val) @@ -26282,10 +26285,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return ira->codegen->invalid_inst_gen; end_scalar = bigint_as_u64(&end_val->data.x_bigint); } else { - end_scalar = array_type->data.array.len; + end_scalar = child_array_type->data.array.len; } - ZigValue *array_sentinel = (array_type->id == ZigTypeIdArray && end_scalar == array_type->data.array.len) - ? sentinel_val : nullptr; + ZigValue *array_sentinel = (child_array_type->id == ZigTypeIdArray && + end_scalar == child_array_type->data.array.len) + ? child_array_type->data.array.sentinel : nullptr; if (start_scalar > end_scalar) { ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice")); @@ -26318,12 +26322,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i size_t abs_offset; size_t rel_end; bool ptr_is_undef = false; - if (array_type->id == ZigTypeIdArray || - (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) - { + if (child_array_type->id == ZigTypeIdArray) { if (array_type->id == ZigTypeIdPointer) { - ZigType *child_array_type = array_type->data.pointer.child_type; - assert(child_array_type->id == ZigTypeIdArray); parent_ptr = const_ptr_pointee(ira, ira->codegen, ptr_ptr->value, instruction->base.base.source_node); if (parent_ptr == nullptr) return ira->codegen->invalid_inst_gen; From 8d0ac6dc4d32daea3561e7de8eeee9ce34d2c5cb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 17:33:44 -0400 Subject: [PATCH 37/79] `@ptrCast` supports casting a slice to pointer --- lib/std/mem.zig | 46 +++++++++++++++++++++++++++++++--------------- src/analyze.cpp | 20 +++++++++++++++++--- src/analyze.hpp | 2 +- src/ir.cpp | 44 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 26 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 2ffac680c7..eb2539720a 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1750,34 +1750,50 @@ fn BytesAsSliceReturnType(comptime T: type, comptime bytesType: type) type { } pub fn bytesAsSlice(comptime T: type, bytes: var) BytesAsSliceReturnType(T, @TypeOf(bytes)) { - const bytesSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(bytes))) bytes[0..] else bytes; - // let's not give an undefined pointer to @ptrCast // it may be equal to zero and fail a null check - if (bytesSlice.len == 0) { + if (bytes.len == 0) { return &[0]T{}; } - const bytesType = @TypeOf(bytesSlice); - const alignment = comptime meta.alignment(bytesType); + const Bytes = @TypeOf(bytes); + const alignment = comptime meta.alignment(Bytes); - const castTarget = if (comptime trait.isConstPtr(bytesType)) [*]align(alignment) const T else [*]align(alignment) T; + const cast_target = if (comptime trait.isConstPtr(Bytes)) [*]align(alignment) const T else [*]align(alignment) T; - return @ptrCast(castTarget, bytesSlice.ptr)[0..@divExact(bytes.len, @sizeOf(T))]; + return @ptrCast(cast_target, bytes)[0..@divExact(bytes.len, @sizeOf(T))]; } test "bytesAsSlice" { - const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; - const slice = bytesAsSlice(u16, bytes[0..]); - testing.expect(slice.len == 2); - testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); - testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); + { + const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + const slice = bytesAsSlice(u16, bytes[0..]); + testing.expect(slice.len == 2); + testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); + testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); + } + { + const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; + var runtime_zero: usize = 0; + const slice = bytesAsSlice(u16, bytes[runtime_zero..]); + testing.expect(slice.len == 2); + testing.expect(bigToNative(u16, slice[0]) == 0xDEAD); + testing.expect(bigToNative(u16, slice[1]) == 0xBEEF); + } } test "bytesAsSlice keeps pointer alignment" { - var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; - const numbers = bytesAsSlice(u32, bytes[0..]); - comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); + { + var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; + const numbers = bytesAsSlice(u32, bytes[0..]); + comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); + } + { + var bytes = [_]u8{ 0x01, 0x02, 0x03, 0x04 }; + var runtime_zero: usize = 0; + const numbers = bytesAsSlice(u32, bytes[runtime_zero..]); + comptime testing.expect(@TypeOf(numbers) == []align(@alignOf(@TypeOf(bytes))) u32); + } } test "bytesAsSlice on a packed struct" { diff --git a/src/analyze.cpp b/src/analyze.cpp index afffe47c82..1f511fa834 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4486,7 +4486,14 @@ static uint32_t get_async_frame_align_bytes(CodeGen *g) { } uint32_t get_ptr_align(CodeGen *g, ZigType *type) { - ZigType *ptr_type = get_src_ptr_type(type); + ZigType *ptr_type; + if (type->id == ZigTypeIdStruct) { + assert(type->data.structure.special == StructSpecialSlice); + TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; + ptr_type = resolve_struct_field_type(g, ptr_field); + } else { + ptr_type = get_src_ptr_type(type); + } if (ptr_type->id == ZigTypeIdPointer) { return (ptr_type->data.pointer.explicit_alignment == 0) ? get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; @@ -4503,8 +4510,15 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { } } -bool get_ptr_const(ZigType *type) { - ZigType *ptr_type = get_src_ptr_type(type); +bool get_ptr_const(CodeGen *g, ZigType *type) { + ZigType *ptr_type; + if (type->id == ZigTypeIdStruct) { + assert(type->data.structure.special == StructSpecialSlice); + TypeStructField *ptr_field = type->data.structure.fields[slice_ptr_index]; + ptr_type = resolve_struct_field_type(g, ptr_field); + } else { + ptr_type = get_src_ptr_type(type); + } if (ptr_type->id == ZigTypeIdPointer) { return ptr_type->data.pointer.is_const; } else if (ptr_type->id == ZigTypeIdFn) { diff --git a/src/analyze.hpp b/src/analyze.hpp index c7cbab4b8c..b6404b1882 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -76,7 +76,7 @@ void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool all ZigType *get_src_ptr_type(ZigType *type); uint32_t get_ptr_align(CodeGen *g, ZigType *type); -bool get_ptr_const(ZigType *type); +bool get_ptr_const(CodeGen *g, ZigType *type); ZigType *validate_var_type(CodeGen *g, AstNode *source_node, ZigType *type_entry); ZigType *container_ref_type(ZigType *type_entry); bool type_is_complete(ZigType *type_entry); diff --git a/src/ir.cpp b/src/ir.cpp index 5558560606..15edfbfc7b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -25479,11 +25479,22 @@ static IrInstGen *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrInstSrcE static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { Error err; - ZigType *ptr_type = get_src_ptr_type(ty); + ZigType *ptr_type; + if (is_slice(ty)) { + TypeStructField *ptr_field = ty->data.structure.fields[slice_ptr_index]; + ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); + } else { + ptr_type = get_src_ptr_type(ty); + } assert(ptr_type != nullptr); if (ptr_type->id == ZigTypeIdPointer) { if ((err = type_resolve(ira->codegen, ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) return err; + } else if (is_slice(ptr_type)) { + TypeStructField *ptr_field = ptr_type->data.structure.fields[slice_ptr_index]; + ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); + if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return err; } *result_align = get_ptr_align(ira->codegen, ty); @@ -27615,10 +27626,18 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn // We have a check for zero bits later so we use get_src_ptr_type to // validate src_type and dest_type. - ZigType *src_ptr_type = get_src_ptr_type(src_type); - if (src_ptr_type == nullptr) { - ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_inst_gen; + ZigType *if_slice_ptr_type; + if (is_slice(src_type)) { + TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; + if_slice_ptr_type = resolve_struct_field_type(ira->codegen, ptr_field); + } else { + if_slice_ptr_type = src_type; + + ZigType *src_ptr_type = get_src_ptr_type(src_type); + if (src_ptr_type == nullptr) { + ir_add_error(ira, ptr_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); + return ira->codegen->invalid_inst_gen; + } } ZigType *dest_ptr_type = get_src_ptr_type(dest_type); @@ -27628,7 +27647,7 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn return ira->codegen->invalid_inst_gen; } - if (get_ptr_const(src_type) && !get_ptr_const(dest_type)) { + if (get_ptr_const(ira->codegen, src_type) && !get_ptr_const(ira->codegen, dest_type)) { ir_add_error(ira, source_instr, buf_sprintf("cast discards const qualifier")); return ira->codegen->invalid_inst_gen; } @@ -27646,7 +27665,10 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_inst_gen; - if (type_has_bits(ira->codegen, dest_type) && !type_has_bits(ira->codegen, src_type) && safety_check_on) { + if (safety_check_on && + type_has_bits(ira->codegen, dest_type) && + !type_has_bits(ira->codegen, if_slice_ptr_type)) + { ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("'%s' and '%s' do not have the same in-memory representation", buf_ptr(&src_type->name), buf_ptr(&dest_type->name))); @@ -27657,6 +27679,14 @@ static IrInstGen *ir_analyze_ptr_cast(IrAnalyze *ira, IrInst* source_instr, IrIn return ira->codegen->invalid_inst_gen; } + // For slices, follow the `ptr` field. + if (is_slice(src_type)) { + TypeStructField *ptr_field = src_type->data.structure.fields[slice_ptr_index]; + IrInstGen *ptr_ref = ir_get_ref(ira, source_instr, ptr, true, false); + IrInstGen *ptr_ptr = ir_analyze_struct_field_ptr(ira, source_instr, ptr_field, ptr_ref, src_type, false); + ptr = ir_get_deref(ira, source_instr, ptr_ptr, nullptr); + } + if (instr_is_comptime(ptr)) { bool dest_allows_addr_zero = ptr_allows_addr_zero(dest_type); UndefAllowed is_undef_allowed = dest_allows_addr_zero ? UndefOk : UndefBad; From 8ea0a00f406bb04c08a8fa4471c3a3895f82b24a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 18:54:09 -0400 Subject: [PATCH 38/79] improve std lib code for the new semantics --- lib/std/mem.zig | 12 +++++------ lib/std/meta.zig | 37 ++++++++++++++++++++------------- src-self-hosted/translate_c.zig | 26 +++++++++++------------ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index eb2539720a..dcdf76e195 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1829,21 +1829,19 @@ fn SliceAsBytesReturnType(comptime sliceType: type) type { } pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { - const actualSlice = if (comptime trait.isPtrTo(.Array)(@TypeOf(slice))) slice[0..] else slice; - const actualSliceTypeInfo = @typeInfo(@TypeOf(actualSlice)).Pointer; + const Slice = @TypeOf(slice); // let's not give an undefined pointer to @ptrCast // it may be equal to zero and fail a null check - if (actualSlice.len == 0 and actualSliceTypeInfo.sentinel == null) { + if (slice.len == 0 and comptime meta.sentinel(Slice) == null) { return &[0]u8{}; } - const sliceType = @TypeOf(actualSlice); - const alignment = comptime meta.alignment(sliceType); + const alignment = comptime meta.alignment(Slice); - const castTarget = if (comptime trait.isConstPtr(sliceType)) [*]align(alignment) const u8 else [*]align(alignment) u8; + const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8; - return @ptrCast(castTarget, actualSlice.ptr)[0 .. actualSlice.len * @sizeOf(comptime meta.Child(sliceType))]; + return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Child(Slice))]; } test "sliceAsBytes" { diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 65809abb5c..e8b9f16895 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -115,30 +115,37 @@ test "std.meta.Child" { testing.expect(Child(?u8) == u8); } -/// Given a type with a sentinel e.g. `[:0]u8`, returns the sentinel -pub fn Sentinel(comptime T: type) Child(T) { - // comptime asserts that ptr has a sentinel +/// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value, +/// or `null` if there is not one. +/// Types which cannot possibly have a sentinel will be a compile error. +pub fn sentinel(comptime T: type) ?Child(T) { switch (@typeInfo(T)) { - .Array => |arrayInfo| { - return comptime arrayInfo.sentinel.?; - }, - .Pointer => |ptrInfo| { - switch (ptrInfo.size) { - .Many, .Slice => { - return comptime ptrInfo.sentinel.?; + .Array => |info| return info.sentinel, + .Pointer => |info| { + switch (info.size) { + .Many, .Slice => return info.sentinel, + .One => switch (info.child) { + .Array => |array_info| return array_info.sentinel, + else => {}, }, else => {}, } }, else => {}, } - @compileError("not a sentinel type, found '" ++ @typeName(T) ++ "'"); + @compileError("type '" ++ @typeName(T) ++ "' cannot possibly have a sentinel"); } -test "std.meta.Sentinel" { - testing.expectEqual(@as(u8, 0), Sentinel([:0]u8)); - testing.expectEqual(@as(u8, 0), Sentinel([*:0]u8)); - testing.expectEqual(@as(u8, 0), Sentinel([5:0]u8)); +test "std.meta.sentinel" { + testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?); + testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?); + testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?); + testing.expectEqual(@as(u8, 0), sentinel(*const [5:0]u8).?); + + testing.expect(sentinel([]u8) == null); + testing.expect(sentinel([*]u8) == null); + testing.expect(sentinel([5]u8) == null); + testing.expect(sentinel(*const [5]u8) == null); } pub fn containerLayout(comptime T: type) TypeInfo.ContainerLayout { diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 84416ac980..e6cf8fb149 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -1744,20 +1744,18 @@ fn writeEscapedString(buf: []u8, s: []const u8) void { // Returns either a string literal or a slice of `buf`. fn escapeChar(c: u8, char_buf: *[4]u8) []const u8 { return switch (c) { - '\"' => "\\\""[0..], - '\'' => "\\'"[0..], - '\\' => "\\\\"[0..], - '\n' => "\\n"[0..], - '\r' => "\\r"[0..], - '\t' => "\\t"[0..], - else => { - // Handle the remaining escapes Zig doesn't support by turning them - // into their respective hex representation - if (std.ascii.isCntrl(c)) - return std.fmt.bufPrint(char_buf[0..], "\\x{x:0<2}", .{c}) catch unreachable - else - return std.fmt.bufPrint(char_buf[0..], "{c}", .{c}) catch unreachable; - }, + '\"' => "\\\"", + '\'' => "\\'", + '\\' => "\\\\", + '\n' => "\\n", + '\r' => "\\r", + '\t' => "\\t", + // Handle the remaining escapes Zig doesn't support by turning them + // into their respective hex representation + else => if (std.ascii.isCntrl(c)) + std.fmt.bufPrint(char_buf, "\\x{x:0<2}", .{c}) catch unreachable + else + std.fmt.bufPrint(char_buf, "{c}", .{c}) catch unreachable, }; } From 2b4134459d468812ac106c124ee6fa5f5e8b9574 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 19:45:59 -0400 Subject: [PATCH 39/79] fix alignment when slicing with comptime start and end index --- src/ir.cpp | 79 +++++++++++++++++++++++----------- test/stage1/behavior/slice.zig | 2 +- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 15edfbfc7b..059a73c2f9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20575,6 +20575,44 @@ static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_ allow_zero); } +static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align, + uint64_t elem_index, uint32_t *result) +{ + Error err; + + if (base_ptr_align == 0) { + *result = 0; + return ErrorNone; + } + + // figure out the largest alignment possible + if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) + return err; + + uint64_t elem_size = type_size(ira->codegen, elem_type); + uint64_t abi_align = get_abi_alignment(ira->codegen, elem_type); + uint64_t ptr_align = base_ptr_align; + + uint64_t chosen_align = abi_align; + if (ptr_align >= abi_align) { + while (ptr_align > abi_align) { + if ((elem_index * elem_size) % ptr_align == 0) { + chosen_align = ptr_align; + break; + } + ptr_align >>= 1; + } + } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { + chosen_align = ptr_align; + } else { + // can't get here because guaranteed elem_size >= abi_align + zig_unreachable(); + } + + *result = chosen_align; + return ErrorNone; +} + static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemPtr *elem_ptr_instruction) { Error err; IrInstGen *array_ptr = elem_ptr_instruction->array_ptr->child; @@ -20713,29 +20751,11 @@ static IrInstGen *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstSrcElemP get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, nullptr, nullptr); } else if (return_type->data.pointer.explicit_alignment != 0) { - // figure out the largest alignment possible - - if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) + uint32_t chosen_align; + if ((err = compute_elem_align(ira, return_type->data.pointer.child_type, + return_type->data.pointer.explicit_alignment, index, &chosen_align))) + { return ira->codegen->invalid_inst_gen; - - uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); - uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); - uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); - - uint64_t chosen_align = abi_align; - if (ptr_align >= abi_align) { - while (ptr_align > abi_align) { - if ((index * elem_size) % ptr_align == 0) { - chosen_align = ptr_align; - break; - } - ptr_align >>= 1; - } - } else if (elem_size >= ptr_align && elem_size % ptr_align == 0) { - chosen_align = ptr_align; - } else { - // can't get here because guaranteed elem_size >= abi_align - zig_unreachable(); } return_type = adjust_ptr_align(ira->codegen, return_type, chosen_align); } @@ -26172,6 +26192,8 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy } static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { + Error err; + IrInstGen *ptr_ptr = instruction->ptr->child; if (type_is_invalid(ptr_ptr->value->type)) return ira->codegen->invalid_inst_gen; @@ -26307,10 +26329,13 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i return ira->codegen->invalid_inst_gen; } - // TODO in the case of non-zero start index, the byte alignment should be smarter here. - // we should be able to use the same logic as indexing. - uint32_t ptr_byte_alignment = ((end_scalar - start_scalar != 0) && start_scalar == 0) ? - non_sentinel_slice_ptr_type->data.pointer.explicit_alignment : 0; + uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; + uint32_t ptr_byte_alignment = 0; + if (end_scalar > start_scalar) { + if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) + return ira->codegen->invalid_inst_gen; + } + ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, array_sentinel); return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, @@ -26318,9 +26343,11 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i non_sentinel_slice_ptr_type->data.pointer.is_volatile, PtrLenSingle, ptr_byte_alignment, 0, 0, false); } else if (sentinel_val != nullptr) { + // TODO deal with non-abi-alignment here ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else { + // TODO deal with non-abi-alignment here return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); } diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index 0d0e33079e..26ad8425f2 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -10,7 +10,7 @@ test "compile time slice of pointer to hard coded address" { expect(@ptrToInt(x) == 0x1000); expect(x.len == 0x500); - expect(@ptrToInt(y.ptr) == 0x1100); + expect(@ptrToInt(y) == 0x1100); expect(y.len == 0x400); } From 4435b05b6b007df9159058fb5ae6f8902eecd1d8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 20:11:47 -0400 Subject: [PATCH 40/79] fix regression when slicing 0-bit pointers --- src/codegen.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 24e9e1017d..14fb6dc8b3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5513,6 +5513,15 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } } + if (!type_has_bits(g, array_type)) { + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + return tmp_struct_ptr; + } + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); if (result_type->id == ZigTypeIdPointer) { ir_assert(instruction->result_loc == nullptr, &instruction->base); @@ -5521,18 +5530,11 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); - if (type_has_bits(g, array_type)) { - size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - } - - size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); - LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - + size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); return tmp_struct_ptr; + } else if (array_type->id == ZigTypeIdStruct) { assert(array_type->data.structure.special == StructSpecialSlice); assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); From 72a261b4d35b4f720e189150eb5e73e0fa52ae35 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 17 Mar 2020 23:32:03 -0400 Subject: [PATCH 41/79] fix runtime slice of pointer not setting length --- src/codegen.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/codegen.cpp b/src/codegen.cpp index 14fb6dc8b3..21e74ba609 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5530,9 +5530,16 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI } LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); + size_t gen_ptr_index = result_type->data.structure.fields[slice_ptr_index]->gen_index; LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_ptr_index, ""); gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + + size_t gen_len_index = result_type->data.structure.fields[slice_len_index]->gen_index; + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, gen_len_index, ""); + LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + return tmp_struct_ptr; } else if (array_type->id == ZigTypeIdStruct) { From e947f0c7409c719377ca08fb09ec72a558a60d99 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 11:19:24 -0400 Subject: [PATCH 42/79] 0-bit array type does not resolve child type --- src/analyze.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index 1f511fa834..77d3f33331 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -780,6 +780,8 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa } ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ZigValue *sentinel) { + Error err; + TypeId type_id = {}; type_id.id = ZigTypeIdArray; type_id.data.array.codegen = g; @@ -791,8 +793,9 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi return existing_entry->value; } - Error err; - if ((err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { + size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); + + if (full_array_size != 0 && (err = type_resolve(g, child_type, ResolveStatusSizeKnown))) { codegen_report_errors_and_exit(g); } @@ -806,9 +809,8 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi } buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); - size_t full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); entry->size_in_bits = child_type->size_in_bits * full_array_size; - entry->abi_align = child_type->abi_align; + entry->abi_align = (full_array_size == 0) ? 0 : child_type->abi_align; entry->abi_size = child_type->abi_size * full_array_size; entry->data.array.child_type = child_type; From 8688c437455d8e8f1f031177375e570022c16ce7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 12:22:39 -0400 Subject: [PATCH 43/79] when result loc is a slice, avoid evaluating lazy start..end This prevents lazy values from being unnecessarily evaluated. --- src/ir.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 059a73c2f9..657956f334 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26191,6 +26191,16 @@ static IrInstGen *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstSrcMemcpy return ir_build_memcpy_gen(ira, &instruction->base.base, casted_dest_ptr, casted_src_ptr, casted_count); } +static ZigType *get_result_loc_type(IrAnalyze *ira, ResultLoc *result_loc) { + if (result_loc == nullptr) return nullptr; + + if (result_loc->id == ResultLocIdCast) { + return ir_resolve_type(ira, result_loc->source_instruction->child); + } + + return nullptr; +} + static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *instruction) { Error err; @@ -26297,11 +26307,16 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i ZigType *child_array_type = (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle) ? array_type->data.pointer.child_type : array_type; - // If start index and end index are both comptime known, then the result type is a pointer to array - // not a slice. ZigType *return_type; - if (value_is_comptime(casted_start->value) && + // If start index and end index are both comptime known, then the result type is a pointer to array + // not a slice. However, if the start or end index is a lazy value, and the result location is a slice, + // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these + // values by making the return type a slice. + ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc); + + if ((res_loc_type == nullptr || !is_slice(res_loc_type)) && + value_is_comptime(casted_start->value) && ((end != nullptr && value_is_comptime(end->value)) || (end == nullptr && child_array_type->id == ZigTypeIdArray))) { From 2164b511cce235ec4a49de99452e4900835bfba8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 19:07:37 -0400 Subject: [PATCH 44/79] partial revert of an improvement this branch made because it uncovered a result location bug, and I need to get this branch merged before going into a result location rabbit hole. also fix the result type of slicing when the indexes are runtime known and the result should be sentinel terminated. --- src/ir.cpp | 111 ++++++++++++++++++++------------- test/stage1/behavior/align.zig | 15 +++-- test/stage1/behavior/misc.zig | 4 +- 3 files changed, 79 insertions(+), 51 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 657956f334..93f265a2d5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12693,34 +12693,50 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc assert(array_ptr->value->type->data.pointer.child_type->id == ZigTypeIdArray); ZigType *array_type = array_ptr->value->type->data.pointer.child_type; - const size_t array_len = array_type->data.array.len; + size_t array_len = array_type->data.array.len; // A zero-sized array can be casted regardless of the destination alignment, or // whether the pointer is undefined, and the result is always comptime known. - if (array_len == 0) { - ZigValue *undef_array = ira->codegen->pass1_arena->create(); - undef_array->special = ConstValSpecialUndef; - undef_array->type = array_type; + // TODO However, this is exposing a result location bug that I failed to solve on the first try. + // If you want to try to fix the bug, uncomment this block and get the tests passing. + //if (array_len == 0 && array_type->data.array.sentinel == nullptr) { + // ZigValue *undef_array = ira->codegen->pass1_arena->create(); + // undef_array->special = ConstValSpecialUndef; + // undef_array->type = array_type; - IrInstGen *result = ir_const(ira, source_instr, wanted_type); - init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); - result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; - result->value->type = wanted_type; - return result; - } + // IrInstGen *result = ir_const(ira, source_instr, wanted_type); + // init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); + // result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; + // result->value->type = wanted_type; + // return result; + //} if ((err = type_resolve(ira->codegen, array_ptr->value->type, ResolveStatusAlignmentKnown))) { return ira->codegen->invalid_inst_gen; } - wanted_type = adjust_slice_align(ira->codegen, wanted_type, - get_ptr_align(ira->codegen, array_ptr->value->type)); + if (array_len != 0) { + wanted_type = adjust_slice_align(ira->codegen, wanted_type, + get_ptr_align(ira->codegen, array_ptr->value->type)); + } if (instr_is_comptime(array_ptr)) { - ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, UndefBad); + UndefAllowed undef_allowed = (array_len == 0) ? UndefOk : UndefBad; + ZigValue *array_ptr_val = ir_resolve_const(ira, array_ptr, undef_allowed); if (array_ptr_val == nullptr) return ira->codegen->invalid_inst_gen; ir_assert(is_slice(wanted_type), source_instr); + if (array_ptr_val->special == ConstValSpecialUndef) { + ZigValue *undef_array = ira->codegen->pass1_arena->create(); + undef_array->special = ConstValSpecialUndef; + undef_array->type = array_type; + + IrInstGen *result = ir_const(ira, source_instr, wanted_type); + init_const_slice(ira->codegen, result->value, undef_array, 0, 0, false); + result->value->data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = ConstPtrMutComptimeConst; + result->value->type = wanted_type; + return result; + } bool wanted_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; // Optimization to avoid creating unnecessary ZigValue in const_ptr_pointee if (array_ptr_val->data.x_ptr.special == ConstPtrSpecialSubArray) { @@ -26314,18 +26330,13 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i // then the pointer-to-array would be casted to a slice anyway. So, we preserve the laziness of these // values by making the return type a slice. ZigType *res_loc_type = get_result_loc_type(ira, instruction->result_loc); - - if ((res_loc_type == nullptr || !is_slice(res_loc_type)) && - value_is_comptime(casted_start->value) && + bool result_loc_is_slice = (res_loc_type != nullptr && is_slice(res_loc_type)); + bool end_is_known = !result_loc_is_slice && ((end != nullptr && value_is_comptime(end->value)) || - (end == nullptr && child_array_type->id == ZigTypeIdArray))) - { - ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); - if (!start_val) - return ira->codegen->invalid_inst_gen; - - uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); + (end == nullptr && child_array_type->id == ZigTypeIdArray)); + ZigValue *array_sentinel = sentinel_val; + if (end_is_known) { uint64_t end_scalar; if (end != nullptr) { ZigValue *end_val = ir_resolve_const(ira, end, UndefBad); @@ -26335,36 +26346,46 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } else { end_scalar = child_array_type->data.array.len; } - ZigValue *array_sentinel = (child_array_type->id == ZigTypeIdArray && - end_scalar == child_array_type->data.array.len) - ? child_array_type->data.array.sentinel : nullptr; + array_sentinel = (child_array_type->id == ZigTypeIdArray && end_scalar == child_array_type->data.array.len) + ? child_array_type->data.array.sentinel : sentinel_val; - if (start_scalar > end_scalar) { - ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice")); - return ira->codegen->invalid_inst_gen; - } - - uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; - uint32_t ptr_byte_alignment = 0; - if (end_scalar > start_scalar) { - if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) + if (value_is_comptime(casted_start->value)) { + ZigValue *start_val = ir_resolve_const(ira, casted_start, UndefBad); + if (!start_val) return ira->codegen->invalid_inst_gen; - } - ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, - array_sentinel); - return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, - non_sentinel_slice_ptr_type->data.pointer.is_const, - non_sentinel_slice_ptr_type->data.pointer.is_volatile, - PtrLenSingle, ptr_byte_alignment, 0, 0, false); - } else if (sentinel_val != nullptr) { + uint64_t start_scalar = bigint_as_u64(&start_val->data.x_bigint); + + if (start_scalar > end_scalar) { + ir_add_error(ira, &instruction->base.base, buf_sprintf("out of bounds slice")); + return ira->codegen->invalid_inst_gen; + } + + uint32_t base_ptr_align = non_sentinel_slice_ptr_type->data.pointer.explicit_alignment; + uint32_t ptr_byte_alignment = 0; + if (end_scalar > start_scalar) { + if ((err = compute_elem_align(ira, elem_type, base_ptr_align, start_scalar, &ptr_byte_alignment))) + return ira->codegen->invalid_inst_gen; + } + + ZigType *return_array_type = get_array_type(ira->codegen, elem_type, end_scalar - start_scalar, + array_sentinel); + return_type = get_pointer_to_type_extra(ira->codegen, return_array_type, + non_sentinel_slice_ptr_type->data.pointer.is_const, + non_sentinel_slice_ptr_type->data.pointer.is_volatile, + PtrLenSingle, ptr_byte_alignment, 0, 0, false); + goto done_with_return_type; + } + } + if (array_sentinel != nullptr) { // TODO deal with non-abi-alignment here - ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); + ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, array_sentinel); return_type = get_slice_type(ira->codegen, slice_ptr_type); } else { // TODO deal with non-abi-alignment here return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); } +done_with_return_type: if (instr_is_comptime(ptr_ptr) && value_is_comptime(casted_start->value) && diff --git a/test/stage1/behavior/align.zig b/test/stage1/behavior/align.zig index d3dd282e59..e9b7e0f1d6 100644 --- a/test/stage1/behavior/align.zig +++ b/test/stage1/behavior/align.zig @@ -5,10 +5,17 @@ const builtin = @import("builtin"); var foo: u8 align(4) = 100; test "global variable alignment" { - expect(@TypeOf(&foo).alignment == 4); - expect(@TypeOf(&foo) == *align(4) u8); - const slice = @as(*[1]u8, &foo)[0..]; - expect(@TypeOf(slice) == []align(4) u8); + comptime expect(@TypeOf(&foo).alignment == 4); + comptime expect(@TypeOf(&foo) == *align(4) u8); + { + const slice = @as(*[1]u8, &foo)[0..]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + } + { + var runtime_zero: usize = 0; + const slice = @as(*[1]u8, &foo)[runtime_zero..]; + comptime expect(@TypeOf(slice) == []align(4) u8); + } } fn derp() align(@sizeOf(usize) * 2) i32 { diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 9eeb989622..51ee6f3a4f 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -572,9 +572,9 @@ test "slice string literal has correct type" { expect(@TypeOf(array[0..]) == *const [4]i32); } var runtime_zero: usize = 0; - expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); + comptime expect(@TypeOf("aoeu"[runtime_zero..]) == [:0]const u8); const array = [_]i32{ 1, 2, 3, 4 }; - expect(@TypeOf(array[runtime_zero..]) == []const u8); + comptime expect(@TypeOf(array[runtime_zero..]) == []const i32); } test "pointer child field" { From b5dba702fff35c2d9aa86c9d5dd93a4a38d3b75b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 19:29:24 -0400 Subject: [PATCH 45/79] fixes to std.meta behavior tests are passing now --- lib/std/meta.zig | 34 ++++++++++++++++++++++++++++--- test/stage1/behavior/pointers.zig | 9 ++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lib/std/meta.zig b/lib/std/meta.zig index e8b9f16895..7343cfc51a 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -104,7 +104,7 @@ pub fn Child(comptime T: type) type { .Array => |info| info.child, .Pointer => |info| info.child, .Optional => |info| info.child, - else => @compileError("Expected pointer, optional, or array type, " ++ "found '" ++ @typeName(T) ++ "'"), + else => @compileError("Expected pointer, optional, or array type, found '" ++ @typeName(T) ++ "'"), }; } @@ -115,16 +115,39 @@ test "std.meta.Child" { testing.expect(Child(?u8) == u8); } +/// Given a "memory span" type, returns the "element type". +pub fn Elem(comptime T: type) type { + switch (@typeInfo(T)) { + .Array => |info| return info.child, + .Pointer => |info| switch (info.size) { + .One => switch (@typeInfo(info.child)) { + .Array => |array_info| return array_info.child, + else => {}, + }, + .Many, .C, .Slice => return info.child, + }, + else => {}, + } + @compileError("Expected pointer, slice, or array, found '" ++ @typeName(T) ++ "'"); +} + +test "std.meta.Elem" { + testing.expect(Elem([1]u8) == u8); + testing.expect(Elem([*]u8) == u8); + testing.expect(Elem([]u8) == u8); + testing.expect(Elem(*[10]u8) == u8); +} + /// Given a type which can have a sentinel e.g. `[:0]u8`, returns the sentinel value, /// or `null` if there is not one. /// Types which cannot possibly have a sentinel will be a compile error. -pub fn sentinel(comptime T: type) ?Child(T) { +pub fn sentinel(comptime T: type) ?Elem(T) { switch (@typeInfo(T)) { .Array => |info| return info.sentinel, .Pointer => |info| { switch (info.size) { .Many, .Slice => return info.sentinel, - .One => switch (info.child) { + .One => switch (@typeInfo(info.child)) { .Array => |array_info| return array_info.sentinel, else => {}, }, @@ -137,6 +160,11 @@ pub fn sentinel(comptime T: type) ?Child(T) { } test "std.meta.sentinel" { + testSentinel(); + comptime testSentinel(); +} + +fn testSentinel() void { testing.expectEqual(@as(u8, 0), sentinel([:0]u8).?); testing.expectEqual(@as(u8, 0), sentinel([*:0]u8).?); testing.expectEqual(@as(u8, 0), sentinel([5:0]u8).?); diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index bcc1d62df3..fbce9731f0 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -159,12 +159,13 @@ test "allowzero pointer and slice" { var opt_ptr: ?[*]allowzero i32 = ptr; expect(opt_ptr != null); expect(@ptrToInt(ptr) == 0); - var slice = ptr[0..10]; - expect(@TypeOf(slice) == []allowzero i32); + var runtime_zero: usize = 0; + var slice = ptr[runtime_zero..10]; + comptime expect(@TypeOf(slice) == []allowzero i32); expect(@ptrToInt(&slice[5]) == 20); - expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); - expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); + comptime expect(@typeInfo(@TypeOf(ptr)).Pointer.is_allowzero); + comptime expect(@typeInfo(@TypeOf(slice)).Pointer.is_allowzero); } test "assign null directly to C pointer and test null equality" { From 7fa88cc0a678a3690b61054030f5597b623964a4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 20:35:19 -0400 Subject: [PATCH 46/79] std lib fixups for new semantics std lib tests are passing now --- lib/std/fmt.zig | 3 ++- lib/std/fs.zig | 2 +- lib/std/hash/auto_hash.zig | 12 ++++++---- lib/std/json.zig | 23 +++++++++++++------ lib/std/mem.zig | 47 ++++++-------------------------------- lib/std/meta/trait.zig | 12 ++++++---- lib/std/net.zig | 10 ++++---- src/ir.cpp | 2 +- 8 files changed, 47 insertions(+), 64 deletions(-) diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 592fe9bb4e..7fc9961938 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1223,7 +1223,8 @@ test "slice" { try testFmt("slice: abc\n", "slice: {}\n", .{value}); } { - const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[0..0]; + var runtime_zero: usize = 0; + const value = @intToPtr([*]align(1) const []const u8, 0xdeadbeef)[runtime_zero..runtime_zero]; try testFmt("slice: []const u8@deadbeef\n", "slice: {}\n", .{value}); } diff --git a/lib/std/fs.zig b/lib/std/fs.zig index bc02fd0c91..01ed80c742 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -360,7 +360,7 @@ pub const Dir = struct { if (self.index >= self.end_index) { const rc = os.system.getdirentries( self.dir.fd, - self.buf[0..].ptr, + &self.buf, self.buf.len, &self.seek, ); diff --git a/lib/std/hash/auto_hash.zig b/lib/std/hash/auto_hash.zig index 2c6b37e3db..b5d6c528a5 100644 --- a/lib/std/hash/auto_hash.zig +++ b/lib/std/hash/auto_hash.zig @@ -40,7 +40,9 @@ pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void { .DeepRecursive => hashArray(hasher, key, .DeepRecursive), }, - .Many, .C, => switch (strat) { + .Many, + .C, + => switch (strat) { .Shallow => hash(hasher, @ptrToInt(key), .Shallow), else => @compileError( \\ unknown-length pointers and C pointers cannot be hashed deeply. @@ -236,9 +238,11 @@ test "hash slice shallow" { defer std.testing.allocator.destroy(array1); array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 }; const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 }; - const a = array1[0..]; - const b = array2[0..]; - const c = array1[0..3]; + // TODO audit deep/shallow - maybe it has the wrong behavior with respect to array pointers and slices + var runtime_zero: usize = 0; + const a = array1[runtime_zero..]; + const b = array2[runtime_zero..]; + const c = array1[runtime_zero..3]; testing.expect(testHashShallow(a) == testHashShallow(a)); testing.expect(testHashShallow(a) != testHashShallow(array1)); testing.expect(testHashShallow(a) != testHashShallow(b)); diff --git a/lib/std/json.zig b/lib/std/json.zig index f5a72d86da..3dd8088785 100644 --- a/lib/std/json.zig +++ b/lib/std/json.zig @@ -2249,11 +2249,16 @@ pub const StringifyOptions = struct { // TODO: allow picking if []u8 is string or array? }; +pub const StringifyError = error{ + TooMuchData, + DifferentData, +}; + pub fn stringify( value: var, options: StringifyOptions, out_stream: var, -) !void { +) StringifyError!void { const T = @TypeOf(value); switch (@typeInfo(T)) { .Float, .ComptimeFloat => { @@ -2320,9 +2325,15 @@ pub fn stringify( return; }, .Pointer => |ptr_info| switch (ptr_info.size) { - .One => { - // TODO: avoid loops? - return try stringify(value.*, options, out_stream); + .One => switch (@typeInfo(ptr_info.child)) { + .Array => { + const Slice = []const std.meta.Elem(ptr_info.child); + return stringify(@as(Slice, value), options, out_stream); + }, + else => { + // TODO: avoid loops? + return stringify(value.*, options, out_stream); + }, }, // TODO: .Many when there is a sentinel (waiting for https://github.com/ziglang/zig/pull/3972) .Slice => { @@ -2381,9 +2392,7 @@ pub fn stringify( }, else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), }, - .Array => |info| { - return try stringify(value[0..], options, out_stream); - }, + .Array => return stringify(&value, options, out_stream), else => @compileError("Unable to stringify type '" ++ @typeName(T) ++ "'"), } unreachable; diff --git a/lib/std/mem.zig b/lib/std/mem.zig index dcdf76e195..951f40ef19 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -1586,24 +1586,24 @@ pub fn nativeToBig(comptime T: type, x: T) T { } fn AsBytesReturnType(comptime P: type) type { - if (comptime !trait.isSingleItemPtr(P)) + if (!trait.isSingleItemPtr(P)) @compileError("expected single item pointer, passed " ++ @typeName(P)); - const size = @as(usize, @sizeOf(meta.Child(P))); - const alignment = comptime meta.alignment(P); + const size = @sizeOf(meta.Child(P)); + const alignment = meta.alignment(P); if (alignment == 0) { - if (comptime trait.isConstPtr(P)) + if (trait.isConstPtr(P)) return *const [size]u8; return *[size]u8; } - if (comptime trait.isConstPtr(P)) + if (trait.isConstPtr(P)) return *align(alignment) const [size]u8; return *align(alignment) [size]u8; } -///Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness. +/// Given a pointer to a single item, returns a slice of the underlying bytes, preserving constness. pub fn asBytes(ptr: var) AsBytesReturnType(@TypeOf(ptr)) { const P = @TypeOf(ptr); return @ptrCast(AsBytesReturnType(P), ptr); @@ -1841,7 +1841,7 @@ pub fn sliceAsBytes(slice: var) SliceAsBytesReturnType(@TypeOf(slice)) { const cast_target = if (comptime trait.isConstPtr(Slice)) [*]align(alignment) const u8 else [*]align(alignment) u8; - return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Child(Slice))]; + return @ptrCast(cast_target, slice)[0 .. slice.len * @sizeOf(meta.Elem(Slice))]; } test "sliceAsBytes" { @@ -1911,39 +1911,6 @@ test "sliceAsBytes and bytesAsSlice back" { testing.expect(bytes[11] == math.maxInt(u8)); } -fn SubArrayPtrReturnType(comptime T: type, comptime length: usize) type { - if (trait.isConstPtr(T)) - return *const [length]meta.Child(meta.Child(T)); - return *[length]meta.Child(meta.Child(T)); -} - -/// Given a pointer to an array, returns a pointer to a portion of that array, preserving constness. -/// TODO this will be obsoleted by https://github.com/ziglang/zig/issues/863 -pub fn subArrayPtr( - ptr: var, - comptime start: usize, - comptime length: usize, -) SubArrayPtrReturnType(@TypeOf(ptr), length) { - assert(start + length <= ptr.*.len); - - const ReturnType = SubArrayPtrReturnType(@TypeOf(ptr), length); - const T = meta.Child(meta.Child(@TypeOf(ptr))); - return @ptrCast(ReturnType, &ptr[start]); -} - -test "subArrayPtr" { - const a1: [6]u8 = "abcdef".*; - const sub1 = subArrayPtr(&a1, 2, 3); - testing.expect(eql(u8, sub1, "cde")); - - var a2: [6]u8 = "abcdef".*; - var sub2 = subArrayPtr(&a2, 2, 3); - - testing.expect(eql(u8, sub2, "cde")); - sub2[1] = 'X'; - testing.expect(eql(u8, &a2, "abcXef")); -} - /// Round an address up to the nearest aligned address /// The alignment must be a power of 2 and greater than 0. pub fn alignForward(addr: usize, alignment: usize) usize { diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index c0fb8c5025..c99e1389f4 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -230,9 +230,10 @@ pub fn isSingleItemPtr(comptime T: type) bool { test "std.meta.trait.isSingleItemPtr" { const array = [_]u8{0} ** 10; - testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); - testing.expect(!isSingleItemPtr(@TypeOf(array))); - testing.expect(!isSingleItemPtr(@TypeOf(array[0..1]))); + comptime testing.expect(isSingleItemPtr(@TypeOf(&array[0]))); + comptime testing.expect(!isSingleItemPtr(@TypeOf(array))); + var runtime_zero: usize = 0; + testing.expect(!isSingleItemPtr(@TypeOf(array[runtime_zero..1]))); } pub fn isManyItemPtr(comptime T: type) bool { @@ -259,7 +260,8 @@ pub fn isSlice(comptime T: type) bool { test "std.meta.trait.isSlice" { const array = [_]u8{0} ** 10; - testing.expect(isSlice(@TypeOf(array[0..]))); + var runtime_zero: usize = 0; + testing.expect(isSlice(@TypeOf(array[runtime_zero..]))); testing.expect(!isSlice(@TypeOf(array))); testing.expect(!isSlice(@TypeOf(&array[0]))); } @@ -276,7 +278,7 @@ pub fn isIndexable(comptime T: type) bool { test "std.meta.trait.isIndexable" { const array = [_]u8{0} ** 10; - const slice = array[0..]; + const slice = @as([]const u8, &array); testing.expect(isIndexable(@TypeOf(array))); testing.expect(isIndexable(@TypeOf(&array))); diff --git a/lib/std/net.zig b/lib/std/net.zig index c2328b9bd0..44efc4644a 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -612,8 +612,7 @@ fn linuxLookupName( } else { mem.copy(u8, &sa6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); mem.copy(u8, &da6.addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff"); - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntNative(u32, @ptrCast(*[4]u8, da6.addr[12..].ptr), addr.addr.in.addr); + mem.writeIntNative(u32, da6.addr[12..], addr.addr.in.addr); da4.addr = addr.addr.in.addr; da = @ptrCast(*os.sockaddr, &da4); dalen = @sizeOf(os.sockaddr_in); @@ -821,7 +820,7 @@ fn linuxLookupNameFromHosts( // Skip to the delimiter in the stream, to fix parsing try stream.skipUntilDelimiterOrEof('\n'); // Use the truncated line. A truncated comment or hostname will be handled correctly. - break :blk line_buf[0..]; + break :blk @as([]u8, &line_buf); // TODO the cast should not be necessary }, else => |e| return e, }) |line| { @@ -958,7 +957,8 @@ fn linuxLookupNameFromDns( } } - var ap = [2][]u8{ apbuf[0][0..0], apbuf[1][0..0] }; + var hack: usize = 0; // TODO remove this hack + var ap = [2][]u8{ apbuf[0][0..hack], apbuf[1][0..hack] }; try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc); var i: usize = 0; @@ -1015,7 +1015,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { // Skip to the delimiter in the stream, to fix parsing try stream.skipUntilDelimiterOrEof('\n'); // Give an empty line to the while loop, which will be skipped. - break :blk line_buf[0..0]; + break :blk @as([]u8, line_buf[0..0]); // TODO the cast should not be necessary }, else => |e| return e, }) |line| { diff --git a/src/ir.cpp b/src/ir.cpp index 93f265a2d5..4800dd9109 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14633,7 +14633,7 @@ static IrInstGen *ir_analyze_cast(IrAnalyze *ira, IrInst *source_instr, return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); } - // *[N]T to ?[]const T + // *[N]T to ?[]T if (wanted_type->id == ZigTypeIdOptional && is_slice(wanted_type->data.maybe.child_type) && actual_type->id == ZigTypeIdPointer && From 61266d26212e89e97d285eb61416d625303704bc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 18 Mar 2020 21:25:35 -0400 Subject: [PATCH 47/79] test & docs fixups to work with new semantics --- doc/langref.html.in | 36 ++++++++++++++++-------------------- lib/std/os/windows.zig | 10 +++++++++- test/compare_output.zig | 2 +- test/compile_errors.zig | 33 +++++++++++---------------------- test/runtime_safety.zig | 2 +- 5 files changed, 38 insertions(+), 45 deletions(-) diff --git a/doc/langref.html.in b/doc/langref.html.in index 3a7892fd45..7def9b42ba 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -2093,8 +2093,9 @@ var foo: u8 align(4) = 100; test "global variable alignment" { assert(@TypeOf(&foo).alignment == 4); assert(@TypeOf(&foo) == *align(4) u8); - const slice = @as(*[1]u8, &foo)[0..]; - assert(@TypeOf(slice) == []align(4) u8); + const as_pointer_to_array: *[1]u8 = &foo; + const as_slice: []u8 = as_pointer_to_array; + assert(@TypeOf(as_slice) == []align(4) u8); } fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; } @@ -2187,7 +2188,8 @@ test "basic slices" { // a slice is that the array's length is part of the type and known at // compile-time, whereas the slice's length is known at runtime. // Both can be accessed with the `len` field. - const slice = array[0..array.len]; + var known_at_runtime_zero: usize = 0; + const slice = array[known_at_runtime_zero..array.len]; assert(&slice[0] == &array[0]); assert(slice.len == array.len); @@ -2207,13 +2209,15 @@ test "basic slices" { {#code_end#}

This is one reason we prefer slices to pointers.

{#code_begin|test|slices#} -const assert = @import("std").debug.assert; -const mem = @import("std").mem; -const fmt = @import("std").fmt; +const std = @import("std"); +const assert = std.debug.assert; +const mem = std.mem; +const fmt = std.fmt; test "using slices for strings" { - // Zig has no concept of strings. String literals are arrays of u8, and - // in general the string type is []u8 (slice of u8). + // Zig has no concept of strings. String literals are const pointers to + // arrays of u8, and by convention parameters that are "strings" are + // expected to be UTF-8 encoded slices of u8. // Here we coerce [5]u8 to []const u8 const hello: []const u8 = "hello"; const world: []const u8 = "世界"; @@ -2222,7 +2226,7 @@ test "using slices for strings" { // You can use slice syntax on an array to convert an array into a slice. const all_together_slice = all_together[0..]; // String concatenation example. - const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{hello, world}); + const hello_world = try fmt.bufPrint(all_together_slice, "{} {}", .{ hello, world }); // Generally, you can use UTF-8 and not worry about whether something is a // string. If you don't need to deal with individual characters, no need @@ -2239,23 +2243,15 @@ test "slice pointer" { slice[2] = 3; assert(slice[2] == 3); // The slice is mutable because we sliced a mutable pointer. - assert(@TypeOf(slice) == []u8); + // Furthermore, it is actually a pointer to an array, since the start + // and end indexes were both comptime-known. + assert(@TypeOf(slice) == *[5]u8); // You can also slice a slice: const slice2 = slice[2..3]; assert(slice2.len == 1); assert(slice2[0] == 3); } - -test "slice widening" { - // Zig supports slice widening and slice narrowing. Cast a slice of u8 - // to a slice of anything else, and Zig will perform the length conversion. - const array align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 }; - const slice = mem.bytesAsSlice(u32, array[0..]); - assert(slice.len == 2); - assert(slice[0] == 0x12121212); - assert(slice[1] == 0x13131313); -} {#code_end#} {#see_also|Pointers|for|Arrays#} diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index f5acb70adb..813a77c275 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -1276,7 +1276,15 @@ pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError { // 614 is the length of the longest windows error desciption var buf_u16: [614]u16 = undefined; var buf_u8: [614]u8 = undefined; - var len = kernel32.FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, null, err, MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), buf_u16[0..].ptr, buf_u16.len / @sizeOf(TCHAR), null); + const len = kernel32.FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + null, + err, + MAKELANGID(LANG.NEUTRAL, SUBLANG.DEFAULT), + &buf_u16, + buf_u16.len / @sizeOf(TCHAR), + null, + ); _ = std.unicode.utf16leToUtf8(&buf_u8, buf_u16[0..len]) catch unreachable; std.debug.warn("error.Unexpected: GetLastError({}): {}\n", .{ @enumToInt(err), buf_u8[0..len] }); std.debug.dumpCurrentStackTrace(null); diff --git a/test/compare_output.zig b/test/compare_output.zig index 1a0179c4c2..46c475e046 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -292,7 +292,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\pub export fn main() c_int { \\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; \\ - \\ c.qsort(@ptrCast(?*c_void, array[0..].ptr), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); + \\ c.qsort(@ptrCast(?*c_void, &array), @intCast(c_ulong, array.len), @sizeOf(i32), compare_fn); \\ \\ for (array) |item, i| { \\ if (item != i) { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index f894a152a7..abcdc48dc6 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -103,18 +103,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:3:23: error: pointer to size 0 type has no address", }); - cases.addTest("slice to pointer conversion mismatch", - \\pub fn bytesAsSlice(bytes: var) [*]align(1) const u16 { - \\ return @ptrCast([*]align(1) const u16, bytes.ptr)[0..1]; - \\} - \\test "bytesAsSlice" { - \\ const bytes = [_]u8{ 0xDE, 0xAD, 0xBE, 0xEF }; - \\ const slice = bytesAsSlice(bytes[0..]); - \\} - , &[_][]const u8{ - "tmp.zig:2:54: error: expected type '[*]align(1) const u16', found '[]align(1) const u16'", - }); - cases.addTest("access invalid @typeInfo decl", \\const A = B; \\test "Crash" { @@ -1915,16 +1903,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:15: error: switch must handle all possibilities", }); - cases.add("reading past end of pointer casted array", - \\comptime { - \\ const array: [4]u8 = "aoeu".*; - \\ const slice = array[1..]; - \\ const int_ptr = @ptrCast(*const u24, slice.ptr); - \\ const deref = int_ptr.*; - \\} - , &[_][]const u8{ - "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes", - }); + // TODO uncomment before merging branch + //cases.add("reading past end of pointer casted array", + // \\comptime { + // \\ const array: [4]u8 = "aoeu".*; + // \\ const sub_array = array[1..]; + // \\ const int_ptr = @ptrCast(*const u24, sub_array); + // \\ const deref = int_ptr.*; + // \\} + //, &[_][]const u8{ + // "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes", + //}); cases.add("error note for function parameter incompatibility", \\fn do_the_thing(func: fn (arg: i32) void) void {} diff --git a/test/runtime_safety.zig b/test/runtime_safety.zig index 5047bfd0d0..b8ab47ddac 100644 --- a/test/runtime_safety.zig +++ b/test/runtime_safety.zig @@ -69,7 +69,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\} \\pub fn main() void { \\ var buf: [4]u8 = undefined; - \\ const ptr = buf[0..].ptr; + \\ const ptr: [*]u8 = &buf; \\ const slice = ptr[0..3 :0]; \\} ); From f824658e136738ea75c8bb3b53d9a67b2c4402b7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 10:54:20 -0400 Subject: [PATCH 48/79] slicing sentinel-terminated slice without end now results in a sentinel-terminated slice. --- src/ir.cpp | 4 ++ test/stage1/behavior/slice.zig | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index 4800dd9109..e20111e21f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26249,6 +26249,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i end = nullptr; } + ZigValue *slice_sentinel_val = nullptr; ZigType *non_sentinel_slice_ptr_type; ZigType *elem_type; @@ -26299,6 +26300,7 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i } } else if (is_slice(array_type)) { ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; + slice_sentinel_val = maybe_sentineled_slice_ptr_type->data.pointer.sentinel; non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; } else { @@ -26376,6 +26378,8 @@ static IrInstGen *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstSrcSlice *i PtrLenSingle, ptr_byte_alignment, 0, 0, false); goto done_with_return_type; } + } else if (array_sentinel == nullptr && end == nullptr) { + array_sentinel = slice_sentinel_val; } if (array_sentinel != nullptr) { // TODO deal with non-abi-alignment here diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index 26ad8425f2..203a3b72d3 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -130,3 +130,82 @@ test "empty array to slice" { S.doTheTest(); comptime S.doTheTest(); } + +test "@ptrCast slice to pointer" { + const S = struct { + fn doTheTest() void { + var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff }; + var slice: []u8 = &array; + var ptr = @ptrCast(*u16, slice); + expect(ptr.* == 65535); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} + +test "slicing producing an array" { + const S = struct { + fn doTheTest() void { + testArray(); + testArrayZ(); + testPointer(); + testPointerZ(); + testSlice(); + testSliceZ(); + } + + fn testArray() void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var slice = array[1..3]; + comptime expect(@TypeOf(slice) == *[2]u8); + expect(slice[0] == 2); + expect(slice[1] == 3); + } + + fn testArrayZ() void { + var array = [5:0]u8{ 1, 2, 3, 4, 5 }; + comptime expect(@TypeOf(array[1..3]) == *[2]u8); + comptime expect(@TypeOf(array[1..5]) == *[4:0]u8); + comptime expect(@TypeOf(array[1..]) == *[4:0]u8); + comptime expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); + } + + fn testPointer() void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*]u8 = &array; + var slice = pointer[1..3]; + comptime expect(@TypeOf(slice) == *[2]u8); + expect(slice[0] == 2); + expect(slice[1] == 3); + } + + fn testPointerZ() void { + var array = [5:0]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*:0]u8 = &array; + comptime expect(@TypeOf(pointer[1..3]) == *[2]u8); + comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); + } + + fn testSlice() void { + var array = [5]u8{ 1, 2, 3, 4, 5 }; + var src_slice: []u8 = &array; + var slice = src_slice[1..3]; + comptime expect(@TypeOf(slice) == *[2]u8); + expect(slice[0] == 2); + expect(slice[1] == 3); + } + + fn testSliceZ() void { + var array = [5:0]u8{ 1, 2, 3, 4, 5 }; + var slice: [:0]u8 = &array; + comptime expect(@TypeOf(slice[1..3]) == *[2]u8); + comptime expect(@TypeOf(slice[1..]) == [:0]u8); + comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); + } + }; + + S.doTheTest(); + comptime S.doTheTest(); +} From 8ddf9d84ffb208042ae7ea0fb3dc9fbfb2b5c983 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 11:17:46 -0400 Subject: [PATCH 49/79] add behavior tests for slicing with comptime indexes --- test/stage1/behavior/slice.zig | 70 +++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index 203a3b72d3..d58132cb08 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -145,15 +145,21 @@ test "@ptrCast slice to pointer" { comptime S.doTheTest(); } -test "slicing producing an array" { +test "slice syntax resulting in pointer-to-array" { const S = struct { fn doTheTest() void { testArray(); testArrayZ(); + testArray0(); + testArrayAlign(); testPointer(); testPointerZ(); + testPointer0(); + testPointerAlign(); testSlice(); testSliceZ(); + testSlice0(); + testSliceAlign(); } fn testArray() void { @@ -172,6 +178,28 @@ test "slicing producing an array" { comptime expect(@TypeOf(array[1..3 :4]) == *[2:4]u8); } + fn testArray0() void { + { + var array = [0]u8{}; + var slice = array[0..0]; + comptime expect(@TypeOf(slice) == *[0]u8); + } + { + var array = [0:0]u8{}; + var slice = array[0..0]; + comptime expect(@TypeOf(slice) == *[0:0]u8); + expect(slice[0] == 0); + } + } + + fn testArrayAlign() void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var slice = array[4..5]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + expect(slice[0] == 5); + comptime expect(@TypeOf(array[0..2]) == *align(4) [2]u8); + } + fn testPointer() void { var array = [5]u8{ 1, 2, 3, 4, 5 }; var pointer: [*]u8 = &array; @@ -188,6 +216,22 @@ test "slicing producing an array" { comptime expect(@TypeOf(pointer[1..3 :4]) == *[2:4]u8); } + fn testPointer0() void { + var pointer: [*]u0 = &[1]u0{0}; + var slice = pointer[0..1]; + comptime expect(@TypeOf(slice) == *[1]u0); + expect(slice[0] == 0); + } + + fn testPointerAlign() void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var pointer: [*]align(4) u8 = &array; + var slice = pointer[4..5]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + expect(slice[0] == 5); + comptime expect(@TypeOf(pointer[0..2]) == *align(4) [2]u8); + } + fn testSlice() void { var array = [5]u8{ 1, 2, 3, 4, 5 }; var src_slice: []u8 = &array; @@ -204,6 +248,30 @@ test "slicing producing an array" { comptime expect(@TypeOf(slice[1..]) == [:0]u8); comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); } + + fn testSlice0() void { + { + var array = [0]u8{}; + var src_slice: []u8 = &array; + var slice = src_slice[0..0]; + comptime expect(@TypeOf(slice) == *[0]u8); + } + { + var array = [0:0]u8{}; + var src_slice: [:0]u8 = &array; + var slice = src_slice[0..0]; + comptime expect(@TypeOf(slice) == *[0]u8); + } + } + + fn testSliceAlign() void { + var array align(4) = [5]u8{ 1, 2, 3, 4, 5 }; + var src_slice: []align(4) u8 = &array; + var slice = src_slice[4..5]; + comptime expect(@TypeOf(slice) == *align(4) [1]u8); + expect(slice[0] == 5); + comptime expect(@TypeOf(src_slice[0..2]) == *align(4) [2]u8); + } }; S.doTheTest(); From 1d7861a36e1bcd8f7bfdb53716ef53467704922b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 13:18:14 -0400 Subject: [PATCH 50/79] fix incorrect sentinel check --- lib/std/crypto/sha2.zig | 6 ++---- src/all_types.hpp | 1 + src/codegen.cpp | 14 +++----------- src/ir.cpp | 6 ++++-- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig index fd7ad532a3..f004bceac3 100644 --- a/lib/std/crypto/sha2.zig +++ b/lib/std/crypto/sha2.zig @@ -167,8 +167,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { const rr = d.s[0 .. params.out_len / 32]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntBig(u32, out[4 * j ..][0..4], s); } } @@ -509,8 +508,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { const rr = d.s[0 .. params.out_len / 64]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s); + mem.writeIntBig(u64, out[8 * j ..][0..8], s); } } diff --git a/src/all_types.hpp b/src/all_types.hpp index 5025ff7cb5..6719d78a92 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3711,6 +3711,7 @@ struct IrInstGenSlice { IrInstGen *start; IrInstGen *end; IrInstGen *result_loc; + ZigValue *sentinel; bool safety_check_on; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index 21e74ba609..8fae16e551 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5425,17 +5425,9 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutableGen *executable, IrI return nullptr; } - ZigValue *sentinel = nullptr; - if (result_type->id == ZigTypeIdPointer) { - ZigType *result_array_type = result_type->data.pointer.child_type; - ir_assert(result_array_type->id == ZigTypeIdArray, &instruction->base); - sentinel = result_array_type->data.array.sentinel; - } else if (result_type->id == ZigTypeIdStruct) { - ZigType *res_slice_ptr_type = result_type->data.structure.fields[slice_ptr_index]->type_entry; - sentinel = res_slice_ptr_type->data.pointer.sentinel; - } else { - zig_unreachable(); - } + // This is not whether the result type has a sentinel, but whether there should be a sentinel check, + // e.g. if they used [a..b :s] syntax. + ZigValue *sentinel = instruction->sentinel; if (array_type->id == ZigTypeIdArray || (array_type->id == ZigTypeIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle)) diff --git a/src/ir.cpp b/src/ir.cpp index e20111e21f..8cd780e46d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3732,7 +3732,8 @@ static IrInstSrc *ir_build_slice_src(IrBuilderSrc *irb, Scope *scope, AstNode *s } static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, ZigType *slice_type, - IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc) + IrInstGen *ptr, IrInstGen *start, IrInstGen *end, bool safety_check_on, IrInstGen *result_loc, + ZigValue *sentinel) { IrInstGenSlice *instruction = ir_build_inst_gen( &ira->new_irb, source_instruction->scope, source_instruction->source_node); @@ -3742,6 +3743,7 @@ static IrInstGen *ir_build_slice_gen(IrAnalyze *ira, IrInst *source_instruction, instruction->end = end; instruction->safety_check_on = safety_check_on; instruction->result_loc = result_loc; + instruction->sentinel = sentinel; ir_ref_inst_gen(ptr, ira->new_irb.current_basic_block); ir_ref_inst_gen(start, ira->new_irb.current_basic_block); @@ -26667,7 +26669,7 @@ done_with_return_type: } return ir_build_slice_gen(ira, &instruction->base.base, return_type, ptr_ptr, - casted_start, end, instruction->safety_check_on, result_loc); + casted_start, end, instruction->safety_check_on, result_loc, sentinel_val); } static IrInstGen *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstSrcHasField *instruction) { From 555a2c03286507ffe4bd3bea2154dbfb719ebef1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 14:38:21 -0400 Subject: [PATCH 51/79] (breaking) std.fs.copyFile now integrates with Dir Removed: * `std.fs.updateFile` * `std.fs.updateFileMode` * `std.fs.copyFile` * `std.fs.copyFileMode` Added: * `std.fs.Dir.copyFile` * `std.fs.copyFileAbsolute` * `std.fs.updateFileAbsolute` Moved: * `std.fs.Dir.UpdateFileOptions` => `std.fs.CopyFileOptions` Deprecated: * `std.fs.deleteDir` * `std.fs.deleteDirC` * `std.fs.deleteDirW` * `std.fs.readLink` * `std.fs.readLinkC` --- lib/std/build.zig | 3 +- lib/std/fs.zig | 115 +++++++++++++++++++++++--------------------- lib/std/os/test.zig | 14 +++--- 3 files changed, 71 insertions(+), 61 deletions(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index fd727c321e..09c77168d6 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -847,7 +847,8 @@ pub const Builder = struct { if (self.verbose) { warn("cp {} {} ", .{ source_path, dest_path }); } - const prev_status = try fs.updateFile(source_path, dest_path); + const cwd = fs.cwd(); + const prev_status = try fs.Dir.updateFile(cwd, source_path, cwd, dest_path, .{}); if (self.verbose) switch (prev_status) { .stale => warn("# installed\n", .{}), .fresh => warn("# up-to-date\n", .{}), diff --git a/lib/std/fs.zig b/lib/std/fs.zig index bc02fd0c91..53cf4b3ce9 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -86,51 +86,33 @@ pub const PrevStatus = enum { fresh, }; -/// Deprecated; use `Dir.updateFile`. -pub fn updateFile(source_path: []const u8, dest_path: []const u8) !PrevStatus { +pub const CopyFileOptions = struct { + /// When this is `null` the mode is copied from the source file. + override_mode: ?File.Mode = null, +}; + +/// Same as `Dir.updateFile`, except asserts that both `source_path` and `dest_path` +/// are absolute. See `Dir.updateFile` for a function that operates on both +/// absolute and relative paths. +pub fn updateFileAbsolute( + source_path: []const u8, + dest_path: []const u8, + args: CopyFileOptions, +) !PrevStatus { + assert(path.isAbsolute(source_path)); + assert(path.isAbsolute(dest_path)); const my_cwd = cwd(); - return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{}); + return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, args); } -/// Deprecated; use `Dir.updateFile`. -pub fn updateFileMode(source_path: []const u8, dest_path: []const u8, mode: ?File.Mode) !Dir.PrevStatus { +/// Same as `Dir.copyFile`, except asserts that both `source_path` and `dest_path` +/// are absolute. See `Dir.copyFile` for a function that operates on both +/// absolute and relative paths. +pub fn copyFileAbsolute(source_path: []const u8, dest_path: []const u8, args: CopyFileOptions) !void { + assert(path.isAbsolute(source_path)); + assert(path.isAbsolute(dest_path)); const my_cwd = cwd(); - return Dir.updateFile(my_cwd, source_path, my_cwd, dest_path, .{ .override_mode = mode }); -} - -/// Guaranteed to be atomic. -/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, -/// there is a possibility of power loss or application termination leaving temporary files present -/// in the same directory as dest_path. -/// Destination file will have the same mode as the source file. -/// TODO rework this to integrate with Dir -pub fn copyFile(source_path: []const u8, dest_path: []const u8) !void { - var in_file = try cwd().openFile(source_path, .{}); - defer in_file.close(); - - const stat = try in_file.stat(); - - var atomic_file = try AtomicFile.init(dest_path, stat.mode); - defer atomic_file.deinit(); - - try atomic_file.file.writeFileAll(in_file, .{ .in_len = stat.size }); - return atomic_file.finish(); -} - -/// Guaranteed to be atomic. -/// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, -/// there is a possibility of power loss or application termination leaving temporary files present -/// in the same directory as dest_path. -/// TODO rework this to integrate with Dir -pub fn copyFileMode(source_path: []const u8, dest_path: []const u8, mode: File.Mode) !void { - var in_file = try cwd().openFile(source_path, .{}); - defer in_file.close(); - - var atomic_file = try AtomicFile.init(dest_path, mode); - defer atomic_file.deinit(); - - try atomic_file.file.writeFileAll(in_file, .{}); - return atomic_file.finish(); + return Dir.copyFile(my_cwd, source_path, my_cwd, dest_path, args); } /// TODO update this API to avoid a getrandom syscall for every operation. @@ -245,18 +227,17 @@ pub fn makeDirAbsoluteW(absolute_path_w: [*:0]const u16) !void { os.windows.CloseHandle(handle); } -/// Returns `error.DirNotEmpty` if the directory is not empty. -/// To delete a directory recursively, see `deleteTree`. +/// Deprecated; use `Dir.deleteDir`. pub fn deleteDir(dir_path: []const u8) !void { return os.rmdir(dir_path); } -/// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. +/// Deprecated; use `Dir.deleteDirC`. pub fn deleteDirC(dir_path: [*:0]const u8) !void { return os.rmdirC(dir_path); } -/// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. +/// Deprecated; use `Dir.deleteDirW`. pub fn deleteDirW(dir_path: [*:0]const u16) !void { return os.rmdirW(dir_path); } @@ -1218,22 +1199,17 @@ pub const Dir = struct { return os.faccessatW(self.fd, sub_path_w, 0, 0); } - pub const UpdateFileOptions = struct { - override_mode: ?File.Mode = null, - }; - /// Check the file size, mtime, and mode of `source_path` and `dest_path`. If they are equal, does nothing. /// Otherwise, atomically copies `source_path` to `dest_path`. The destination file gains the mtime, /// atime, and mode of the source file so that the next call to `updateFile` will not need a copy. /// Returns the previous status of the file before updating. /// If any of the directories do not exist for dest_path, they are created. - /// If `override_mode` is provided, then that value is used rather than the source path's mode. pub fn updateFile( source_dir: Dir, source_path: []const u8, dest_dir: Dir, dest_path: []const u8, - options: UpdateFileOptions, + options: CopyFileOptions, ) !PrevStatus { var src_file = try source_dir.openFile(source_path, .{}); defer src_file.close(); @@ -1272,6 +1248,34 @@ pub const Dir = struct { return PrevStatus.stale; } + /// Guaranteed to be atomic. + /// On Linux, until https://patchwork.kernel.org/patch/9636735/ is merged and readily available, + /// there is a possibility of power loss or application termination leaving temporary files present + /// in the same directory as dest_path. + pub fn copyFile( + source_dir: Dir, + source_path: []const u8, + dest_dir: Dir, + dest_path: []const u8, + options: CopyFileOptions, + ) !void { + var in_file = try source_dir.openFile(source_path, .{}); + defer in_file.close(); + + var size: ?u64 = null; + const mode = options.override_mode orelse blk: { + const stat = try in_file.stat(); + size = stat.size; + break :blk stat.mode; + }; + + var atomic_file = try dest_dir.atomicFile(dest_path, .{ .mode = mode }); + defer atomic_file.deinit(); + + try atomic_file.file.writeFileAll(in_file, .{ .in_len = size }); + return atomic_file.finish(); + } + pub const AtomicFileOptions = struct { mode: File.Mode = File.default_mode, }; @@ -1471,13 +1475,12 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { return walker; } -/// Read value of a symbolic link. -/// The return value is a slice of buffer, from index `0`. +/// Deprecated; use `Dir.readLink`. pub fn readLink(pathname: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { return os.readlink(pathname, buffer); } -/// Same as `readLink`, except the parameter is null-terminated. +/// Deprecated; use `Dir.readLinkC`. pub fn readLinkC(pathname_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { return os.readlinkC(pathname_c, buffer); } @@ -1584,6 +1587,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const } /// `realpath`, except caller must free the returned memory. +/// TODO integrate with `Dir` pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); @@ -1592,6 +1596,9 @@ pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { test "" { _ = makeDirAbsolute; _ = makeDirAbsoluteZ; + _ = copyFileAbsolute; + _ = updateFileAbsolute; + _ = Dir.copyFile; _ = @import("fs/path.zig"); _ = @import("fs/file.zig"); _ = @import("fs/get_app_data_dir.zig"); diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 14a865904b..154932d9c5 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -113,14 +113,16 @@ test "fs.copyFile" { const dest_file = "tmp_test_copy_file2.txt"; const dest_file2 = "tmp_test_copy_file3.txt"; - try fs.cwd().writeFile(src_file, data); - defer fs.cwd().deleteFile(src_file) catch {}; + const cwd = fs.cwd(); - try fs.copyFile(src_file, dest_file); - defer fs.cwd().deleteFile(dest_file) catch {}; + try cwd.writeFile(src_file, data); + defer cwd.deleteFile(src_file) catch {}; - try fs.copyFileMode(src_file, dest_file2, File.default_mode); - defer fs.cwd().deleteFile(dest_file2) catch {}; + try cwd.copyFile(src_file, cwd, dest_file, .{}); + defer cwd.deleteFile(dest_file) catch {}; + + try cwd.copyFile(src_file, cwd, dest_file2, .{ .override_mode = File.default_mode }); + defer cwd.deleteFile(dest_file2) catch {}; try expectFileContents(dest_file, data); try expectFileContents(dest_file2, data); From f614d94faa3b2a259c3a82cd66f167029f20d224 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 14:48:47 -0400 Subject: [PATCH 52/79] update std lib to take advantage of slicing with comptime indexes --- lib/std/crypto/aes.zig | 38 +++++++++++------------ lib/std/crypto/blake2.zig | 11 +++---- lib/std/crypto/chacha20.zig | 61 ++++++++++++++++++------------------- lib/std/crypto/md5.zig | 3 +- lib/std/crypto/poly1305.zig | 29 +++++++++--------- lib/std/crypto/sha1.zig | 3 +- lib/std/crypto/sha3.zig | 5 ++- lib/std/crypto/x25519.zig | 41 ++++++++++++------------- lib/std/hash/siphash.zig | 6 ++-- lib/std/hash/wyhash.zig | 2 +- lib/std/mem.zig | 6 ++-- lib/std/rand.zig | 2 +- lib/std/unicode.zig | 20 ++++++------ 13 files changed, 108 insertions(+), 119 deletions(-) diff --git a/lib/std/crypto/aes.zig b/lib/std/crypto/aes.zig index 1cc166f943..81dc56f0b3 100644 --- a/lib/std/crypto/aes.zig +++ b/lib/std/crypto/aes.zig @@ -15,10 +15,10 @@ fn rotw(w: u32) u32 { // Encrypt one block from src into dst, using the expanded key xk. fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { - var s0 = mem.readIntSliceBig(u32, src[0..4]); - var s1 = mem.readIntSliceBig(u32, src[4..8]); - var s2 = mem.readIntSliceBig(u32, src[8..12]); - var s3 = mem.readIntSliceBig(u32, src[12..16]); + var s0 = mem.readIntBig(u32, src[0..4]); + var s1 = mem.readIntBig(u32, src[4..8]); + var s2 = mem.readIntBig(u32, src[8..12]); + var s3 = mem.readIntBig(u32, src[12..16]); // First round just XORs input with key. s0 ^= xk[0]; @@ -58,18 +58,18 @@ fn encryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { s2 ^= xk[k + 2]; s3 ^= xk[k + 3]; - mem.writeIntSliceBig(u32, dst[0..4], s0); - mem.writeIntSliceBig(u32, dst[4..8], s1); - mem.writeIntSliceBig(u32, dst[8..12], s2); - mem.writeIntSliceBig(u32, dst[12..16], s3); + mem.writeIntBig(u32, dst[0..4], s0); + mem.writeIntBig(u32, dst[4..8], s1); + mem.writeIntBig(u32, dst[8..12], s2); + mem.writeIntBig(u32, dst[12..16], s3); } // Decrypt one block from src into dst, using the expanded key xk. pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { - var s0 = mem.readIntSliceBig(u32, src[0..4]); - var s1 = mem.readIntSliceBig(u32, src[4..8]); - var s2 = mem.readIntSliceBig(u32, src[8..12]); - var s3 = mem.readIntSliceBig(u32, src[12..16]); + var s0 = mem.readIntBig(u32, src[0..4]); + var s1 = mem.readIntBig(u32, src[4..8]); + var s2 = mem.readIntBig(u32, src[8..12]); + var s3 = mem.readIntBig(u32, src[12..16]); // First round just XORs input with key. s0 ^= xk[0]; @@ -109,10 +109,10 @@ pub fn decryptBlock(xk: []const u32, dst: []u8, src: []const u8) void { s2 ^= xk[k + 2]; s3 ^= xk[k + 3]; - mem.writeIntSliceBig(u32, dst[0..4], s0); - mem.writeIntSliceBig(u32, dst[4..8], s1); - mem.writeIntSliceBig(u32, dst[8..12], s2); - mem.writeIntSliceBig(u32, dst[12..16], s3); + mem.writeIntBig(u32, dst[0..4], s0); + mem.writeIntBig(u32, dst[4..8], s1); + mem.writeIntBig(u32, dst[8..12], s2); + mem.writeIntBig(u32, dst[12..16], s3); } fn xorBytes(dst: []u8, a: []const u8, b: []const u8) usize { @@ -154,8 +154,8 @@ fn AES(comptime keysize: usize) type { var n: usize = 0; while (n < src.len) { ctx.encrypt(keystream[0..], ctrbuf[0..]); - var ctr_i = std.mem.readIntSliceBig(u128, ctrbuf[0..]); - std.mem.writeIntSliceBig(u128, ctrbuf[0..], ctr_i +% 1); + var ctr_i = std.mem.readIntBig(u128, ctrbuf[0..]); + std.mem.writeIntBig(u128, ctrbuf[0..], ctr_i +% 1); n += xorBytes(dst[n..], src[n..], &keystream); } @@ -251,7 +251,7 @@ fn expandKey(key: []const u8, enc: []u32, dec: []u32) void { var i: usize = 0; var nk = key.len / 4; while (i < nk) : (i += 1) { - enc[i] = mem.readIntSliceBig(u32, key[4 * i .. 4 * i + 4]); + enc[i] = mem.readIntBig(u32, key[4 * i ..][0..4]); } while (i < enc.len) : (i += 1) { var t = enc[i - 1]; diff --git a/lib/std/crypto/blake2.zig b/lib/std/crypto/blake2.zig index e03d8f7dab..fc1d59290e 100644 --- a/lib/std/crypto/blake2.zig +++ b/lib/std/crypto/blake2.zig @@ -123,8 +123,7 @@ fn Blake2s(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 32]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntLittle(u32, out[4 * j ..][0..4], s); } } @@ -135,8 +134,7 @@ fn Blake2s(comptime out_len: usize) type { var v: [16]u32 = undefined; for (m) |*r, i| { - // TODO https://github.com/ziglang/zig/issues/863 - r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]); + r.* = mem.readIntLittle(u32, b[4 * i ..][0..4]); } var k: usize = 0; @@ -358,8 +356,7 @@ fn Blake2b(comptime out_len: usize) type { const rr = d.h[0 .. out_len / 64]; for (rr) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s); + mem.writeIntLittle(u64, out[8 * j ..][0..8], s); } } @@ -370,7 +367,7 @@ fn Blake2b(comptime out_len: usize) type { var v: [16]u64 = undefined; for (m) |*r, i| { - r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]); + r.* = mem.readIntLittle(u64, b[8 * i ..][0..8]); } var k: usize = 0; diff --git a/lib/std/crypto/chacha20.zig b/lib/std/crypto/chacha20.zig index d67877b051..f6008745af 100644 --- a/lib/std/crypto/chacha20.zig +++ b/lib/std/crypto/chacha20.zig @@ -61,8 +61,7 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void { } for (x) |_, i| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]); + mem.writeIntLittle(u32, out[4 * i ..][0..4], x[i] +% input[i]); } } @@ -73,10 +72,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo const c = "expand 32-byte k"; const constant_le = [_]u32{ - mem.readIntSliceLittle(u32, c[0..4]), - mem.readIntSliceLittle(u32, c[4..8]), - mem.readIntSliceLittle(u32, c[8..12]), - mem.readIntSliceLittle(u32, c[12..16]), + mem.readIntLittle(u32, c[0..4]), + mem.readIntLittle(u32, c[4..8]), + mem.readIntLittle(u32, c[8..12]), + mem.readIntLittle(u32, c[12..16]), }; mem.copy(u32, ctx[0..], constant_le[0..4]); @@ -120,19 +119,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce: var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntSliceLittle(u32, key[0..4]); - k[1] = mem.readIntSliceLittle(u32, key[4..8]); - k[2] = mem.readIntSliceLittle(u32, key[8..12]); - k[3] = mem.readIntSliceLittle(u32, key[12..16]); - k[4] = mem.readIntSliceLittle(u32, key[16..20]); - k[5] = mem.readIntSliceLittle(u32, key[20..24]); - k[6] = mem.readIntSliceLittle(u32, key[24..28]); - k[7] = mem.readIntSliceLittle(u32, key[28..32]); + k[0] = mem.readIntLittle(u32, key[0..4]); + k[1] = mem.readIntLittle(u32, key[4..8]); + k[2] = mem.readIntLittle(u32, key[8..12]); + k[3] = mem.readIntLittle(u32, key[12..16]); + k[4] = mem.readIntLittle(u32, key[16..20]); + k[5] = mem.readIntLittle(u32, key[20..24]); + k[6] = mem.readIntLittle(u32, key[24..28]); + k[7] = mem.readIntLittle(u32, key[28..32]); c[0] = counter; - c[1] = mem.readIntSliceLittle(u32, nonce[0..4]); - c[2] = mem.readIntSliceLittle(u32, nonce[4..8]); - c[3] = mem.readIntSliceLittle(u32, nonce[8..12]); + c[1] = mem.readIntLittle(u32, nonce[0..4]); + c[2] = mem.readIntLittle(u32, nonce[4..8]); + c[3] = mem.readIntLittle(u32, nonce[8..12]); chaCha20_internal(out, in, k, c); } @@ -147,19 +146,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32] var k: [8]u32 = undefined; var c: [4]u32 = undefined; - k[0] = mem.readIntSliceLittle(u32, key[0..4]); - k[1] = mem.readIntSliceLittle(u32, key[4..8]); - k[2] = mem.readIntSliceLittle(u32, key[8..12]); - k[3] = mem.readIntSliceLittle(u32, key[12..16]); - k[4] = mem.readIntSliceLittle(u32, key[16..20]); - k[5] = mem.readIntSliceLittle(u32, key[20..24]); - k[6] = mem.readIntSliceLittle(u32, key[24..28]); - k[7] = mem.readIntSliceLittle(u32, key[28..32]); + k[0] = mem.readIntLittle(u32, key[0..4]); + k[1] = mem.readIntLittle(u32, key[4..8]); + k[2] = mem.readIntLittle(u32, key[8..12]); + k[3] = mem.readIntLittle(u32, key[12..16]); + k[4] = mem.readIntLittle(u32, key[16..20]); + k[5] = mem.readIntLittle(u32, key[20..24]); + k[6] = mem.readIntLittle(u32, key[24..28]); + k[7] = mem.readIntLittle(u32, key[28..32]); c[0] = @truncate(u32, counter); c[1] = @truncate(u32, counter >> 32); - c[2] = mem.readIntSliceLittle(u32, nonce[0..4]); - c[3] = mem.readIntSliceLittle(u32, nonce[4..8]); + c[2] = mem.readIntLittle(u32, nonce[0..4]); + c[3] = mem.readIntLittle(u32, nonce[4..8]); const block_size = (1 << 6); // The full block size is greater than the address space on a 32bit machine @@ -463,8 +462,8 @@ pub fn chacha20poly1305Seal(dst: []u8, plaintext: []const u8, data: []const u8, mac.update(zeros[0..padding]); } var lens: [16]u8 = undefined; - mem.writeIntSliceLittle(u64, lens[0..8], data.len); - mem.writeIntSliceLittle(u64, lens[8..16], plaintext.len); + mem.writeIntLittle(u64, lens[0..8], data.len); + mem.writeIntLittle(u64, lens[8..16], plaintext.len); mac.update(lens[0..]); mac.final(dst[plaintext.len..]); } @@ -500,8 +499,8 @@ pub fn chacha20poly1305Open(dst: []u8, msgAndTag: []const u8, data: []const u8, mac.update(zeros[0..padding]); } var lens: [16]u8 = undefined; - mem.writeIntSliceLittle(u64, lens[0..8], data.len); - mem.writeIntSliceLittle(u64, lens[8..16], ciphertext.len); + mem.writeIntLittle(u64, lens[0..8], data.len); + mem.writeIntLittle(u64, lens[8..16], ciphertext.len); mac.update(lens[0..]); var computedTag: [16]u8 = undefined; mac.final(computedTag[0..]); diff --git a/lib/std/crypto/md5.zig b/lib/std/crypto/md5.zig index d9dd08c904..ac8948ca20 100644 --- a/lib/std/crypto/md5.zig +++ b/lib/std/crypto/md5.zig @@ -112,8 +112,7 @@ pub const Md5 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntLittle(u32, out[4 * j ..][0..4], s); } } diff --git a/lib/std/crypto/poly1305.zig b/lib/std/crypto/poly1305.zig index 2395b1c7aa..fda978307d 100644 --- a/lib/std/crypto/poly1305.zig +++ b/lib/std/crypto/poly1305.zig @@ -3,11 +3,11 @@ // https://monocypher.org/ const std = @import("../std.zig"); -const builtin = @import("builtin"); +const builtin = std.builtin; const Endian = builtin.Endian; -const readIntSliceLittle = std.mem.readIntSliceLittle; -const writeIntSliceLittle = std.mem.writeIntSliceLittle; +const readIntLittle = std.mem.readIntLittle; +const writeIntLittle = std.mem.writeIntLittle; pub const Poly1305 = struct { const Self = @This(); @@ -59,19 +59,19 @@ pub const Poly1305 = struct { { var i: usize = 0; while (i < 1) : (i += 1) { - ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff; + ctx.r[0] = readIntLittle(u32, key[0..4]) & 0x0fffffff; } } { var i: usize = 1; while (i < 4) : (i += 1) { - ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc; + ctx.r[i] = readIntLittle(u32, key[i * 4 ..][0..4]) & 0x0ffffffc; } } { var i: usize = 0; while (i < 4) : (i += 1) { - ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]); + ctx.pad[i] = readIntLittle(u32, key[i * 4 + 16 ..][0..4]); } } @@ -168,10 +168,10 @@ pub const Poly1305 = struct { const nb_blocks = nmsg.len >> 4; var i: usize = 0; while (i < nb_blocks) : (i += 1) { - ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]); - ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]); - ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]); - ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]); + ctx.c[0] = readIntLittle(u32, nmsg[0..4]); + ctx.c[1] = readIntLittle(u32, nmsg[4..8]); + ctx.c[2] = readIntLittle(u32, nmsg[8..12]); + ctx.c[3] = readIntLittle(u32, nmsg[12..16]); polyBlock(ctx); nmsg = nmsg[16..]; } @@ -210,11 +210,10 @@ pub const Poly1305 = struct { const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000 const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000 - // TODO https://github.com/ziglang/zig/issues/863 - writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0)); - writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1)); - writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2)); - writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3)); + writeIntLittle(u32, out[0..4], @truncate(u32, uu0)); + writeIntLittle(u32, out[4..8], @truncate(u32, uu1)); + writeIntLittle(u32, out[8..12], @truncate(u32, uu2)); + writeIntLittle(u32, out[12..16], @truncate(u32, uu3)); ctx.secureZero(); } diff --git a/lib/std/crypto/sha1.zig b/lib/std/crypto/sha1.zig index 5be42180a1..6edf7b745e 100644 --- a/lib/std/crypto/sha1.zig +++ b/lib/std/crypto/sha1.zig @@ -109,8 +109,7 @@ pub const Sha1 = struct { d.round(d.buf[0..]); for (d.s) |s, j| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s); + mem.writeIntBig(u32, out[4 * j ..][0..4], s); } } diff --git a/lib/std/crypto/sha3.zig b/lib/std/crypto/sha3.zig index d7b2fbe256..7c60674d75 100644 --- a/lib/std/crypto/sha3.zig +++ b/lib/std/crypto/sha3.zig @@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { var c = [_]u64{0} ** 5; for (s) |*r, i| { - r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]); + r.* = mem.readIntLittle(u64, d[8 * i ..][0..8]); } comptime var x: usize = 0; @@ -167,8 +167,7 @@ fn keccak_f(comptime F: usize, d: []u8) void { } for (s) |r, i| { - // TODO https://github.com/ziglang/zig/issues/863 - mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r); + mem.writeIntLittle(u64, d[8 * i ..][0..8], r); } } diff --git a/lib/std/crypto/x25519.zig b/lib/std/crypto/x25519.zig index 16e3f073f8..e2e2bf90e5 100644 --- a/lib/std/crypto/x25519.zig +++ b/lib/std/crypto/x25519.zig @@ -7,8 +7,8 @@ const builtin = @import("builtin"); const fmt = std.fmt; const Endian = builtin.Endian; -const readIntSliceLittle = std.mem.readIntSliceLittle; -const writeIntSliceLittle = std.mem.writeIntSliceLittle; +const readIntLittle = std.mem.readIntLittle; +const writeIntLittle = std.mem.writeIntLittle; // Based on Supercop's ref10 implementation. pub const X25519 = struct { @@ -255,16 +255,16 @@ const Fe = struct { var t: [10]i64 = undefined; - t[0] = readIntSliceLittle(u32, s[0..4]); - t[1] = @as(u32, readIntSliceLittle(u24, s[4..7])) << 6; - t[2] = @as(u32, readIntSliceLittle(u24, s[7..10])) << 5; - t[3] = @as(u32, readIntSliceLittle(u24, s[10..13])) << 3; - t[4] = @as(u32, readIntSliceLittle(u24, s[13..16])) << 2; - t[5] = readIntSliceLittle(u32, s[16..20]); - t[6] = @as(u32, readIntSliceLittle(u24, s[20..23])) << 7; - t[7] = @as(u32, readIntSliceLittle(u24, s[23..26])) << 5; - t[8] = @as(u32, readIntSliceLittle(u24, s[26..29])) << 4; - t[9] = (@as(u32, readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2; + t[0] = readIntLittle(u32, s[0..4]); + t[1] = @as(u32, readIntLittle(u24, s[4..7])) << 6; + t[2] = @as(u32, readIntLittle(u24, s[7..10])) << 5; + t[3] = @as(u32, readIntLittle(u24, s[10..13])) << 3; + t[4] = @as(u32, readIntLittle(u24, s[13..16])) << 2; + t[5] = readIntLittle(u32, s[16..20]); + t[6] = @as(u32, readIntLittle(u24, s[20..23])) << 7; + t[7] = @as(u32, readIntLittle(u24, s[23..26])) << 5; + t[8] = @as(u32, readIntLittle(u24, s[26..29])) << 4; + t[9] = (@as(u32, readIntLittle(u24, s[29..32])) & 0x7fffff) << 2; carry1(h, t[0..]); } @@ -544,15 +544,14 @@ const Fe = struct { ut[i] = @bitCast(u32, @intCast(i32, t[i])); } - // TODO https://github.com/ziglang/zig/issues/863 - writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); - writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); - writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); - writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); - writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); - writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); - writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); - writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6)); + writeIntLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26)); + writeIntLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19)); + writeIntLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13)); + writeIntLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6)); + writeIntLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25)); + writeIntLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19)); + writeIntLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12)); + writeIntLittle(u32, s[28..32], (ut[8] >> 20) | (ut[9] << 6)); std.mem.secureZero(i64, t[0..]); } diff --git a/lib/std/hash/siphash.zig b/lib/std/hash/siphash.zig index ccef47c4b2..ebafdd6855 100644 --- a/lib/std/hash/siphash.zig +++ b/lib/std/hash/siphash.zig @@ -39,8 +39,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round pub fn init(key: []const u8) Self { assert(key.len >= 16); - const k0 = mem.readIntSliceLittle(u64, key[0..8]); - const k1 = mem.readIntSliceLittle(u64, key[8..16]); + const k0 = mem.readIntLittle(u64, key[0..8]); + const k1 = mem.readIntLittle(u64, key[8..16]); var d = Self{ .v0 = k0 ^ 0x736f6d6570736575, @@ -111,7 +111,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round fn round(self: *Self, b: []const u8) void { assert(b.len == 8); - const m = mem.readIntSliceLittle(u64, b[0..]); + const m = mem.readIntLittle(u64, b[0..8]); self.v3 ^= m; // TODO this is a workaround, should be able to supply the value without a separate variable diff --git a/lib/std/hash/wyhash.zig b/lib/std/hash/wyhash.zig index 8fcbbbce4c..8b7edd246f 100644 --- a/lib/std/hash/wyhash.zig +++ b/lib/std/hash/wyhash.zig @@ -11,7 +11,7 @@ const primes = [_]u64{ fn read_bytes(comptime bytes: u8, data: []const u8) u64 { const T = std.meta.IntType(false, 8 * bytes); - return mem.readIntSliceLittle(T, data[0..bytes]); + return mem.readIntLittle(T, data[0..bytes]); } fn read_8bytes_swapped(data: []const u8) u64 { diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 951f40ef19..2f7a21c6b6 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -824,8 +824,7 @@ pub const readIntBig = switch (builtin.endian) { pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T { const n = @divExact(T.bit_count, 8); assert(bytes.len >= n); - // TODO https://github.com/ziglang/zig/issues/863 - return readIntNative(T, @ptrCast(*const [n]u8, bytes.ptr)); + return readIntNative(T, bytes[0..n]); } /// Asserts that bytes.len >= T.bit_count / 8. Reads the integer starting from index 0 @@ -863,8 +862,7 @@ pub fn readInt(comptime T: type, bytes: *const [@divExact(T.bit_count, 8)]u8, en pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T { const n = @divExact(T.bit_count, 8); assert(bytes.len >= n); - // TODO https://github.com/ziglang/zig/issues/863 - return readInt(T, @ptrCast(*const [n]u8, bytes.ptr), endian); + return readInt(T, bytes[0..n], endian); } test "comptime read/write int" { diff --git a/lib/std/rand.zig b/lib/std/rand.zig index 31891f5f0e..ede46e3065 100644 --- a/lib/std/rand.zig +++ b/lib/std/rand.zig @@ -5,7 +5,7 @@ // ``` // var buf: [8]u8 = undefined; // try std.crypto.randomBytes(buf[0..]); -// const seed = mem.readIntSliceLittle(u64, buf[0..8]); +// const seed = mem.readIntLittle(u64, buf[0..8]); // // var r = DefaultPrng.init(seed); // diff --git a/lib/std/unicode.zig b/lib/std/unicode.zig index 8ed51fa145..a971a730e8 100644 --- a/lib/std/unicode.zig +++ b/lib/std/unicode.zig @@ -251,12 +251,12 @@ pub const Utf16LeIterator = struct { pub fn nextCodepoint(it: *Utf16LeIterator) !?u21 { assert(it.i <= it.bytes.len); if (it.i == it.bytes.len) return null; - const c0: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); + const c0: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); if (c0 & ~@as(u21, 0x03ff) == 0xd800) { // surrogate pair it.i += 2; if (it.i >= it.bytes.len) return error.DanglingSurrogateHalf; - const c1: u21 = mem.readIntSliceLittle(u16, it.bytes[it.i .. it.i + 2]); + const c1: u21 = mem.readIntLittle(u16, it.bytes[it.i..][0..2]); if (c1 & ~@as(u21, 0x03ff) != 0xdc00) return error.ExpectedSecondSurrogateHalf; it.i += 2; return 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)); @@ -630,11 +630,11 @@ test "utf8ToUtf16LeWithNull" { } } -/// Converts a UTF-8 string literal into a UTF-16LE string literal. -pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8) :0] u16 { +/// Converts a UTF-8 string literal into a UTF-16LE string literal. +pub fn utf8ToUtf16LeStringLiteral(comptime utf8: []const u8) *const [calcUtf16LeLen(utf8):0]u16 { comptime { const len: usize = calcUtf16LeLen(utf8); - var utf16le: [len :0]u16 = [_ :0]u16{0} ** len; + var utf16le: [len:0]u16 = [_:0]u16{0} ** len; const utf16le_len = utf8ToUtf16Le(&utf16le, utf8[0..]) catch |err| @compileError(err); assert(len == utf16le_len); return &utf16le; @@ -660,8 +660,8 @@ fn calcUtf16LeLen(utf8: []const u8) usize { } test "utf8ToUtf16LeStringLiteral" { -{ - const bytes = [_:0]u16{ 0x41 }; + { + const bytes = [_:0]u16{0x41}; const utf16 = utf8ToUtf16LeStringLiteral("A"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); @@ -673,19 +673,19 @@ test "utf8ToUtf16LeStringLiteral" { testing.expect(utf16[2] == 0); } { - const bytes = [_:0]u16{ 0x02FF }; + const bytes = [_:0]u16{0x02FF}; const utf16 = utf8ToUtf16LeStringLiteral("\u{02FF}"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); } { - const bytes = [_:0]u16{ 0x7FF }; + const bytes = [_:0]u16{0x7FF}; const utf16 = utf8ToUtf16LeStringLiteral("\u{7FF}"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); } { - const bytes = [_:0]u16{ 0x801 }; + const bytes = [_:0]u16{0x801}; const utf16 = utf8ToUtf16LeStringLiteral("\u{801}"); testing.expectEqualSlices(u16, &bytes, utf16); testing.expect(utf16[1] == 0); From 6b6f2fcf96b0d8493be45b484226ea8ae9a83a88 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 15:09:52 -0400 Subject: [PATCH 53/79] std.net: remove the hack from earlier in the branch --- lib/std/net.zig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/std/net.zig b/lib/std/net.zig index 44efc4644a..b9c1281191 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -957,8 +957,10 @@ fn linuxLookupNameFromDns( } } - var hack: usize = 0; // TODO remove this hack - var ap = [2][]u8{ apbuf[0][0..hack], apbuf[1][0..hack] }; + var ap = [2][]u8{ apbuf[0], apbuf[1] }; + ap[0].len = 0; + ap[1].len = 0; + try resMSendRc(qp[0..nq], ap[0..nq], apbuf[0..nq], rc); var i: usize = 0; From 160367e0ddcb36b6957e603d869507b9d7542edc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 17:23:53 -0400 Subject: [PATCH 54/79] fix compile error for reading past end of pointer casted array --- src/ir.cpp | 28 +++++++++++++++++++++++++++- test/compile_errors.zig | 21 ++++++++++----------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 8cd780e46d..b3b3198ce1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -19971,6 +19971,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf), pointee); if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; + buf_deinit(&buf); return ErrorNone; } @@ -19990,7 +19991,31 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source dst_size, buf_ptr(&pointee->type->name), src_size)); return ErrorSemanticAnalyzeFail; } - case ConstPtrSpecialSubArray: + case ConstPtrSpecialSubArray: { + ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; + assert(array_val->type->id == ZigTypeIdArray); + if (array_val->data.x_array.special != ConstArraySpecialNone) + zig_panic("TODO"); + if (dst_size > src_size) { + size_t elem_index = ptr_val->data.x_ptr.data.base_array.elem_index; + opt_ir_add_error_node(ira, codegen, source_node, + buf_sprintf("attempt to read %" ZIG_PRI_usize " bytes from %s at index %" ZIG_PRI_usize " which is %" ZIG_PRI_usize " bytes", + dst_size, buf_ptr(&array_val->type->name), elem_index, src_size)); + return ErrorSemanticAnalyzeFail; + } + size_t elem_size = src_size; + size_t elem_count = (dst_size % elem_size == 0) ? (dst_size / elem_size) : (dst_size / elem_size + 1); + Buf buf = BUF_INIT; + buf_resize(&buf, elem_count * elem_size); + for (size_t i = 0; i < elem_count; i += 1) { + ZigValue *elem_val = &array_val->data.x_array.data.s_none.elements[i]; + buf_write_value_bytes(codegen, (uint8_t*)buf_ptr(&buf) + (i * elem_size), elem_val); + } + if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) + return err; + buf_deinit(&buf); + return ErrorNone; + } case ConstPtrSpecialBaseArray: { ZigValue *array_val = ptr_val->data.x_ptr.data.base_array.array_val; assert(array_val->type->id == ZigTypeIdArray); @@ -20014,6 +20039,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source } if ((err = buf_read_value_bytes(ira, codegen, source_node, (uint8_t*)buf_ptr(&buf), out_val))) return err; + buf_deinit(&buf); return ErrorNone; } case ConstPtrSpecialBaseStruct: diff --git a/test/compile_errors.zig b/test/compile_errors.zig index abcdc48dc6..e3e1462173 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1903,17 +1903,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:7:15: error: switch must handle all possibilities", }); - // TODO uncomment before merging branch - //cases.add("reading past end of pointer casted array", - // \\comptime { - // \\ const array: [4]u8 = "aoeu".*; - // \\ const sub_array = array[1..]; - // \\ const int_ptr = @ptrCast(*const u24, sub_array); - // \\ const deref = int_ptr.*; - // \\} - //, &[_][]const u8{ - // "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes", - //}); + cases.add("reading past end of pointer casted array", + \\comptime { + \\ const array: [4]u8 = "aoeu".*; + \\ const sub_array = array[1..]; + \\ const int_ptr = @ptrCast(*const u24, sub_array); + \\ const deref = int_ptr.*; + \\} + , &[_][]const u8{ + "tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes", + }); cases.add("error note for function parameter incompatibility", \\fn do_the_thing(func: fn (arg: i32) void) void {} From 28a6c136e9dc9bcf3e04ab0aa38edc21918c78b9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 19 Mar 2020 19:30:09 -0400 Subject: [PATCH 55/79] revert std.mem.span to prefer len over sentinel; add spanZ --- lib/std/mem.zig | 103 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 2f7a21c6b6..fa2794160b 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -496,14 +496,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { return true; } -/// Deprecated. Use `span`. +/// Deprecated. Use `spanZ`. pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { - return ptr[0..len(ptr) :0]; + return ptr[0..lenZ(ptr) :0]; } -/// Deprecated. Use `span`. +/// Deprecated. Use `spanZ`. pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { - return ptr[0..len(ptr) :0]; + return ptr[0..lenZ(ptr) :0]; } /// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and @@ -548,6 +548,9 @@ test "Span" { /// returns a slice. If there is a sentinel on the input type, there will be a /// sentinel on the output type. The constness of the output type matches /// the constness of the input type. +/// +/// When there is both a sentinel and an array length or slice length, the +/// length value is used instead of the sentinel. pub fn span(ptr: var) Span(@TypeOf(ptr)) { const Result = Span(@TypeOf(ptr)); const l = len(ptr); @@ -565,23 +568,37 @@ test "span" { testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); } +/// Same as `span`, except when there is both a sentinel and an array +/// length or slice length, scans the memory for the sentinel value +/// rather than using the length. +pub fn spanZ(ptr: var) Span(@TypeOf(ptr)) { + const Result = Span(@TypeOf(ptr)); + const l = lenZ(ptr); + if (@typeInfo(Result).Pointer.sentinel) |s| { + return ptr[0..l :s]; + } else { + return ptr[0..l]; + } +} + +test "spanZ" { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + const ptr = @as([*:3]u16, array[0..2 :3]); + testing.expect(eql(u16, spanZ(ptr), &[_]u16{ 1, 2 })); + testing.expect(eql(u16, spanZ(&array), &[_]u16{ 1, 2, 3, 4, 5 })); +} + /// Takes a pointer to an array, an array, a sentinel-terminated pointer, /// or a slice, and returns the length. -/// In the case of a sentinel-terminated array, it scans the array -/// for a sentinel and uses that for the length, rather than using the array length. +/// In the case of a sentinel-terminated array, it uses the array length. +/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. pub fn len(ptr: var) usize { return switch (@typeInfo(@TypeOf(ptr))) { - .Array => |info| if (info.sentinel) |sentinel| - indexOfSentinel(info.child, sentinel, &ptr) - else - info.len, + .Array => |info| info.len, .Pointer => |info| switch (info.size) { .One => switch (@typeInfo(info.child)) { - .Array => |x| if (x.sentinel) |sentinel| - indexOfSentinel(x.child, sentinel, ptr) - else - ptr.len, - else => @compileError("invalid type given to std.mem.length"), + .Array => ptr.len, + else => @compileError("invalid type given to std.mem.len"), }, .Many => if (info.sentinel) |sentinel| indexOfSentinel(info.child, sentinel, ptr) @@ -590,7 +607,7 @@ pub fn len(ptr: var) usize { .C => indexOfSentinel(info.child, 0, ptr), .Slice => ptr.len, }, - else => @compileError("invalid type given to std.mem.length"), + else => @compileError("invalid type given to std.mem.len"), }; } @@ -609,7 +626,59 @@ test "len" { var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; testing.expect(len(&array) == 5); array[2] = 0; - testing.expect(len(&array) == 2); + testing.expect(len(&array) == 5); + } +} + +/// Takes a pointer to an array, an array, a sentinel-terminated pointer, +/// or a slice, and returns the length. +/// In the case of a sentinel-terminated array, it scans the array +/// for a sentinel and uses that for the length, rather than using the array length. +/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. +pub fn lenZ(ptr: var) usize { + return switch (@typeInfo(@TypeOf(ptr))) { + .Array => |info| if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, &ptr) + else + info.len, + .Pointer => |info| switch (info.size) { + .One => switch (@typeInfo(info.child)) { + .Array => |x| if (x.sentinel) |sentinel| + indexOfSentinel(x.child, sentinel, ptr) + else + ptr.len, + else => @compileError("invalid type given to std.mem.lenZ"), + }, + .Many => if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, ptr) + else + @compileError("length of pointer with no sentinel"), + .C => indexOfSentinel(info.child, 0, ptr), + .Slice => if (info.sentinel) |sentinel| + indexOfSentinel(info.child, sentinel, ptr.ptr) + else + ptr.len, + }, + else => @compileError("invalid type given to std.mem.lenZ"), + }; +} + +test "lenZ" { + testing.expect(lenZ("aoeu") == 4); + + { + var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; + testing.expect(lenZ(&array) == 5); + testing.expect(lenZ(array[0..3]) == 3); + array[2] = 0; + const ptr = @as([*:0]u16, array[0..2 :0]); + testing.expect(lenZ(ptr) == 2); + } + { + var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; + testing.expect(lenZ(&array) == 5); + array[2] = 0; + testing.expect(lenZ(&array) == 2); } } From 541e763010403d8233a6420756a1e8393f1dd4c2 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 20 Mar 2020 12:59:55 +0100 Subject: [PATCH 56/79] ir: Peer type resolution between ?[]T and *[N]T Closes #4767 --- lib/std/net.zig | 4 ++-- src/ir.cpp | 17 ++++++++++++++--- test/stage1/behavior/slice.zig | 8 ++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/std/net.zig b/lib/std/net.zig index b9c1281191..0a789b0dde 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -820,7 +820,7 @@ fn linuxLookupNameFromHosts( // Skip to the delimiter in the stream, to fix parsing try stream.skipUntilDelimiterOrEof('\n'); // Use the truncated line. A truncated comment or hostname will be handled correctly. - break :blk @as([]u8, &line_buf); // TODO the cast should not be necessary + break :blk &line_buf; }, else => |e| return e, }) |line| { @@ -1017,7 +1017,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { // Skip to the delimiter in the stream, to fix parsing try stream.skipUntilDelimiterOrEof('\n'); // Give an empty line to the while loop, which will be skipped. - break :blk @as([]u8, line_buf[0..0]); // TODO the cast should not be necessary + break :blk line_buf[0..0]; }, else => |e| return e, }) |line| { diff --git a/src/ir.cpp b/src/ir.cpp index b3b3198ce1..b3e24fed1f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12350,11 +12350,22 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT prev_type->data.pointer.child_type->id == ZigTypeIdArray && prev_type->data.pointer.ptr_len == PtrLenSingle && ((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) || - is_slice(cur_type))) + (cur_type->id == ZigTypeIdOptional && is_slice(cur_type->data.maybe.child_type)) || + is_slice(cur_type))) { ZigType *array_type = prev_type->data.pointer.child_type; - ZigType *slice_type = (cur_type->id == ZigTypeIdErrorUnion) ? - cur_type->data.error_union.payload_type : cur_type; + ZigType *slice_type; + switch (cur_type->id) { + case ZigTypeIdErrorUnion: + slice_type = cur_type->data.error_union.payload_type; + break; + case ZigTypeIdOptional: + slice_type = cur_type->data.maybe.child_type; + break; + default: + slice_type = cur_type; + break; + } ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || !prev_type->data.pointer.is_const) && diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index d58132cb08..f7d6037a1f 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -159,6 +159,7 @@ test "slice syntax resulting in pointer-to-array" { testSlice(); testSliceZ(); testSlice0(); + testSliceOpt(); testSliceAlign(); } @@ -249,6 +250,13 @@ test "slice syntax resulting in pointer-to-array" { comptime expect(@TypeOf(slice[1..3 :4]) == *[2:4]u8); } + fn testSliceOpt() void { + var array: [2]u8 = [2]u8{ 1, 2 }; + var slice: ?[]u8 = &array; + comptime expect(@TypeOf(&array, slice) == ?[]u8); + comptime expect(@TypeOf(slice.?[0..2]) == *[2]u8); + } + fn testSlice0() void { { var array = [0]u8{}; From 245dc9d930a4f11a7ce719d3b9aa272a6a1127ff Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 20 Mar 2020 12:59:37 -0400 Subject: [PATCH 57/79] include ld symbols when generating glibc dummy objects closes #4748 --- lib/libc/glibc/abi.txt | 135 +++++++++++++++++++++++++++++++++++++++++ lib/libc/glibc/fns.txt | 9 +++ tools/update_glibc.zig | 29 +++++---- 3 files changed, 160 insertions(+), 13 deletions(-) diff --git a/lib/libc/glibc/abi.txt b/lib/libc/glibc/abi.txt index 089b9c077e..4d8d6f5255 100644 --- a/lib/libc/glibc/abi.txt +++ b/lib/libc/glibc/abi.txt @@ -193,6 +193,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 + 29 29 @@ -514,6 +515,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 @@ -697,6 +699,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 + 29 29 29 @@ -819,6 +822,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 29 @@ -904,6 +908,9 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 + + 29 29 29 @@ -1004,6 +1011,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 29 @@ -1033,6 +1041,7 @@ aarch64-linux-gnu aarch64_be-linux-gnu 29 29 29 +29 29 29 @@ -3920,6 +3929,7 @@ s390x-linux-gnu 5 + 27 27 @@ -4241,6 +4251,7 @@ s390x-linux-gnu 5 5 5 +5 11 27 @@ -4424,6 +4435,7 @@ s390x-linux-gnu 19 19 5 + 5 5 28 @@ -4543,6 +4555,7 @@ s390x-linux-gnu 27 16 + 5 5 15 @@ -4631,6 +4644,9 @@ s390x-linux-gnu 16 5 5 + + +12 5 5 5 @@ -4731,6 +4747,7 @@ s390x-linux-gnu 5 5 5 +5 5 5 @@ -4756,6 +4773,7 @@ s390x-linux-gnu 5 5 5 +5 31 5 24 5 12 16 24 5 12 16 @@ -7645,6 +7663,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf + 27 @@ -7968,6 +7987,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 27 @@ -8151,6 +8171,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 19 19 16 + 16 16 28 @@ -8273,6 +8294,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 16 16 @@ -8358,6 +8380,9 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 + + 16 16 16 @@ -8458,6 +8483,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 16 16 @@ -8484,6 +8510,7 @@ arm-linux-gnueabi armeb-linux-gnueabi arm-linux-gnueabihf armeb-linux-gnueabihf 16 16 16 +16 24 16 24 16 16 @@ -11374,6 +11401,7 @@ sparc-linux-gnu sparcel-linux-gnu 0 + 27 27 @@ -11693,6 +11721,7 @@ sparc-linux-gnu sparcel-linux-gnu 0 0 1 +1 0 0 3 11 @@ -11878,6 +11907,7 @@ sparc-linux-gnu sparcel-linux-gnu 19 19 0 + 0 1 28 @@ -11997,6 +12027,7 @@ sparc-linux-gnu sparcel-linux-gnu 33 16 + 5 0 15 @@ -12085,6 +12116,9 @@ sparc-linux-gnu sparcel-linux-gnu 16 0 0 +12 + + 1 1 1 @@ -12183,6 +12217,7 @@ sparc-linux-gnu sparcel-linux-gnu 1 1 1 +1 0 0 @@ -12207,6 +12242,7 @@ sparc-linux-gnu sparcel-linux-gnu 0 0 0 +0 5 0 0 @@ -15101,6 +15137,7 @@ sparcv9-linux-gnu 5 5 + 27 27 @@ -15422,6 +15459,7 @@ sparcv9-linux-gnu 5 5 5 +5 11 27 @@ -15605,6 +15643,7 @@ sparcv9-linux-gnu 19 19 5 + 5 5 28 @@ -15724,6 +15763,7 @@ sparcv9-linux-gnu 27 16 + 5 5 15 @@ -15812,6 +15852,9 @@ sparcv9-linux-gnu 16 5 5 +12 + + 5 5 5 @@ -15912,6 +15955,7 @@ sparcv9-linux-gnu 5 5 5 +5 5 5 @@ -15938,6 +15982,7 @@ sparcv9-linux-gnu 5 5 5 +5 24 28 5 12 16 24 28 5 12 16 5 14 @@ -18828,6 +18873,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 0 + 27 27 @@ -19147,6 +19193,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 0 0 5 +5 0 0 11 @@ -19332,6 +19379,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 19 19 0 + 0 5 28 @@ -19450,6 +19498,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 27 27 +16 16 5 0 @@ -19539,6 +19588,9 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 16 0 0 +12 + + 5 5 5 @@ -19637,6 +19689,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 5 5 5 +5 0 0 0 @@ -19661,6 +19714,7 @@ mips64el-linux-gnuabi64 mips64-linux-gnuabi64 0 0 0 +0 5 0 0 @@ -22555,6 +22609,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 0 + 27 27 @@ -22874,6 +22929,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 0 0 5 +5 0 0 11 @@ -23059,6 +23115,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 19 19 0 + 0 5 28 @@ -23177,6 +23234,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 27 27 +16 16 5 0 @@ -23266,6 +23324,9 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 16 0 0 +12 + + 5 5 5 @@ -23364,6 +23425,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 5 5 5 +5 0 0 0 @@ -23388,6 +23450,7 @@ mips64el-linux-gnuabin32 mips64-linux-gnuabin32 0 0 0 +0 5 0 0 @@ -26282,6 +26345,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 0 + 27 27 @@ -26601,6 +26665,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 0 0 5 +5 0 0 11 @@ -26786,6 +26851,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 19 19 0 + 0 5 28 @@ -26904,6 +26970,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 27 +16 16 5 0 @@ -26993,6 +27060,9 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 16 0 0 +12 + + 5 5 5 @@ -27091,6 +27161,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 5 5 5 +5 0 0 0 @@ -27115,6 +27186,7 @@ mipsel-linux-gnueabihf mips-linux-gnueabihf 0 0 0 +0 5 0 0 @@ -30009,6 +30081,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 0 + 27 27 @@ -30328,6 +30401,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 0 0 5 +5 0 0 11 @@ -30513,6 +30587,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 19 19 0 + 0 5 28 @@ -30631,6 +30706,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 27 +16 16 5 0 @@ -30720,6 +30796,9 @@ mipsel-linux-gnueabi mips-linux-gnueabi 16 0 0 +12 + + 5 5 5 @@ -30818,6 +30897,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 5 5 5 +5 0 0 0 @@ -30842,6 +30922,7 @@ mipsel-linux-gnueabi mips-linux-gnueabi 0 0 0 +0 5 0 0 @@ -33734,6 +33815,7 @@ x86_64-linux-gnu + 27 @@ -34057,6 +34139,7 @@ x86_64-linux-gnu 10 10 10 +10 11 27 36 @@ -34240,6 +34323,7 @@ x86_64-linux-gnu 19 19 10 + 10 10 28 @@ -34359,6 +34443,7 @@ x86_64-linux-gnu 27 16 + 10 10 15 @@ -34447,6 +34532,9 @@ x86_64-linux-gnu 16 10 10 +12 + + 10 10 10 @@ -34547,6 +34635,7 @@ x86_64-linux-gnu 10 10 10 +10 10 10 @@ -34573,6 +34662,7 @@ x86_64-linux-gnu 10 10 10 +10 24 10 12 16 24 10 12 16 10 14 @@ -37461,6 +37551,7 @@ x86_64-linux-gnux32 + 28 @@ -37784,6 +37875,7 @@ x86_64-linux-gnux32 28 28 28 +28 28 36 @@ -37967,6 +38059,7 @@ x86_64-linux-gnux32 28 28 28 + 28 28 28 @@ -38086,6 +38179,7 @@ x86_64-linux-gnux32 28 28 + 28 28 28 @@ -38174,6 +38268,9 @@ x86_64-linux-gnux32 28 28 28 +28 + + 28 28 28 @@ -38274,6 +38371,7 @@ x86_64-linux-gnux32 28 28 28 +28 28 28 @@ -38303,6 +38401,7 @@ x86_64-linux-gnux32 28 28 28 +28 28 28 @@ -41190,6 +41289,7 @@ i386-linux-gnu 0 +12 27 36 27 @@ -41509,6 +41609,7 @@ i386-linux-gnu 0 0 1 +1 0 0 3 11 @@ -41694,6 +41795,7 @@ i386-linux-gnu 19 19 0 + 0 1 28 @@ -41813,6 +41915,7 @@ i386-linux-gnu 27 16 + 5 0 15 @@ -41901,6 +42004,9 @@ i386-linux-gnu 16 0 0 +12 + + 1 1 1 @@ -41999,6 +42105,7 @@ i386-linux-gnu 1 1 1 +1 0 0 @@ -42023,6 +42130,7 @@ i386-linux-gnu 0 0 0 +0 5 0 0 @@ -44915,6 +45023,7 @@ powerpc64le-linux-gnu + 29 @@ -45238,6 +45347,7 @@ powerpc64le-linux-gnu 29 29 29 +29 29 36 @@ -45421,6 +45531,7 @@ powerpc64le-linux-gnu 29 29 29 +33 29 29 29 @@ -45540,6 +45651,7 @@ powerpc64le-linux-gnu 29 29 + 29 29 29 @@ -45628,6 +45740,9 @@ powerpc64le-linux-gnu 29 29 29 +29 +32 + 29 29 29 @@ -45728,6 +45843,7 @@ powerpc64le-linux-gnu 29 29 29 +29 29 29 @@ -45757,6 +45873,7 @@ powerpc64le-linux-gnu 29 29 29 +29 29 29 @@ -48642,6 +48759,7 @@ powerpc64-linux-gnu + 27 @@ -48965,6 +49083,7 @@ powerpc64-linux-gnu 12 12 12 +12 27 @@ -49148,6 +49267,7 @@ powerpc64-linux-gnu 19 19 12 +33 12 12 28 @@ -49267,6 +49387,7 @@ powerpc64-linux-gnu 27 16 + 12 12 15 @@ -49355,6 +49476,9 @@ powerpc64-linux-gnu 16 12 12 +12 +32 + 12 12 12 @@ -49455,6 +49579,7 @@ powerpc64-linux-gnu 12 12 12 +12 12 12 @@ -49480,6 +49605,7 @@ powerpc64-linux-gnu 12 12 12 +12 12 15 24 12 16 24 12 16 @@ -52369,6 +52495,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf + 27 @@ -52690,6 +52817,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 0 0 1 +1 0 0 3 11 @@ -52875,6 +53003,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 19 19 0 +33 0 1 28 @@ -52994,6 +53123,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 27 13 16 + 5 0 15 @@ -53082,6 +53212,9 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 16 0 0 +12 +32 + 1 1 1 @@ -53180,6 +53313,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 1 1 1 +1 0 0 @@ -53204,6 +53338,7 @@ powerpc-linux-gnueabi powerpc-linux-gnueabihf 0 0 0 +0 5 0 0 diff --git a/lib/libc/glibc/fns.txt b/lib/libc/glibc/fns.txt index 32dc37ce17..4e2e126b0e 100644 --- a/lib/libc/glibc/fns.txt +++ b/lib/libc/glibc/fns.txt @@ -192,6 +192,7 @@ _Qp_uitoq c _Qp_uxtoq c _Qp_xtoq c ___brk_addr c +___tls_get_addr ld __acos_finite m __acosf128_finite m __acosf_finite m @@ -511,6 +512,7 @@ __libc_memalign c __libc_pvalloc c __libc_realloc c __libc_sa_len c +__libc_stack_end ld __libc_start_main c __libc_valloc c __libpthread_version_placeholder pthread @@ -696,6 +698,7 @@ __open_2 c __openat64_2 c __openat_2 c __overflow c +__parse_hwcap_and_convert_at_platform ld __pipe c __poll c __poll_chk c @@ -815,6 +818,7 @@ __sqrtf_finite m __sqrtl_finite m __sqrtsf2 c __stack_chk_fail c +__stack_chk_guard ld __statfs c __stpcpy c __stpcpy_chk c @@ -903,6 +907,9 @@ __sysctl c __syslog_chk c __sysv_signal c __timezone c +__tls_get_addr ld +__tls_get_addr_opt ld +__tls_get_offset ld __toascii_l c __tolower_l c __toupper_l c @@ -999,6 +1006,7 @@ __ynf128_finite m __ynf_finite m __ynl_finite m _authenticate c +_dl_mcount ld _dl_mcount_wrapper c _dl_mcount_wrapper_check c _environ c @@ -1024,6 +1032,7 @@ _pthread_cleanup_pop pthread _pthread_cleanup_pop_restore pthread _pthread_cleanup_push pthread _pthread_cleanup_push_defer pthread +_r_debug ld _res c _res_hconf c _rpc_dtablesize c diff --git a/tools/update_glibc.zig b/tools/update_glibc.zig index 84522aabe4..4a5b1751a2 100644 --- a/tools/update_glibc.zig +++ b/tools/update_glibc.zig @@ -20,6 +20,7 @@ const lib_names = [_][]const u8{ "m", "pthread", "rt", + "ld", }; // fpu/nofpu are hardcoded elsewhere, based on .gnueabi/.gnueabihf with an exception for .arm @@ -154,22 +155,24 @@ pub fn main() !void { const fn_set = &target_funcs_gop.kv.value.list; for (lib_names) |lib_name, lib_name_index| { - const basename = try fmt.allocPrint(allocator, "lib{}.abilist", .{lib_name}); + const lib_prefix = if (std.mem.eql(u8, lib_name, "ld")) "" else "lib"; + const basename = try fmt.allocPrint(allocator, "{}{}.abilist", .{ lib_prefix, lib_name }); const abi_list_filename = blk: { - if (abi_list.targets[0].abi == .gnuabi64 and std.mem.eql(u8, lib_name, "c")) { + const is_c = std.mem.eql(u8, lib_name, "c"); + const is_m = std.mem.eql(u8, lib_name, "m"); + const is_ld = std.mem.eql(u8, lib_name, "ld"); + if (abi_list.targets[0].abi == .gnuabi64 and (is_c or is_ld)) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "n64", basename }); - } else if (abi_list.targets[0].abi == .gnuabin32 and std.mem.eql(u8, lib_name, "c")) { + } else if (abi_list.targets[0].abi == .gnuabin32 and (is_c or is_ld)) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "n32", basename }); } else if (abi_list.targets[0].arch != .arm and abi_list.targets[0].abi == .gnueabihf and - (std.mem.eql(u8, lib_name, "c") or - (std.mem.eql(u8, lib_name, "m") and abi_list.targets[0].arch == .powerpc))) + (is_c or (is_m and abi_list.targets[0].arch == .powerpc))) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "fpu", basename }); } else if (abi_list.targets[0].arch != .arm and abi_list.targets[0].abi == .gnueabi and - (std.mem.eql(u8, lib_name, "c") or - (std.mem.eql(u8, lib_name, "m") and abi_list.targets[0].arch == .powerpc))) + (is_c or (is_m and abi_list.targets[0].arch == .powerpc))) { break :blk try fs.path.join(allocator, &[_][]const u8{ prefix, abi_list.path, "nofpu", basename }); } else if (abi_list.targets[0].arch == .arm) { @@ -234,8 +237,8 @@ pub fn main() !void { const vers_txt_path = try fs.path.join(allocator, &[_][]const u8{ glibc_out_dir, "vers.txt" }); const vers_txt_file = try fs.cwd().createFile(vers_txt_path, .{}); defer vers_txt_file.close(); - var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&vers_txt_file.outStream().stream); - const vers_txt = &buffered.stream; + var buffered = std.io.bufferedOutStream(vers_txt_file.outStream()); + const vers_txt = buffered.outStream(); for (global_ver_list) |name, i| { _ = global_ver_set.put(name, i) catch unreachable; try vers_txt.print("{}\n", .{name}); @@ -246,8 +249,8 @@ pub fn main() !void { const fns_txt_path = try fs.path.join(allocator, &[_][]const u8{ glibc_out_dir, "fns.txt" }); const fns_txt_file = try fs.cwd().createFile(fns_txt_path, .{}); defer fns_txt_file.close(); - var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&fns_txt_file.outStream().stream); - const fns_txt = &buffered.stream; + var buffered = std.io.bufferedOutStream(fns_txt_file.outStream()); + const fns_txt = buffered.outStream(); for (global_fn_list) |name, i| { const kv = global_fn_set.get(name).?; kv.value.index = i; @@ -277,8 +280,8 @@ pub fn main() !void { const abilist_txt_path = try fs.path.join(allocator, &[_][]const u8{ glibc_out_dir, "abi.txt" }); const abilist_txt_file = try fs.cwd().createFile(abilist_txt_path, .{}); defer abilist_txt_file.close(); - var buffered = std.io.BufferedOutStream(fs.File.WriteError).init(&abilist_txt_file.outStream().stream); - const abilist_txt = &buffered.stream; + var buffered = std.io.bufferedOutStream(abilist_txt_file.outStream()); + const abilist_txt = buffered.outStream(); // first iterate over the abi lists for (abi_lists) |*abi_list, abi_index| { From 7438d0fc31f70b3a6d19e1da9a4e3f7918fc9d66 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 20 Mar 2020 14:39:05 -0400 Subject: [PATCH 58/79] glibc: include ld symbols and proper soname for ld --- src-self-hosted/stage2.zig | 8 ++++++++ src/all_types.hpp | 1 + src/codegen.cpp | 1 + src/glibc.cpp | 10 ++++++++++ src/link.cpp | 8 ++++---- src/stage2.h | 1 + 6 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index a1d741bc9b..78aa278005 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -909,6 +909,7 @@ const Stage2Target = extern struct { os_builtin_str: ?[*:0]const u8, dynamic_linker: ?[*:0]const u8, + standard_dynamic_linker_path: ?[*:0]const u8, fn fromTarget(self: *Stage2Target, cross_target: CrossTarget) !void { const allocator = std.heap.c_allocator; @@ -1119,6 +1120,12 @@ const Stage2Target = extern struct { } }; + const std_dl = target.standardDynamicLinkerPath(); + const std_dl_z = if (std_dl.get()) |dl| + (try mem.dupeZ(std.heap.c_allocator, u8, dl)).ptr + else + null; + const cache_hash_slice = cache_hash.toOwnedSlice(); self.* = .{ .arch = @enumToInt(target.cpu.arch) + 1, // skip over ZigLLVM_UnknownArch @@ -1134,6 +1141,7 @@ const Stage2Target = extern struct { .is_native = cross_target.isNative(), .glibc_or_darwin_version = glibc_or_darwin_version, .dynamic_linker = dynamic_linker, + .standard_dynamic_linker_path = std_dl_z, }; } }; diff --git a/src/all_types.hpp b/src/all_types.hpp index 6719d78a92..3f143b35c1 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2267,6 +2267,7 @@ struct CodeGen { Buf *zig_lib_dir; Buf *zig_std_dir; Buf *version_script_path; + Buf *override_soname; const char **llvm_argv; size_t llvm_argv_len; diff --git a/src/codegen.cpp b/src/codegen.cpp index 8fae16e551..c2ce2ac3eb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -10510,6 +10510,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_str(ch, g->libc->kernel32_lib_dir); } cache_buf_opt(ch, g->version_script_path); + cache_buf_opt(ch, g->override_soname); // gen_c_objects appends objects to g->link_objects which we want to include in the hash gen_c_objects(g); diff --git a/src/glibc.cpp b/src/glibc.cpp index da5c1d5290..75b77ec122 100644 --- a/src/glibc.cpp +++ b/src/glibc.cpp @@ -16,6 +16,7 @@ static const ZigGLibCLib glibc_libs[] = { {"pthread", 0}, {"dl", 2}, {"rt", 1}, + {"ld", 2}, }; Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose) { @@ -330,6 +331,8 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con return err; } + bool is_ld = (strcmp(lib->name, "ld") == 0); + CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr, lib->name, progress_node); codegen_set_lib_version(child_gen, lib->sover, 0, 0); child_gen->is_dynamic = true; @@ -337,6 +340,13 @@ Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, con child_gen->version_script_path = map_file_path; child_gen->enable_cache = false; child_gen->output_dir = dummy_dir; + if (is_ld) { + assert(g->zig_target->standard_dynamic_linker_path != nullptr); + Buf *ld_basename = buf_alloc(); + os_path_split(buf_create_from_str(g->zig_target->standard_dynamic_linker_path), + nullptr, ld_basename); + child_gen->override_soname = ld_basename; + } codegen_build_and_link(child_gen); } diff --git a/src/link.cpp b/src/link.cpp index 3f7772bb08..0ae47c8432 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -1651,7 +1651,6 @@ static void construct_linker_job_elf(LinkJob *lj) { bool is_lib = g->out_type == OutTypeLib; bool is_dyn_lib = g->is_dynamic && is_lib; - Buf *soname = nullptr; if (!g->have_dynamic_link) { if (g->zig_target->arch == ZigLLVM_arm || g->zig_target->arch == ZigLLVM_armeb || g->zig_target->arch == ZigLLVM_thumb || g->zig_target->arch == ZigLLVM_thumbeb) @@ -1662,15 +1661,13 @@ static void construct_linker_job_elf(LinkJob *lj) { } } else if (is_dyn_lib) { lj->args.append("-shared"); - - assert(buf_len(&g->bin_file_output_path) != 0); - soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major); } if (target_requires_pie(g->zig_target) && g->out_type == OutTypeExe) { lj->args.append("-pie"); } + assert(buf_len(&g->bin_file_output_path) != 0); lj->args.append("-o"); lj->args.append(buf_ptr(&g->bin_file_output_path)); @@ -1740,6 +1737,9 @@ static void construct_linker_job_elf(LinkJob *lj) { } if (is_dyn_lib) { + Buf *soname = (g->override_soname == nullptr) ? + buf_sprintf("lib%s.so.%" ZIG_PRI_usize, buf_ptr(g->root_out_name), g->version_major) : + g->override_soname; lj->args.append("-soname"); lj->args.append(buf_ptr(soname)); diff --git a/src/stage2.h b/src/stage2.h index 24fd664b3c..9ba7e062b1 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -291,6 +291,7 @@ struct ZigTarget { size_t cache_hash_len; const char *os_builtin_str; const char *dynamic_linker; + const char *standard_dynamic_linker_path; }; // ABI warning From 3a2c4908891cdc9f64f0e94eb570ce084f8bc57c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 20 Mar 2020 18:33:36 -0400 Subject: [PATCH 59/79] "generate .h files" feature is no longer supported in stage1 --- CMakeLists.txt | 1 - build.zig | 3 ++- lib/std/build.zig | 18 ++++++++---------- lib/std/start.zig | 4 ++++ src/main.cpp | 16 ++++++++++------ test/standalone/mix_o_files/test.c | 8 +++++--- test/standalone/shared_library/test.c | 8 +++++++- 7 files changed, 36 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a3d6a7fb68..6f2a88d34b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -622,7 +622,6 @@ set(BUILD_LIBSTAGE2_ARGS "build-lib" --cache on --output-dir "${CMAKE_BINARY_DIR}" ${LIBSTAGE2_RELEASE_ARG} - --disable-gen-h --bundle-compiler-rt -fPIC -lc diff --git a/build.zig b/build.zig index 6a41e6ef64..f8b41f2dc4 100644 --- a/build.zig +++ b/build.zig @@ -134,7 +134,8 @@ pub fn build(b: *Builder) !void { test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes)); test_step.dependOn(tests.addTranslateCTests(b, test_filter)); test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter)); - test_step.dependOn(tests.addGenHTests(b, test_filter)); + // tests for this feature are disabled until we have the self-hosted compiler available + //test_step.dependOn(tests.addGenHTests(b, test_filter)); test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes)); test_step.dependOn(docs_step); } diff --git a/lib/std/build.zig b/lib/std/build.zig index 09c77168d6..ac411d6cf6 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1121,7 +1121,7 @@ pub const LibExeObjStep = struct { emit_llvm_ir: bool = false, emit_asm: bool = false, emit_bin: bool = true, - disable_gen_h: bool, + emit_h: bool = false, bundle_compiler_rt: bool, disable_stack_probing: bool, disable_sanitize_c: bool, @@ -1281,7 +1281,6 @@ pub const LibExeObjStep = struct { .exec_cmd_args = null, .name_prefix = "", .filter = null, - .disable_gen_h = false, .bundle_compiler_rt = false, .disable_stack_probing = false, .disable_sanitize_c = false, @@ -1600,8 +1599,9 @@ pub const LibExeObjStep = struct { self.main_pkg_path = dir_path; } - pub fn setDisableGenH(self: *LibExeObjStep, value: bool) void { - self.disable_gen_h = value; + /// Deprecated; just set the field directly. + pub fn setDisableGenH(self: *LibExeObjStep, is_disabled: bool) void { + self.emit_h = !is_disabled; } pub fn setLibCFile(self: *LibExeObjStep, libc_file: ?[]const u8) void { @@ -1632,7 +1632,7 @@ pub const LibExeObjStep = struct { /// the make step, from a step that has declared a dependency on this one. pub fn getOutputHPath(self: *LibExeObjStep) []const u8 { assert(self.kind != Kind.Exe); - assert(!self.disable_gen_h); + assert(self.emit_h); return fs.path.join( self.builder.allocator, &[_][]const u8{ self.output_dir.?, self.out_h_filename }, @@ -1884,6 +1884,7 @@ pub const LibExeObjStep = struct { if (self.emit_llvm_ir) try zig_args.append("-femit-llvm-ir"); if (self.emit_asm) try zig_args.append("-femit-asm"); if (!self.emit_bin) try zig_args.append("-fno-emit-bin"); + if (self.emit_h) try zig_args.append("-femit-h"); if (self.strip) { try zig_args.append("--strip"); @@ -1929,9 +1930,6 @@ pub const LibExeObjStep = struct { if (self.is_dynamic) { try zig_args.append("-dynamic"); } - if (self.disable_gen_h) { - try zig_args.append("--disable-gen-h"); - } if (self.bundle_compiler_rt) { try zig_args.append("--bundle-compiler-rt"); } @@ -2069,7 +2067,7 @@ pub const LibExeObjStep = struct { try zig_args.append("-isystem"); try zig_args.append(self.builder.pathFromRoot(include_path)); }, - .OtherStep => |other| if (!other.disable_gen_h) { + .OtherStep => |other| if (other.emit_h) { const h_path = other.getOutputHPath(); try zig_args.append("-isystem"); try zig_args.append(fs.path.dirname(h_path).?); @@ -2209,7 +2207,7 @@ const InstallArtifactStep = struct { break :blk InstallDir.Lib; } } else null, - .h_dir = if (artifact.kind == .Lib and !artifact.disable_gen_h) .Header else null, + .h_dir = if (artifact.kind == .Lib and artifact.emit_h) .Header else null, }; self.step.dependOn(&artifact.step); artifact.install_step = self; diff --git a/lib/std/start.zig b/lib/std/start.zig index 857af03b56..1a4997edbd 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -41,6 +41,10 @@ fn _DllMainCRTStartup( fdwReason: std.os.windows.DWORD, lpReserved: std.os.windows.LPVOID, ) callconv(.Stdcall) std.os.windows.BOOL { + if (!builtin.single_threaded) { + _ = @import("start_windows_tls.zig"); + } + if (@hasDecl(root, "DllMain")) { return root.DllMain(hinstDLL, fdwReason, lpReserved); } diff --git a/src/main.cpp b/src/main.cpp index 06d132da8b..76d6eadb14 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -54,7 +54,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --cache-dir [path] override the local cache directory\n" " --cache [auto|off|on] build in cache, print output path to stdout\n" " --color [auto|off|on] enable or disable colored error messages\n" - " --disable-gen-h do not generate a C header file (.h)\n" " --disable-valgrind omit valgrind client requests in debug builds\n" " --eh-frame-hdr enable C++ exception handling by passing --eh-frame-hdr to linker\n" " --enable-valgrind include valgrind client requests release builds\n" @@ -77,6 +76,8 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -fno-emit-asm (default) do not output .s (assembly code)\n" " -femit-llvm-ir produce a .ll file with LLVM IR\n" " -fno-emit-llvm-ir (default) do not produce a .ll file with LLVM IR\n" + " -femit-h generate a C header file (.h)\n" + " -fno-emit-h (default) do not generate a C header file (.h)\n" " --libc [file] Provide a file which specifies libc paths\n" " --name [name] override output name\n" " --output-dir [dir] override output directory (defaults to cwd)\n" @@ -431,6 +432,7 @@ static int main0(int argc, char **argv) { bool emit_bin = true; bool emit_asm = false; bool emit_llvm_ir = false; + bool emit_h = false; const char *cache_dir = nullptr; CliPkg *cur_pkg = heap::c_allocator.create(); BuildMode build_mode = BuildModeDebug; @@ -439,7 +441,6 @@ static int main0(int argc, char **argv) { bool system_linker_hack = false; TargetSubsystem subsystem = TargetSubsystemAuto; bool want_single_threaded = false; - bool disable_gen_h = false; bool bundle_compiler_rt = false; Buf *override_lib_dir = nullptr; Buf *main_pkg_path = nullptr; @@ -660,9 +661,7 @@ static int main0(int argc, char **argv) { } else if (strcmp(arg, "--system-linker-hack") == 0) { system_linker_hack = true; } else if (strcmp(arg, "--single-threaded") == 0) { - want_single_threaded = true; - } else if (strcmp(arg, "--disable-gen-h") == 0) { - disable_gen_h = true; + want_single_threaded = true;; } else if (strcmp(arg, "--bundle-compiler-rt") == 0) { bundle_compiler_rt = true; } else if (strcmp(arg, "--test-cmd-bin") == 0) { @@ -719,6 +718,11 @@ static int main0(int argc, char **argv) { emit_llvm_ir = true; } else if (strcmp(arg, "-fno-emit-llvm-ir") == 0) { emit_llvm_ir = false; + } else if (strcmp(arg, "-femit-h") == 0) { + emit_h = true; + } else if (strcmp(arg, "-fno-emit-h") == 0 || strcmp(arg, "--disable-gen-h") == 0) { + // the --disable-gen-h is there to support godbolt. once they upgrade to -fno-emit-h then we can remove this + emit_h = false; } else if (str_starts_with(arg, "-mcpu=")) { mcpu = arg + strlen("-mcpu="); } else if (i + 1 >= argc) { @@ -1202,7 +1206,7 @@ static int main0(int argc, char **argv) { g->verbose_cc = verbose_cc; g->verbose_llvm_cpu_features = verbose_llvm_cpu_features; g->output_dir = output_dir; - g->disable_gen_h = disable_gen_h; + g->disable_gen_h = !emit_h; g->bundle_compiler_rt = bundle_compiler_rt; codegen_set_errmsg_color(g, color); g->system_linker_hack = system_linker_hack; diff --git a/test/standalone/mix_o_files/test.c b/test/standalone/mix_o_files/test.c index 7f9f751a4a..e5e77a8f3e 100644 --- a/test/standalone/mix_o_files/test.c +++ b/test/standalone/mix_o_files/test.c @@ -1,10 +1,12 @@ -// This header is generated by zig from base64.zig -#include "base64.h" - #include #include #include +// TODO we would like to #include "base64.h" here but this feature has been disabled in +// the stage1 compiler. Users will have to wait until self-hosted is available for +// the "generate .h file" feature. +size_t decode_base_64(uint8_t *dest_ptr, size_t dest_len, const uint8_t *source_ptr, size_t source_len); + extern int *x_ptr; int main(int argc, char **argv) { diff --git a/test/standalone/shared_library/test.c b/test/standalone/shared_library/test.c index b60a6a5a75..f178f78b45 100644 --- a/test/standalone/shared_library/test.c +++ b/test/standalone/shared_library/test.c @@ -1,6 +1,12 @@ -#include "mathtest.h" #include +// TODO we would like to #include "mathtest.h" here but this feature has been disabled in +// the stage1 compiler. Users will have to wait until self-hosted is available for +// the "generate .h file" feature. + +#include +int32_t add(int32_t a, int32_t b); + int main(int argc, char **argv) { assert(add(42, 1337) == 1379); return 0; From 153c6cf92e3459038c4ab8251a463163ac89b116 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 20 Mar 2020 21:33:37 -0400 Subject: [PATCH 60/79] ci: disable test-gen-h on sr.ht and drone --- ci/drone/linux_script | 3 ++- ci/srht/freebsd_script | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ci/drone/linux_script b/ci/drone/linux_script index 61a5908dee..a0d2406f89 100755 --- a/ci/drone/linux_script +++ b/ci/drone/linux_script @@ -26,7 +26,8 @@ make -j$(nproc) install # TODO test-cli is hitting https://github.com/ziglang/zig/issues/3526 ./zig build test-asm-link test-runtime-safety # TODO test-translate-c is hitting https://github.com/ziglang/zig/issues/3526 -./zig build test-gen-h +# TODO disabled until we are shipping self-hosted +#./zig build test-gen-h # TODO test-compile-errors is hitting https://github.com/ziglang/zig/issues/3526 # TODO building docs is hitting https://github.com/ziglang/zig/issues/3526 diff --git a/ci/srht/freebsd_script b/ci/srht/freebsd_script index 12cd2d5406..6cf4cb7582 100755 --- a/ci/srht/freebsd_script +++ b/ci/srht/freebsd_script @@ -42,7 +42,8 @@ release/bin/zig build test-asm-link release/bin/zig build test-runtime-safety release/bin/zig build test-translate-c release/bin/zig build test-run-translated-c -release/bin/zig build test-gen-h +# TODO disabled until we are shipping self-hosted +#release/bin/zig build test-gen-h release/bin/zig build test-compile-errors release/bin/zig build docs From 128e70ff3a056e5b800c624f7157b00fd624509b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 19 Mar 2020 21:03:38 +0100 Subject: [PATCH 61/79] ir: Allow errdefer with payload Closes #1265 --- lib/std/zig/ast.zig | 7 +-- lib/std/zig/parse.zig | 7 ++- lib/std/zig/parser_test.zig | 13 ++++ lib/std/zig/render.zig | 3 + src/all_types.hpp | 1 + src/ir.cpp | 105 ++++++++++++++++++++++++--------- src/parser.cpp | 11 +++- test/stage1/behavior/defer.zig | 23 +++++++- 8 files changed, 135 insertions(+), 35 deletions(-) diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 8caaad2d4f..5445d3435f 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1032,6 +1032,7 @@ pub const Node = struct { pub const Defer = struct { base: Node = Node{ .id = .Defer }, defer_token: TokenIndex, + payload: ?*Node, expr: *Node, pub fn iterate(self: *Defer, index: usize) ?*Node { @@ -1833,8 +1834,7 @@ pub const Node = struct { var i = index; switch (self.kind) { - .Break, - .Continue => |maybe_label| { + .Break, .Continue => |maybe_label| { if (maybe_label) |label| { if (i < 1) return label; i -= 1; @@ -1861,8 +1861,7 @@ pub const Node = struct { } switch (self.kind) { - .Break, - .Continue => |maybe_label| { + .Break, .Continue => |maybe_label| { if (maybe_label) |label| { return label.lastToken(); } diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index b0c3e6d759..2fcaaaab2d 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -465,7 +465,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No /// / KEYWORD_noasync BlockExprStatement /// / KEYWORD_suspend (SEMICOLON / BlockExprStatement) /// / KEYWORD_defer BlockExprStatement -/// / KEYWORD_errdefer BlockExprStatement +/// / KEYWORD_errdefer Payload? BlockExprStatement /// / IfStatement /// / LabeledStatement /// / SwitchExpr @@ -526,6 +526,10 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No const defer_token = eatToken(it, .Keyword_defer) orelse eatToken(it, .Keyword_errdefer); if (defer_token) |token| { + const payload = if (tree.tokens.at(token).id == .Keyword_errdefer) + try parsePayload(arena, it, tree) + else + null; const expr_node = try expectNode(arena, it, tree, parseBlockExprStatement, .{ .ExpectedBlockOrExpression = .{ .token = it.index }, }); @@ -533,6 +537,7 @@ fn parseStatement(arena: *Allocator, it: *TokenIterator, tree: *Tree) Error!?*No node.* = .{ .defer_token = token, .expr = expr_node, + .payload = payload, }; return &node.base; } diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index e1fe07a57c..b71a78221f 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1,3 +1,16 @@ +test "zig fmt: noasync block" { + try testCanonical( + \\pub fn main() anyerror!void { + \\ errdefer |a| x += 1; + \\ errdefer |a| {} + \\ errdefer |a| { + \\ x += 1; + \\ } + \\} + \\ + ); +} + test "zig fmt: noasync block" { try testCanonical( \\pub fn main() anyerror!void { diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 23dc9e02ac..37d058bebf 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -376,6 +376,9 @@ fn renderExpression( const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base); try renderToken(tree, stream, defer_node.defer_token, indent, start_col, Space.Space); + if (defer_node.payload) |payload| { + try renderExpression(allocator, stream, tree, indent, start_col, payload, Space.Space); + } return renderExpression(allocator, stream, tree, indent, start_col, defer_node.expr, space); }, .Comptime => { diff --git a/src/all_types.hpp b/src/all_types.hpp index 3f143b35c1..b1450f08da 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -744,6 +744,7 @@ struct AstNodeReturnExpr { struct AstNodeDefer { ReturnKind kind; + AstNode *err_payload; AstNode *expr; // temporary data used in IR generation diff --git a/src/ir.cpp b/src/ir.cpp index b3e24fed1f..531c1b2432 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -272,6 +272,10 @@ static ResultLoc *no_result_loc(void); static IrInstGen *ir_analyze_test_non_null(IrAnalyze *ira, IrInst *source_inst, IrInstGen *value); static IrInstGen *ir_error_dependency_loop(IrAnalyze *ira, IrInst *source_instr); static IrInstGen *ir_const_undef(IrAnalyze *ira, IrInst *source_instruction, ZigType *ty); +static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, + bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime); +static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, + IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime); static void destroy_instruction_src(IrInstSrc *inst) { switch (inst->id) { @@ -5011,39 +5015,73 @@ static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) { return instruction; } -static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) { +static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) { Scope *scope = inner_scope; - bool is_noreturn = false; + if (is_noreturn != nullptr) *is_noreturn = false; while (scope != outer_scope) { if (!scope) - return is_noreturn; + return true; switch (scope->id) { case ScopeIdDefer: { AstNode *defer_node = scope->source_node; assert(defer_node->type == NodeTypeDefer); ReturnKind defer_kind = defer_node->data.defer.kind; - if (defer_kind == ReturnKindUnconditional || - (gen_error_defers && defer_kind == ReturnKindError)) - { - AstNode *defer_expr_node = defer_node->data.defer.expr; - Scope *defer_expr_scope = defer_node->data.defer.expr_scope; - IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); - if (defer_expr_value != irb->codegen->invalid_inst_src) { - if (defer_expr_value->is_noreturn) { - is_noreturn = true; - } else { - ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, - defer_expr_value)); - } + AstNode *defer_expr_node = defer_node->data.defer.expr; + AstNode *defer_var_node = defer_node->data.defer.err_payload; + + if (defer_kind == ReturnKindError && err_value == nullptr) { + // This is an `errdefer` but we're generating code for a + // `return` that doesn't return an error, skip it + scope = scope->parent; + continue; + } + + Scope *defer_expr_scope = defer_node->data.defer.expr_scope; + if (defer_var_node != nullptr) { + assert(defer_kind == ReturnKindError); + assert(defer_var_node->type == NodeTypeSymbol); + Buf *var_name = defer_var_node->data.symbol_expr.symbol; + + if (defer_expr_node->type == NodeTypeUnreachable) { + add_node_error(irb->codegen, defer_var_node, + buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); + return false; } + + IrInstSrc *is_comptime; + if (ir_should_inline(irb->exec, defer_expr_scope)) { + is_comptime = ir_build_const_bool(irb, defer_expr_scope, + defer_expr_node, true); + } else { + is_comptime = ir_build_test_comptime(irb, defer_expr_scope, + defer_expr_node, err_value); + } + + ZigVar *err_var = ir_create_var(irb, defer_var_node, defer_expr_scope, + var_name, true, true, false, is_comptime); + build_decl_var_and_init(irb, defer_expr_scope, defer_var_node, err_var, err_value, + buf_ptr(var_name), is_comptime); + + defer_expr_scope = err_var->child_scope; + } + + IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); + if (defer_expr_value == irb->codegen->invalid_inst_src) + return irb->codegen->invalid_inst_src; + + if (defer_expr_value->is_noreturn) { + if (is_noreturn != nullptr) *is_noreturn = true; + } else { + ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, + defer_expr_value)); } scope = scope->parent; continue; } case ScopeIdDecls: case ScopeIdFnDef: - return is_noreturn; + return true; case ScopeIdBlock: case ScopeIdVarDecl: case ScopeIdLoop: @@ -5060,7 +5098,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope zig_unreachable(); } } - return is_noreturn; + return true; } static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { @@ -5146,7 +5184,8 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, bool have_err_defers = defer_counts[ReturnKindError] > 0; if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { // only generate unconditional defers - ir_gen_defers_for_block(irb, scope, outer_scope, false); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); result_loc_ret->base.source_instruction = result; return result; @@ -5169,14 +5208,16 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); ir_set_cursor_at_end_and_append_block(irb, err_block); - ir_gen_defers_for_block(irb, scope, outer_scope, true); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, return_value)) + return irb->codegen->invalid_inst_src; if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr_src(irb, scope, node); } ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ok_block); - ir_gen_defers_for_block(irb, scope, outer_scope, false); + if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); @@ -5213,7 +5254,12 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, result_loc_ret->base.id = ResultLocIdReturn; ir_build_reset_result(irb, scope, node, &result_loc_ret->base); ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); - if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) { + + bool is_noreturn = false; + if (!ir_gen_defers_for_block(irb, scope, outer_scope, &is_noreturn, err_val)) { + return irb->codegen->invalid_inst_src; + } + if (!is_noreturn) { if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr_src(irb, scope, node); } @@ -5415,7 +5461,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * bool is_return_from_fn = block_node == irb->main_block_node; if (!is_return_from_fn) { - ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); + if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; } IrInstSrc *result; @@ -5440,7 +5487,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * result_loc_ret->base.id = ResultLocIdReturn; ir_build_reset_result(irb, parent_scope, block_node, &result_loc_ret->base); ir_mark_gen(ir_build_end_expr(irb, parent_scope, block_node, result, &result_loc_ret->base)); - ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); + if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; return ir_mark_gen(ir_build_return_src(irb, child_scope, result->base.source_node, result)); } @@ -9240,7 +9288,8 @@ static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope } IrBasicBlockSrc *dest_block = block_scope->end_block; - ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); + if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; block_scope->incoming_blocks->append(irb->current_basic_block); block_scope->incoming_values->append(result_value); @@ -9314,7 +9363,8 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n } IrBasicBlockSrc *dest_block = loop_scope->break_block; - ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); + if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; loop_scope->incoming_blocks->append(irb->current_basic_block); loop_scope->incoming_values->append(result_value); @@ -9373,7 +9423,8 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN } IrBasicBlockSrc *dest_block = loop_scope->continue_block; - ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false); + if (!ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, nullptr, nullptr)) + return irb->codegen->invalid_inst_src; return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); } diff --git a/src/parser.cpp b/src/parser.cpp index cdd254962e..20ad179a75 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -879,7 +879,7 @@ static AstNode *ast_parse_container_field(ParseContext *pc) { // / KEYWORD_noasync BlockExprStatement // / KEYWORD_suspend (SEMICOLON / BlockExprStatement) // / KEYWORD_defer BlockExprStatement -// / KEYWORD_errdefer BlockExprStatement +// / KEYWORD_errdefer Payload? BlockExprStatement // / IfStatement // / LabeledStatement // / SwitchExpr @@ -923,12 +923,18 @@ static AstNode *ast_parse_statement(ParseContext *pc) { if (defer == nullptr) defer = eat_token_if(pc, TokenIdKeywordErrdefer); if (defer != nullptr) { + Token *payload = (defer->id == TokenIdKeywordErrdefer) ? + ast_parse_payload(pc) : nullptr; AstNode *statement = ast_expect(pc, ast_parse_block_expr_statement); AstNode *res = ast_create_node(pc, NodeTypeDefer, defer); + res->data.defer.kind = ReturnKindUnconditional; res->data.defer.expr = statement; - if (defer->id == TokenIdKeywordErrdefer) + if (defer->id == TokenIdKeywordErrdefer) { res->data.defer.kind = ReturnKindError; + if (payload != nullptr) + res->data.defer.err_payload = token_symbol(pc, payload); + } return res; } @@ -3032,6 +3038,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont break; case NodeTypeDefer: visit_field(&node->data.defer.expr, visit, context); + visit_field(&node->data.defer.err_payload, visit, context); break; case NodeTypeVariableDeclaration: visit_field(&node->data.variable_declaration.type, visit, context); diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig index 5a643609fd..7cefafa9a0 100644 --- a/test/stage1/behavior/defer.zig +++ b/test/stage1/behavior/defer.zig @@ -1,4 +1,6 @@ -const expect = @import("std").testing.expect; +const std = @import("std"); +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; var result: [3]u8 = undefined; var index: usize = undefined; @@ -93,3 +95,22 @@ test "return variable while defer expression in scope to modify it" { S.doTheTest(); comptime S.doTheTest(); } + +test "errdefer with payload" { + const S = struct { + fn foo() !i32 { + errdefer |a| { + expectEqual(error.One, a); + } + return error.One; + } + fn doTheTest() void { + _ = foo() catch |err| switch (err) { + error.One => {}, + else => unreachable, + }; + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} From 28dbc5883763fb2b87ef8d186a57c3971d3414bc Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 20 Mar 2020 22:23:51 +0100 Subject: [PATCH 62/79] Address review comments --- lib/std/zig/parser_test.zig | 2 +- test/compile_errors.zig | 12 ++++++++++++ test/stage1/behavior/defer.zig | 6 ++---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index b71a78221f..894f726fb1 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1,4 +1,4 @@ -test "zig fmt: noasync block" { +test "zig fmt: errdefer with payload" { try testCanonical( \\pub fn main() anyerror!void { \\ errdefer |a| x += 1; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index e3e1462173..d2e298032f 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,18 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("unused variable error on errdefer", + \\fn foo() !void { + \\ errdefer |a| unreachable; + \\ return error.A; + \\} + \\export fn entry() void { + \\ foo() catch unreachable; + \\} + , &[_][]const u8{ + "tmp.zig:2:15: error: unused variable: 'a'", + }); + cases.addTest("shift on type with non-power-of-two size", \\export fn entry() void { \\ const S = struct { diff --git a/test/stage1/behavior/defer.zig b/test/stage1/behavior/defer.zig index 7cefafa9a0..6bfeb485cc 100644 --- a/test/stage1/behavior/defer.zig +++ b/test/stage1/behavior/defer.zig @@ -1,6 +1,7 @@ const std = @import("std"); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; +const expectError = std.testing.expectError; var result: [3]u8 = undefined; var index: usize = undefined; @@ -105,10 +106,7 @@ test "errdefer with payload" { return error.One; } fn doTheTest() void { - _ = foo() catch |err| switch (err) { - error.One => {}, - else => unreachable, - }; + expectError(error.One, foo()); } }; S.doTheTest(); From a4eaeee72011a2f7866a18420812178991feaf8d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 21 Mar 2020 10:12:28 -0400 Subject: [PATCH 63/79] ability to use `zig cc` as a drop-in C compiler The basics are working --- src-self-hosted/clang_options.zig | 126 + src-self-hosted/clang_options_data.zig | 5632 ++++++++++++++++++++++++ src-self-hosted/stage2.zig | 155 + src/codegen.cpp | 2 +- src/error.cpp | 1 + src/link.cpp | 2 +- src/main.cpp | 56 +- src/stage2.cpp | 12 + src/stage2.h | 31 + tools/process_headers.zig | 22 +- tools/update_clang_options.zig | 274 ++ 11 files changed, 6295 insertions(+), 18 deletions(-) create mode 100644 src-self-hosted/clang_options.zig create mode 100644 src-self-hosted/clang_options_data.zig create mode 100644 tools/update_clang_options.zig diff --git a/src-self-hosted/clang_options.zig b/src-self-hosted/clang_options.zig new file mode 100644 index 0000000000..9fa35b8f9a --- /dev/null +++ b/src-self-hosted/clang_options.zig @@ -0,0 +1,126 @@ +const std = @import("std"); +const mem = std.mem; + +pub const list = @import("clang_options_data.zig").data; + +pub const CliArg = struct { + name: []const u8, + syntax: Syntax, + + /// TODO we're going to want to change this when we start shipping self-hosted because this causes + /// all the functions in stage2.zig to get exported. + zig_equivalent: @import("stage2.zig").ClangArgIterator.ZigEquivalent, + + /// Prefixed by "-" + pd1: bool = false, + + /// Prefixed by "--" + pd2: bool = false, + + /// Prefixed by "/" + psl: bool = false, + + const Syntax = union(enum) { + /// A flag with no values. + flag, + + /// An option which prefixes its (single) value. + joined, + + /// An option which is followed by its value. + separate, + + /// An option which is either joined to its (non-empty) value, or followed by its value. + joined_or_separate, + + /// An option which is both joined to its (first) value, and followed by its (second) value. + joined_and_separate, + + /// An option followed by its values, which are separated by commas. + comma_joined, + + /// An option which consumes an optional joined argument and any other remaining arguments. + remaining_args_joined, + + /// An option which is which takes multiple (separate) arguments. + multi_arg: u8, + }; + + fn matchEql(self: CliArg, arg: []const u8) bool { + if (self.pd1 and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "-") and mem.eql(u8, arg[1..], self.name)) + { + return true; + } + if (self.pd2 and arg.len >= self.name.len + 2 and + mem.startsWith(u8, arg, "--") and mem.eql(u8, arg[2..], self.name)) + { + return true; + } + if (self.psl and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "/") and mem.eql(u8, arg[1..], self.name)) + { + return true; + } + return false; + } + + fn matchStartsWith(self: CliArg, arg: []const u8) usize { + if (self.pd1 and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "-") and mem.startsWith(u8, arg[1..], self.name)) + { + return self.name.len + 1; + } + if (self.pd2 and arg.len >= self.name.len + 2 and + mem.startsWith(u8, arg, "--") and mem.startsWith(u8, arg[2..], self.name)) + { + return self.name.len + 2; + } + if (self.psl and arg.len >= self.name.len + 1 and + mem.startsWith(u8, arg, "/") and mem.startsWith(u8, arg[1..], self.name)) + { + return self.name.len + 1; + } + return 0; + } +}; + +/// Shortcut function for initializing a `CliArg` +pub fn flagpd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + }; +} + +/// Shortcut function for initializing a `CliArg` +pub fn joinpd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + }; +} + +/// Shortcut function for initializing a `CliArg` +pub fn jspd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + }; +} + +/// Shortcut function for initializing a `CliArg` +pub fn sepd1(name: []const u8) CliArg { + return .{ + .name = name, + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = true, + }; +} diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig new file mode 100644 index 0000000000..a88f3583c9 --- /dev/null +++ b/src-self-hosted/clang_options_data.zig @@ -0,0 +1,5632 @@ +// This file is generated by tools/update_clang_options.zig. +// zig fmt: off +usingnamespace @import("clang_options.zig"); +pub const data = blk: { @setEvalBranchQuota(6000); break :blk &[_]CliArg{ +jspd1("A"), +joinpd1("A-"), +jspd1("B"), +flagpd1("C"), +flagpd1("CC"), +jspd1("D"), +flagpd1("E"), +flagpd1("EB"), +flagpd1("EL"), +flagpd1("Eonly"), +jspd1("F"), +jspd1("G"), +joinpd1("G="), +flagpd1("H"), +jspd1("I"), +.{ + .name = "", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = false, + .psl = false, +}, +flagpd1("I-"), +jspd1("J"), +jspd1("L"), +flagpd1("M"), +flagpd1("MD"), +jspd1("MF"), +flagpd1("MG"), +jspd1("MJ"), +flagpd1("MM"), +flagpd1("MMD"), +flagpd1("MP"), +jspd1("MQ"), +jspd1("MT"), +flagpd1("MV"), +flagpd1("Mach"), +joinpd1("O"), +flagpd1("O0"), +flagpd1("O4"), +flagpd1("O"), +flagpd1("ObjC"), +flagpd1("ObjC++"), +joinpd1("Ofast"), +flagpd1("P"), +flagpd1("Q"), +flagpd1("Qn"), +flagpd1("Qunused-arguments"), +flagpd1("Qy"), +joinpd1("R"), +joinpd1("Rpass="), +joinpd1("Rpass-analysis="), +joinpd1("Rpass-missed="), +flagpd1("S"), +jspd1("T"), +jspd1("Tbss"), +jspd1("Tdata"), +jspd1("Ttext"), +jspd1("U"), +.{ + .name = "", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = false, + .psl = false, +}, +jspd1("V"), +flagpd1("WCL4"), +joinpd1("W"), +.{ + .name = "Wa,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("Wall"), +flagpd1("Wdeprecated"), +joinpd1("Wframe-larger-than="), +.{ + .name = "Wl,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("Wlarge-by-value-copy="), +flagpd1("Wlarge-by-value-copy"), +joinpd1("Wlarger-than-"), +joinpd1("Wlarger-than="), +flagpd1("Wno-deprecated"), +joinpd1("Wno-nonportable-cfstrings"), +flagpd1("Wno-rewrite-macros"), +flagpd1("Wno-write-strings"), +joinpd1("Wnonportable-cfstrings"), +.{ + .name = "Wp,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("Wwrite-strings"), +flagpd1("X"), +joinpd1("X"), +sepd1("Xanalyzer"), +.{ + .name = "Xarch_", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("Xassembler"), +sepd1("Xclang"), +sepd1("Xcuda-fatbinary"), +sepd1("Xcuda-ptxas"), +sepd1("Xlinker"), +sepd1("Xopenmp-target"), +.{ + .name = "Xopenmp-target=", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("Xpreprocessor"), +flagpd1("Z"), +joinpd1("Z"), +flagpd1("Z-Xlinker-no-demangle"), +flagpd1("Z-reserved-lib-cckext"), +flagpd1("Z-reserved-lib-stdc++"), +sepd1("Zlinker-input"), +.{ + .name = "CLASSPATH", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "CLASSPATH=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("###"), +.{ + .name = "AI", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Brepro", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Brepro-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Bt", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Bt+", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "C", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "D", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "E", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "EH", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "EP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "F", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FA", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FA", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FC", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FI", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FR", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FS", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FU", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fa", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fd", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fe", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fi", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fm", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fo", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fp", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fr", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fx", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "G1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "G2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GA", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GF", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GF-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GH", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GL", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GL-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GR", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GR-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GS", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GS-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GT", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GX", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GX-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "GZ", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ge", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gh", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gm", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gm-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gr", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gregcall", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gs", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gv", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gw", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gw-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gy", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gy-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gz", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "H", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "HELP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "I", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "J", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "JMC", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "LD", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "LDd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "LN", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MD", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MDd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MP", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MT", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MTd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "P", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "QIfist", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "?", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qfast_transcendentals", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qimprecise_fwaits", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qpar", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qpar-report", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qsafe_fp_loads", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qspectre", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec-report", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "RTC", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "TC", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "TP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Tc", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Tp", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "U", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "V", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W0", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W3", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "W4", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "WL", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "WX", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "WX-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Wall", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Wp64", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "X", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Y-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yc", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yl", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yu", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Z7", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZH:MD5", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZH:SHA1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZH:SHA_256", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZI", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZW", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Za", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:__cplusplus", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:alignedNew", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:alignedNew-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:auto", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:char8_t", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:char8_t-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:dllexportInlines", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:dllexportInlines-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:forScope", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:inline", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:rvalueCast", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:sizedDealloc", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:sizedDealloc-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:strictStrings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:ternary", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:threadSafeInit", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:threadSafeInit-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:trigraphs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:trigraphs-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:twoPhase", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:twoPhase-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:wchar_t", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zd", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ze", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zg", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zi", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zl", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zm", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zo", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zo-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zp", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "analyze-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "arch:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "await", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "bigobj", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "c", + .syntax = .flag, + .zig_equivalent = .c, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "cgthreads", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "clang:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "clr", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "constexpr:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d1PP", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d1reportAllClassLayout", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2FastFail", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2Zi+", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "diagnostics:caret", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "diagnostics:classic", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "diagnostics:column", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "doc", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "errorReport", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "execution-charset:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fallback", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "favor", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:except", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:except-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:fast", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:precise", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "fp:strict", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "guard:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "help", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "homeparams", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "hotpatch", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "imsvc", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "kernel", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "kernel-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "link", + .syntax = .remaining_args_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "nologo", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "o", + .syntax = .joined_or_separate, + .zig_equivalent = .o, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "openmp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "openmp-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "openmp:experimental", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "permissive-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "sdl", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "sdl-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "showFilenames", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "showFilenames-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "showIncludes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "source-charset:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "std:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "u", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "utf-8", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "validate-charset", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "validate-charset-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vd", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmb", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmg", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmm", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vms", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vmv", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "volatile:iso", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "volatile:ms", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "w", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "w", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4005", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4018", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4100", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4910", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "wd4996", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "all-warnings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "analyze", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "analyzer-no-default-checks", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "analyzer-output", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "assemble", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "assert", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "assert=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "bootclasspath", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "bootclasspath=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "classpath", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "classpath=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "comments", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "comments-in-macros", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "compile", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "constant-cfstrings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "debug", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "debug=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "define-macro", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "define-macro=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dyld-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dyld-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "encoding", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "encoding=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "entry", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "extdirs", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "extdirs=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "extra-warnings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "for-linker", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "for-linker=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "force-link", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "force-link=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "help-hidden", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "imacros=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-barrier", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-directory", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-directory-after", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-directory-after=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix-after", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix-after=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix-before", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix-before=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "language", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "language=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "library-directory", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "library-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "mhwdiv", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "mhwdiv=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "migrate", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-line-commands", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-standard-includes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-standard-libraries", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-undefined", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-warnings", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "optimize", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "optimize=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output-class-directory", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output-class-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "param", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "param=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "precompile", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "preprocess", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-diagnostic-categories", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-file-name", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-missing-file-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-prog-name", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "profile", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "profile-blocks", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "resource", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "resource=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "rtlib", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "serialize-diagnostics", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "signed-char", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "std", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "stdlib", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "sysroot", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "sysroot=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "target-help", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "trace-includes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "undefine-macro", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "undefine-macro=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "unsigned-char", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "user-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "verbose", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "version", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "warn-", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "warn-=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "write-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "write-user-dependencies", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("a"), +sepd1("add-plugin"), +flagpd1("faggressive-function-elimination"), +flagpd1("fno-aggressive-function-elimination"), +flagpd1("falign-commons"), +flagpd1("fno-align-commons"), +flagpd1("falign-jumps"), +flagpd1("fno-align-jumps"), +flagpd1("falign-labels"), +flagpd1("fno-align-labels"), +flagpd1("falign-loops"), +flagpd1("fno-align-loops"), +flagpd1("faligned-alloc-unavailable"), +flagpd1("all_load"), +flagpd1("fall-intrinsics"), +flagpd1("fno-all-intrinsics"), +sepd1("allowable_client"), +flagpd1("cfg-add-implicit-dtors"), +flagpd1("unoptimized-cfg"), +flagpd1("analyze"), +sepd1("analyze-function"), +joinpd1("analyze-function="), +sepd1("analyzer-checker"), +joinpd1("analyzer-checker="), +flagpd1("analyzer-checker-help"), +flagpd1("analyzer-checker-help-alpha"), +flagpd1("analyzer-checker-help-developer"), +flagpd1("analyzer-checker-option-help"), +flagpd1("analyzer-checker-option-help-alpha"), +flagpd1("analyzer-checker-option-help-developer"), +sepd1("analyzer-config"), +sepd1("analyzer-config-compatibility-mode"), +joinpd1("analyzer-config-compatibility-mode="), +flagpd1("analyzer-config-help"), +sepd1("analyzer-constraints"), +joinpd1("analyzer-constraints="), +flagpd1("analyzer-disable-all-checks"), +sepd1("analyzer-disable-checker"), +joinpd1("analyzer-disable-checker="), +flagpd1("analyzer-disable-retry-exhausted"), +flagpd1("analyzer-display-progress"), +sepd1("analyzer-dump-egraph"), +joinpd1("analyzer-dump-egraph="), +sepd1("analyzer-inline-max-stack-depth"), +joinpd1("analyzer-inline-max-stack-depth="), +sepd1("analyzer-inlining-mode"), +joinpd1("analyzer-inlining-mode="), +flagpd1("analyzer-list-enabled-checkers"), +sepd1("analyzer-max-loop"), +flagpd1("analyzer-opt-analyze-headers"), +flagpd1("analyzer-opt-analyze-nested-blocks"), +sepd1("analyzer-output"), +joinpd1("analyzer-output="), +sepd1("analyzer-purge"), +joinpd1("analyzer-purge="), +flagpd1("analyzer-stats"), +sepd1("analyzer-store"), +joinpd1("analyzer-store="), +flagpd1("analyzer-viz-egraph-graphviz"), +flagpd1("analyzer-werror"), +flagpd1("fslp-vectorize-aggressive"), +flagpd1("fno-slp-vectorize-aggressive"), +flagpd1("fexpensive-optimizations"), +flagpd1("fno-expensive-optimizations"), +flagpd1("fdefer-pop"), +flagpd1("fno-defer-pop"), +flagpd1("fextended-identifiers"), +flagpd1("fno-extended-identifiers"), +flagpd1("fhonor-infinites"), +flagpd1("fno-honor-infinites"), +flagpd1("findirect-virtual-calls"), +sepd1("fnew-alignment"), +joinpd1("objcmt-white-list-dir-path="), +flagpd1("faligned-new"), +flagpd1("fno-aligned-new"), +flagpd1("fsched-interblock"), +flagpd1("ftree-vectorize"), +flagpd1("fno-tree-vectorize"), +flagpd1("ftree-slp-vectorize"), +flagpd1("fno-tree-slp-vectorize"), +flagpd1("fterminated-vtables"), +flagpd1("grecord-gcc-switches"), +flagpd1("gno-record-gcc-switches"), +flagpd1("fident"), +flagpd1("nocudalib"), +.{ + .name = "system-header-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-system-header-prefix", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("integrated-as"), +flagpd1("no-integrated-as"), +flagpd1("fkeep-inline-functions"), +flagpd1("fno-keep-inline-functions"), +flagpd1("fno-semantic-interposition"), +.{ + .name = "Gs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +flagpd1("fno-ident"), +.{ + .name = "Ob0", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ob1", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ob2", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Od", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Og", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Oi", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Oi-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Os", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ot", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Ox", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +flagpd1("fcuda-rdc"), +.{ + .name = "Oy", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Oy-", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +flagpd1("fno-cuda-rdc"), +flagpd1("shared-libasan"), +flagpd1("frecord-gcc-switches"), +flagpd1("fno-record-gcc-switches"), +.{ + .name = "ansi", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("arch"), +flagpd1("arch_errors_fatal"), +sepd1("arch_only"), +flagpd1("arcmt-check"), +flagpd1("arcmt-migrate"), +flagpd1("arcmt-migrate-emit-errors"), +sepd1("arcmt-migrate-report-output"), +flagpd1("arcmt-modify"), +flagpd1("ast-dump"), +joinpd1("ast-dump="), +flagpd1("ast-dump-all"), +joinpd1("ast-dump-all="), +sepd1("ast-dump-filter"), +flagpd1("ast-dump-lookups"), +flagpd1("ast-list"), +sepd1("ast-merge"), +flagpd1("ast-print"), +flagpd1("ast-view"), +.{ + .name = "autocomplete=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("fautomatic"), +flagpd1("fno-automatic"), +sepd1("aux-triple"), +jspd1("b"), +flagpd1("fbackslash"), +flagpd1("fno-backslash"), +flagpd1("fbacktrace"), +flagpd1("fno-backtrace"), +flagpd1("bind_at_load"), +flagpd1("fbounds-check"), +flagpd1("fno-bounds-check"), +flagpd1("fbranch-count-reg"), +flagpd1("fno-branch-count-reg"), +flagpd1("building-pch-with-obj"), +flagpd1("bundle"), +sepd1("bundle_loader"), +.{ + .name = "c", + .syntax = .flag, + .zig_equivalent = .c, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("c-isystem"), +flagpd1("fcaller-saves"), +flagpd1("fno-caller-saves"), +flagpd1("cc1"), +flagpd1("cc1as"), +joinpd1("ccc-"), +flagpd1("ccc-arcmt-check"), +sepd1("ccc-arcmt-migrate"), +flagpd1("ccc-arcmt-modify"), +sepd1("ccc-gcc-name"), +sepd1("ccc-install-dir"), +sepd1("ccc-objcmt-migrate"), +flagpd1("ccc-print-bindings"), +flagpd1("ccc-print-phases"), +flagpd1("cfguard"), +flagpd1("cfguard-no-checks"), +sepd1("chain-include"), +flagpd1("fcheck-array-temporaries"), +flagpd1("fno-check-array-temporaries"), +flagpd1("cl-denorms-are-zero"), +.{ + .name = "cl-ext=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("cl-fast-relaxed-math"), +flagpd1("cl-finite-math-only"), +flagpd1("cl-fp32-correctly-rounded-divide-sqrt"), +flagpd1("cl-kernel-arg-info"), +flagpd1("cl-mad-enable"), +flagpd1("cl-no-signed-zeros"), +flagpd1("cl-opt-disable"), +flagpd1("cl-single-precision-constant"), +joinpd1("cl-std="), +flagpd1("cl-strict-aliasing"), +flagpd1("cl-uniform-work-group-size"), +flagpd1("cl-unsafe-math-optimizations"), +jspd1("client_name"), +sepd1("code-completion-at"), +joinpd1("code-completion-at="), +flagpd1("code-completion-brief-comments"), +flagpd1("code-completion-macros"), +flagpd1("code-completion-patterns"), +flagpd1("code-completion-with-fixits"), +.{ + .name = "combine", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +jspd1("compatibility_version"), +flagpd1("compiler-options-dump"), +.{ + .name = "compress-debug-sections", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "compress-debug-sections=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "config", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "config-system-dir=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "config-user-dir=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "coverage", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("coverage-cfg-checksum"), +sepd1("coverage-data-file"), +joinpd1("coverage-data-file="), +flagpd1("coverage-exit-block-before-body"), +flagpd1("coverage-no-function-names-in-data"), +sepd1("coverage-notes-file"), +joinpd1("coverage-notes-file="), +joinpd1("coverage-version="), +flagpd1("cpp"), +flagpd1("cpp-precomp"), +flagpd1("fcray-pointer"), +flagpd1("fno-cray-pointer"), +.{ + .name = "cuda-compile-host-device", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-device-only", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-gpu-arch=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-host-only", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-include-ptx=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-noopt-device-debug", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-path-ignore-env", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +jspd1("current_version"), +jspd1("cxx-isystem"), +flagpd1("dA"), +flagpd1("dD"), +flagpd1("dI"), +flagpd1("dM"), +flagpd1("d"), +joinpd1("d"), +flagpd1("fd-lines-as-code"), +flagpd1("fno-d-lines-as-code"), +flagpd1("fd-lines-as-comments"), +flagpd1("fno-d-lines-as-comments"), +flagpd1("dead_strip"), +flagpd1("debug-forward-template-params"), +joinpd1("debug-info-kind="), +flagpd1("debug-info-macro"), +joinpd1("debugger-tuning="), +flagpd1("fdefault-double-8"), +flagpd1("fno-default-double-8"), +sepd1("default-function-attr"), +flagpd1("fdefault-inline"), +flagpd1("fno-default-inline"), +flagpd1("fdefault-integer-8"), +flagpd1("fno-default-integer-8"), +flagpd1("fdefault-real-8"), +flagpd1("fno-default-real-8"), +sepd1("defsym"), +sepd1("dependency-dot"), +sepd1("dependency-file"), +.{ + .name = "dependent-lib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("detailed-preprocessing-record"), +flagpd1("fdevirtualize"), +flagpd1("fno-devirtualize"), +flagpd1("fdevirtualize-speculatively"), +flagpd1("fno-devirtualize-speculatively"), +sepd1("diagnostic-log-file"), +sepd1("serialize-diagnostic-file"), +flagpd1("disable-O0-optnone"), +flagpd1("disable-free"), +flagpd1("disable-lifetime-markers"), +flagpd1("disable-llvm-optzns"), +flagpd1("disable-llvm-passes"), +flagpd1("disable-llvm-verifier"), +flagpd1("disable-objc-default-synthesize-properties"), +flagpd1("disable-pragma-debug-crash"), +flagpd1("disable-red-zone"), +flagpd1("discard-value-names"), +flagpd1("fdollar-ok"), +flagpd1("fno-dollar-ok"), +.{ + .name = "driver-mode=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("dump-coverage-mapping"), +flagpd1("dump-deserialized-decls"), +flagpd1("fdump-fortran-optimized"), +flagpd1("fno-dump-fortran-optimized"), +flagpd1("fdump-fortran-original"), +flagpd1("fno-dump-fortran-original"), +flagpd1("fdump-parse-tree"), +flagpd1("fno-dump-parse-tree"), +flagpd1("dump-raw-tokens"), +flagpd1("dump-tokens"), +flagpd1("dumpmachine"), +flagpd1("dumpspecs"), +flagpd1("dumpversion"), +flagpd1("dwarf-column-info"), +sepd1("dwarf-debug-flags"), +sepd1("dwarf-debug-producer"), +flagpd1("dwarf-explicit-import"), +flagpd1("dwarf-ext-refs"), +joinpd1("dwarf-version="), +sepd1("dylib_file"), +flagpd1("dylinker"), +jspd1("dylinker_install_name"), +flagpd1("dynamic"), +flagpd1("dynamiclib"), +jspd1("e"), +flagpd1("feliminate-unused-debug-types"), +flagpd1("fno-eliminate-unused-debug-types"), +flagpd1("emit-ast"), +flagpd1("emit-codegen-only"), +flagpd1("emit-header-module"), +flagpd1("emit-html"), +flagpd1("emit-interface-stubs"), +flagpd1("emit-llvm"), +flagpd1("emit-llvm-bc"), +flagpd1("emit-llvm-only"), +flagpd1("emit-llvm-uselists"), +flagpd1("emit-merged-ifs"), +flagpd1("emit-module"), +flagpd1("emit-module-interface"), +flagpd1("emit-obj"), +flagpd1("emit-pch"), +flagpd1("enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang"), +sepd1("error-on-deserialized-decl"), +joinpd1("error-on-deserialized-decl="), +sepd1("exported_symbols_list"), +flagpd1("fexternal-blas"), +flagpd1("fno-external-blas"), +flagpd1("ff2c"), +flagpd1("fno-f2c"), +flagpd1("fPIC"), +flagpd1("fPIE"), +flagpd1("faccess-control"), +joinpd1("faddress-space-map-mangling="), +flagpd1("faddrsig"), +flagpd1("falign-functions"), +joinpd1("falign-functions="), +joinpd1("falign-jumps="), +joinpd1("falign-labels="), +joinpd1("falign-loops="), +flagpd1("faligned-allocation"), +joinpd1("faligned-new="), +flagpd1("fallow-editor-placeholders"), +flagpd1("fallow-half-arguments-and-returns"), +flagpd1("fallow-pch-with-compiler-errors"), +flagpd1("fallow-unsupported"), +flagpd1("faltivec"), +flagpd1("fansi-escape-codes"), +flagpd1("fapple-kext"), +flagpd1("fapple-link-rtlib"), +flagpd1("fapple-pragma-pack"), +flagpd1("fapplication-extension"), +flagpd1("fapply-global-visibility-to-externs"), +flagpd1("fasm"), +flagpd1("fasm-blocks"), +flagpd1("fassociative-math"), +flagpd1("fassume-sane-operator-new"), +flagpd1("fast"), +flagpd1("fastcp"), +flagpd1("fastf"), +flagpd1("fasynchronous-unwind-tables"), +flagpd1("ffat-lto-objects"), +flagpd1("fno-fat-lto-objects"), +flagpd1("fauto-profile"), +joinpd1("fauto-profile="), +flagpd1("fauto-profile-accurate"), +flagpd1("fautolink"), +joinpd1("fblas-matmul-limit="), +flagpd1("fblocks"), +flagpd1("fblocks-runtime-optional"), +joinpd1("fbootclasspath="), +flagpd1("fborland-extensions"), +sepd1("fbracket-depth"), +joinpd1("fbracket-depth="), +joinpd1("fbuild-session-file="), +joinpd1("fbuild-session-timestamp="), +flagpd1("fbuiltin"), +flagpd1("fbuiltin-module-map"), +flagpd1("fcall-saved-x10"), +flagpd1("fcall-saved-x11"), +flagpd1("fcall-saved-x12"), +flagpd1("fcall-saved-x13"), +flagpd1("fcall-saved-x14"), +flagpd1("fcall-saved-x15"), +flagpd1("fcall-saved-x18"), +flagpd1("fcall-saved-x8"), +flagpd1("fcall-saved-x9"), +flagpd1("fcaret-diagnostics"), +sepd1("fcaret-diagnostics-max-lines"), +flagpd1("fcf-protection"), +joinpd1("fcf-protection="), +joinpd1("fcf-runtime-abi="), +flagpd1("fchar8_t"), +joinpd1("fcheck="), +flagpd1("fcheck-new"), +flagpd1("fno-check-new"), +joinpd1("fclang-abi-compat="), +joinpd1("fclasspath="), +joinpd1("fcoarray="), +flagpd1("fcolor-diagnostics"), +.{ + .name = "fcomment-block-commands=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fcommon"), +joinpd1("fcompile-resource="), +flagpd1("fcomplete-member-pointers"), +flagpd1("fconcepts-ts"), +flagpd1("fconst-strings"), +flagpd1("fconstant-cfstrings"), +sepd1("fconstant-string-class"), +joinpd1("fconstant-string-class="), +sepd1("fconstexpr-backtrace-limit"), +joinpd1("fconstexpr-backtrace-limit="), +sepd1("fconstexpr-depth"), +joinpd1("fconstexpr-depth="), +sepd1("fconstexpr-steps"), +joinpd1("fconstexpr-steps="), +flagpd1("fconvergent-functions"), +joinpd1("fconvert="), +flagpd1("fcoroutines-ts"), +flagpd1("fcoverage-mapping"), +joinpd1("fcrash-diagnostics-dir="), +flagpd1("fcreate-profile"), +flagpd1("fcs-profile-generate"), +joinpd1("fcs-profile-generate="), +flagpd1("fcuda-allow-variadic-functions"), +flagpd1("fcuda-approx-transcendentals"), +flagpd1("fcuda-flush-denormals-to-zero"), +sepd1("fcuda-include-gpubinary"), +flagpd1("fcuda-is-device"), +flagpd1("fcuda-short-ptr"), +flagpd1("fcxx-exceptions"), +flagpd1("fcxx-modules"), +flagpd1("fc++-static-destructors"), +flagpd1("fdata-sections"), +sepd1("fdebug-compilation-dir"), +joinpd1("fdebug-compilation-dir="), +joinpd1("fdebug-default-version="), +flagpd1("fdebug-info-for-profiling"), +flagpd1("fdebug-macro"), +flagpd1("fdebug-pass-arguments"), +flagpd1("fdebug-pass-manager"), +flagpd1("fdebug-pass-structure"), +joinpd1("fdebug-prefix-map="), +flagpd1("fdebug-ranges-base-address"), +flagpd1("fdebug-types-section"), +flagpd1("fdebugger-cast-result-to-id"), +flagpd1("fdebugger-objc-literal"), +flagpd1("fdebugger-support"), +flagpd1("fdeclare-opencl-builtins"), +flagpd1("fdeclspec"), +joinpd1("fdefault-calling-conv="), +flagpd1("fdelayed-template-parsing"), +flagpd1("fdelete-null-pointer-checks"), +joinpd1("fdenormal-fp-math="), +joinpd1("fdepfile-entry="), +flagpd1("fdeprecated-macro"), +flagpd1("fdiagnostics-absolute-paths"), +flagpd1("fdiagnostics-color"), +joinpd1("fdiagnostics-color="), +flagpd1("fdiagnostics-fixit-info"), +sepd1("fdiagnostics-format"), +joinpd1("fdiagnostics-format="), +joinpd1("fdiagnostics-hotness-threshold="), +flagpd1("fdiagnostics-parseable-fixits"), +flagpd1("fdiagnostics-print-source-range-info"), +sepd1("fdiagnostics-show-category"), +joinpd1("fdiagnostics-show-category="), +flagpd1("fdiagnostics-show-hotness"), +joinpd1("fdiagnostics-show-location="), +flagpd1("fdiagnostics-show-note-include-stack"), +flagpd1("fdiagnostics-show-option"), +flagpd1("fdiagnostics-show-template-tree"), +flagpd1("fdigraphs"), +flagpd1("fdisable-module-hash"), +flagpd1("fdiscard-value-names"), +flagpd1("fdollars-in-identifiers"), +flagpd1("fdouble-square-bracket-attributes"), +flagpd1("fdump-record-layouts"), +flagpd1("fdump-record-layouts-simple"), +flagpd1("fdump-vtable-layouts"), +flagpd1("fdwarf2-cfi-asm"), +flagpd1("fdwarf-directory-asm"), +flagpd1("fdwarf-exceptions"), +flagpd1("felide-constructors"), +flagpd1("feliminate-unused-debug-symbols"), +flagpd1("fembed-bitcode"), +joinpd1("fembed-bitcode="), +flagpd1("fembed-bitcode-marker"), +flagpd1("femit-all-decls"), +flagpd1("femit-coverage-data"), +flagpd1("femit-coverage-notes"), +flagpd1("femit-debug-entry-values"), +flagpd1("femulated-tls"), +flagpd1("fencode-extended-block-signature"), +joinpd1("fencoding="), +sepd1("ferror-limit"), +joinpd1("ferror-limit="), +flagpd1("fescaping-block-tail-calls"), +flagpd1("fexceptions"), +joinpd1("fexcess-precision="), +joinpd1("fexec-charset="), +flagpd1("fexperimental-isel"), +flagpd1("fexperimental-new-constant-interpreter"), +flagpd1("fexperimental-new-pass-manager"), +joinpd1("fextdirs="), +flagpd1("fexternc-nounwind"), +flagpd1("ffake-address-space-map"), +flagpd1("ffast-math"), +joinpd1("ffile-prefix-map="), +flagpd1("ffine-grained-bitfield-accesses"), +flagpd1("ffinite-math-only"), +joinpd1("ffixed-line-length-"), +flagpd1("ffixed-point"), +flagpd1("ffixed-r19"), +flagpd1("ffixed-r9"), +flagpd1("ffixed-x1"), +flagpd1("ffixed-x10"), +flagpd1("ffixed-x11"), +flagpd1("ffixed-x12"), +flagpd1("ffixed-x13"), +flagpd1("ffixed-x14"), +flagpd1("ffixed-x15"), +flagpd1("ffixed-x16"), +flagpd1("ffixed-x17"), +flagpd1("ffixed-x18"), +flagpd1("ffixed-x19"), +flagpd1("ffixed-x2"), +flagpd1("ffixed-x20"), +flagpd1("ffixed-x21"), +flagpd1("ffixed-x22"), +flagpd1("ffixed-x23"), +flagpd1("ffixed-x24"), +flagpd1("ffixed-x25"), +flagpd1("ffixed-x26"), +flagpd1("ffixed-x27"), +flagpd1("ffixed-x28"), +flagpd1("ffixed-x29"), +flagpd1("ffixed-x3"), +flagpd1("ffixed-x30"), +flagpd1("ffixed-x31"), +flagpd1("ffixed-x4"), +flagpd1("ffixed-x5"), +flagpd1("ffixed-x6"), +flagpd1("ffixed-x7"), +flagpd1("ffixed-x8"), +flagpd1("ffixed-x9"), +flagpd1("ffor-scope"), +flagpd1("fforbid-guard-variables"), +flagpd1("fforce-dwarf-frame"), +flagpd1("fforce-emit-vtables"), +flagpd1("fforce-enable-int128"), +joinpd1("ffp-contract="), +joinpd1("ffp-exception-behavior="), +joinpd1("ffp-model="), +joinpd1("ffpe-trap="), +joinpd1("ffree-line-length-"), +flagpd1("ffreestanding"), +flagpd1("ffunction-sections"), +flagpd1("fgnu89-inline"), +flagpd1("fgnu-inline-asm"), +flagpd1("fgnu-keywords"), +flagpd1("fgnu-runtime"), +joinpd1("fgnuc-version="), +flagpd1("fgpu-allow-device-init"), +flagpd1("fgpu-rdc"), +flagpd1("fheinous-gnu-extensions"), +flagpd1("fhip-dump-offload-linker-script"), +flagpd1("fhip-new-launch-api"), +flagpd1("fhonor-infinities"), +flagpd1("fhonor-nans"), +flagpd1("fhosted"), +sepd1("filelist"), +sepd1("filetype"), +flagpd1("fimplicit-module-maps"), +flagpd1("fimplicit-modules"), +flagpd1("finclude-default-header"), +joinpd1("finit-character="), +joinpd1("finit-integer="), +joinpd1("finit-logical="), +joinpd1("finit-real="), +flagpd1("finline"), +flagpd1("finline-functions"), +flagpd1("finline-hint-functions"), +joinpd1("finline-limit="), +flagpd1("finline-limit"), +flagpd1("fno-inline-limit"), +joinpd1("finput-charset="), +flagpd1("finstrument-function-entry-bare"), +flagpd1("finstrument-functions"), +flagpd1("finstrument-functions-after-inlining"), +flagpd1("fintegrated-as"), +flagpd1("fintegrated-cc1"), +flagpd1("fix-only-warnings"), +flagpd1("fix-what-you-can"), +flagpd1("ffixed-form"), +flagpd1("fno-fixed-form"), +flagpd1("fixit"), +joinpd1("fixit="), +flagpd1("fixit-recompile"), +flagpd1("fixit-to-temporary"), +flagpd1("fjump-tables"), +flagpd1("fkeep-static-consts"), +flagpd1("flat_namespace"), +flagpd1("flax-vector-conversions"), +joinpd1("flax-vector-conversions="), +flagpd1("flimit-debug-info"), +joinpd1("flimited-precision="), +flagpd1("ffloat-store"), +flagpd1("fno-float-store"), +flagpd1("flto"), +joinpd1("flto="), +joinpd1("flto-jobs="), +flagpd1("flto-unit"), +flagpd1("flto-visibility-public-std"), +sepd1("fmacro-backtrace-limit"), +joinpd1("fmacro-backtrace-limit="), +joinpd1("fmacro-prefix-map="), +flagpd1("fmath-errno"), +joinpd1("fmax-array-constructor="), +joinpd1("fmax-errors="), +joinpd1("fmax-stack-var-size="), +joinpd1("fmax-subrecord-length="), +joinpd1("fmax-type-align="), +flagpd1("fmerge-all-constants"), +flagpd1("fmerge-functions"), +sepd1("fmessage-length"), +joinpd1("fmessage-length="), +sepd1("fmodule-feature"), +joinpd1("fmodule-file="), +flagpd1("fmodule-file-deps"), +joinpd1("fmodule-format="), +sepd1("fmodule-implementation-of"), +joinpd1("fmodule-map-file="), +flagpd1("fmodule-map-file-home-is-cwd"), +flagpd1("fmodule-maps"), +sepd1("fmodule-name"), +joinpd1("fmodule-name="), +flagpd1("fmodules"), +joinpd1("fmodules-cache-path="), +flagpd1("fmodules-codegen"), +flagpd1("fmodules-debuginfo"), +flagpd1("fmodules-decluse"), +flagpd1("fmodules-disable-diagnostic-validation"), +joinpd1("fmodules-embed-all-files"), +joinpd1("fmodules-embed-file="), +flagpd1("fmodules-hash-content"), +joinpd1("fmodules-ignore-macro="), +flagpd1("fmodules-local-submodule-visibility"), +joinpd1("fmodules-prune-after="), +joinpd1("fmodules-prune-interval="), +flagpd1("fmodules-search-all"), +flagpd1("fmodules-strict-context-hash"), +flagpd1("fmodules-strict-decluse"), +flagpd1("fmodules-ts"), +sepd1("fmodules-user-build-path"), +flagpd1("fmodules-validate-input-files-content"), +flagpd1("fmodules-validate-once-per-build-session"), +flagpd1("fmodules-validate-system-headers"), +flagpd1("fms-compatibility"), +joinpd1("fms-compatibility-version="), +flagpd1("fms-extensions"), +joinpd1("fms-memptr-rep="), +flagpd1("fms-volatile"), +joinpd1("fmsc-version="), +flagpd1("fmudflap"), +flagpd1("fmudflapth"), +flagpd1("fnative-half-arguments-and-returns"), +flagpd1("fnative-half-type"), +flagpd1("fnested-functions"), +joinpd1("fnew-alignment="), +flagpd1("fnext-runtime"), +flagpd1("fno-PIC"), +flagpd1("fno-PIE"), +flagpd1("fno-access-control"), +flagpd1("fno-addrsig"), +flagpd1("fno-align-functions"), +flagpd1("fno-aligned-allocation"), +flagpd1("fno-allow-editor-placeholders"), +flagpd1("fno-altivec"), +flagpd1("fno-apple-pragma-pack"), +flagpd1("fno-application-extension"), +flagpd1("fno-asm"), +flagpd1("fno-asm-blocks"), +flagpd1("fno-associative-math"), +flagpd1("fno-assume-sane-operator-new"), +flagpd1("fno-asynchronous-unwind-tables"), +flagpd1("fno-auto-profile"), +flagpd1("fno-auto-profile-accurate"), +flagpd1("fno-autolink"), +flagpd1("fno-bitfield-type-align"), +flagpd1("fno-blocks"), +flagpd1("fno-borland-extensions"), +flagpd1("fno-builtin"), +joinpd1("fno-builtin-"), +flagpd1("fno-caret-diagnostics"), +flagpd1("fno-char8_t"), +flagpd1("fno-color-diagnostics"), +flagpd1("fno-common"), +flagpd1("fno-complete-member-pointers"), +flagpd1("fno-concept-satisfaction-caching"), +flagpd1("fno-const-strings"), +flagpd1("fno-constant-cfstrings"), +flagpd1("fno-coroutines-ts"), +flagpd1("fno-coverage-mapping"), +flagpd1("fno-crash-diagnostics"), +flagpd1("fno-cuda-approx-transcendentals"), +flagpd1("fno-cuda-flush-denormals-to-zero"), +flagpd1("fno-cuda-host-device-constexpr"), +flagpd1("fno-cuda-short-ptr"), +flagpd1("fno-cxx-exceptions"), +flagpd1("fno-cxx-modules"), +flagpd1("fno-c++-static-destructors"), +flagpd1("fno-data-sections"), +flagpd1("fno-debug-info-for-profiling"), +flagpd1("fno-debug-macro"), +flagpd1("fno-debug-pass-manager"), +flagpd1("fno-debug-ranges-base-address"), +flagpd1("fno-debug-types-section"), +flagpd1("fno-declspec"), +flagpd1("fno-delayed-template-parsing"), +flagpd1("fno-delete-null-pointer-checks"), +flagpd1("fno-deprecated-macro"), +flagpd1("fno-diagnostics-color"), +flagpd1("fno-diagnostics-fixit-info"), +flagpd1("fno-diagnostics-show-hotness"), +flagpd1("fno-diagnostics-show-note-include-stack"), +flagpd1("fno-diagnostics-show-option"), +flagpd1("fno-diagnostics-use-presumed-location"), +flagpd1("fno-digraphs"), +flagpd1("fno-discard-value-names"), +flagpd1("fno-dllexport-inlines"), +flagpd1("fno-dollars-in-identifiers"), +flagpd1("fno-double-square-bracket-attributes"), +flagpd1("fno-dwarf2-cfi-asm"), +flagpd1("fno-dwarf-directory-asm"), +flagpd1("fno-elide-constructors"), +flagpd1("fno-elide-type"), +flagpd1("fno-eliminate-unused-debug-symbols"), +flagpd1("fno-emulated-tls"), +flagpd1("fno-escaping-block-tail-calls"), +flagpd1("fno-exceptions"), +flagpd1("fno-experimental-isel"), +flagpd1("fno-experimental-new-pass-manager"), +flagpd1("fno-fast-math"), +flagpd1("fno-fine-grained-bitfield-accesses"), +flagpd1("fno-finite-math-only"), +flagpd1("fno-fixed-point"), +flagpd1("fno-for-scope"), +flagpd1("fno-force-dwarf-frame"), +flagpd1("fno-force-emit-vtables"), +flagpd1("fno-force-enable-int128"), +flagpd1("fno-function-sections"), +flagpd1("fno-gnu89-inline"), +flagpd1("fno-gnu-inline-asm"), +flagpd1("fno-gnu-keywords"), +flagpd1("fno-gpu-allow-device-init"), +flagpd1("fno-gpu-rdc"), +flagpd1("fno-hip-new-launch-api"), +flagpd1("fno-honor-infinities"), +flagpd1("fno-honor-nans"), +flagpd1("fno-implicit-module-maps"), +flagpd1("fno-implicit-modules"), +flagpd1("fno-inline"), +flagpd1("fno-inline-functions"), +flagpd1("fno-integrated-as"), +flagpd1("fno-integrated-cc1"), +flagpd1("fno-jump-tables"), +flagpd1("fno-lax-vector-conversions"), +flagpd1("fno-limit-debug-info"), +flagpd1("fno-lto"), +flagpd1("fno-lto-unit"), +flagpd1("fno-math-builtin"), +flagpd1("fno-math-errno"), +flagpd1("fno-max-type-align"), +flagpd1("fno-merge-all-constants"), +flagpd1("fno-module-file-deps"), +flagpd1("fno-module-maps"), +flagpd1("fno-modules"), +flagpd1("fno-modules-decluse"), +flagpd1("fno-modules-error-recovery"), +flagpd1("fno-modules-global-index"), +flagpd1("fno-modules-search-all"), +flagpd1("fno-strict-modules-decluse"), +flagpd1("fno_modules-validate-input-files-content"), +flagpd1("fno-modules-validate-system-headers"), +flagpd1("fno-ms-compatibility"), +flagpd1("fno-ms-extensions"), +flagpd1("fno-objc-arc"), +flagpd1("fno-objc-arc-exceptions"), +flagpd1("fno-objc-convert-messages-to-runtime-calls"), +flagpd1("fno-objc-exceptions"), +flagpd1("fno-objc-infer-related-result-type"), +flagpd1("fno-objc-legacy-dispatch"), +flagpd1("fno-objc-nonfragile-abi"), +flagpd1("fno-objc-weak"), +flagpd1("fno-omit-frame-pointer"), +flagpd1("fno-openmp"), +flagpd1("fno-openmp-cuda-force-full-runtime"), +flagpd1("fno-openmp-cuda-mode"), +flagpd1("fno-openmp-optimistic-collapse"), +flagpd1("fno-openmp-simd"), +flagpd1("fno-operator-names"), +flagpd1("fno-optimize-sibling-calls"), +flagpd1("fno-pack-struct"), +flagpd1("fno-padding-on-unsigned-fixed-point"), +flagpd1("fno-pascal-strings"), +flagpd1("fno-pch-timestamp"), +flagpd1("fno_pch-validate-input-files-content"), +flagpd1("fno-pic"), +flagpd1("fno-pie"), +flagpd1("fno-plt"), +flagpd1("fno-preserve-as-comments"), +flagpd1("fno-profile-arcs"), +flagpd1("fno-profile-generate"), +flagpd1("fno-profile-instr-generate"), +flagpd1("fno-profile-instr-use"), +flagpd1("fno-profile-sample-accurate"), +flagpd1("fno-profile-sample-use"), +flagpd1("fno-profile-use"), +flagpd1("fno-reciprocal-math"), +flagpd1("fno-record-command-line"), +flagpd1("fno-register-global-dtors-with-atexit"), +flagpd1("fno-relaxed-template-template-args"), +flagpd1("fno-reroll-loops"), +flagpd1("fno-rewrite-imports"), +flagpd1("fno-rewrite-includes"), +flagpd1("fno-ropi"), +flagpd1("fno-rounding-math"), +flagpd1("fno-rtlib-add-rpath"), +flagpd1("fno-rtti"), +flagpd1("fno-rtti-data"), +flagpd1("fno-rwpi"), +.{ + .name = "fno-sanitize=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fno-sanitize-address-poison-custom-array-cookie"), +flagpd1("fno-sanitize-address-use-after-scope"), +flagpd1("fno-sanitize-address-use-odr-indicator"), +flagpd1("fno-sanitize-blacklist"), +flagpd1("fno-sanitize-cfi-canonical-jump-tables"), +flagpd1("fno-sanitize-cfi-cross-dso"), +.{ + .name = "fno-sanitize-coverage=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fno-sanitize-link-c++-runtime"), +flagpd1("fno-sanitize-link-runtime"), +flagpd1("fno-sanitize-memory-track-origins"), +flagpd1("fno-sanitize-memory-use-after-dtor"), +flagpd1("fno-sanitize-minimal-runtime"), +flagpd1("fno-sanitize-recover"), +.{ + .name = "fno-sanitize-recover=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fno-sanitize-stats"), +flagpd1("fno-sanitize-thread-atomics"), +flagpd1("fno-sanitize-thread-func-entry-exit"), +flagpd1("fno-sanitize-thread-memory-access"), +.{ + .name = "fno-sanitize-trap=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fno-sanitize-undefined-trap-on-error"), +flagpd1("fno-save-optimization-record"), +flagpd1("fno-short-enums"), +flagpd1("fno-short-wchar"), +flagpd1("fno-show-column"), +flagpd1("fno-show-source-location"), +flagpd1("fno-signaling-math"), +flagpd1("fno-signed-char"), +flagpd1("fno-signed-wchar"), +flagpd1("fno-signed-zeros"), +flagpd1("fno-sized-deallocation"), +flagpd1("fno-slp-vectorize"), +flagpd1("fno-spell-checking"), +flagpd1("fno-split-dwarf-inlining"), +flagpd1("fno-split-lto-unit"), +flagpd1("fno-stack-protector"), +flagpd1("fno-stack-size-section"), +flagpd1("fno-standalone-debug"), +flagpd1("fno-strict-aliasing"), +flagpd1("fno-strict-enums"), +flagpd1("fno-strict-float-cast-overflow"), +flagpd1("fno-strict-overflow"), +flagpd1("fno-strict-return"), +flagpd1("fno-strict-vtable-pointers"), +flagpd1("fno-struct-path-tbaa"), +flagpd1("fno-temp-file"), +flagpd1("fno-threadsafe-statics"), +flagpd1("fno-trapping-math"), +flagpd1("fno-trigraphs"), +flagpd1("fno-unique-section-names"), +flagpd1("fno-unit-at-a-time"), +flagpd1("fno-unroll-loops"), +flagpd1("fno-unsafe-math-optimizations"), +flagpd1("fno-unsigned-char"), +flagpd1("fno-unwind-tables"), +flagpd1("fno-use-cxa-atexit"), +flagpd1("fno-use-init-array"), +flagpd1("fno-use-line-directives"), +flagpd1("fno-validate-pch"), +flagpd1("fno-var-tracking"), +flagpd1("fno-vectorize"), +flagpd1("fno-verbose-asm"), +flagpd1("fno-virtual-function_elimination"), +flagpd1("fno-wchar"), +flagpd1("fno-whole-program-vtables"), +flagpd1("fno-working-directory"), +flagpd1("fno-wrapv"), +flagpd1("fno-zero-initialized-in-bss"), +flagpd1("fno-zvector"), +flagpd1("fnoopenmp-relocatable-target"), +flagpd1("fnoopenmp-use-tls"), +flagpd1("fno-xray-always-emit-customevents"), +flagpd1("fno-xray-always-emit-typedevents"), +flagpd1("fno-xray-instrument"), +flagpd1("fnoxray-link-deps"), +joinpd1("fobjc-abi-version="), +flagpd1("fobjc-arc"), +joinpd1("fobjc-arc-cxxlib="), +flagpd1("fobjc-arc-exceptions"), +flagpd1("fobjc-atdefs"), +flagpd1("fobjc-call-cxx-cdtors"), +flagpd1("fobjc-convert-messages-to-runtime-calls"), +joinpd1("fobjc-dispatch-method="), +flagpd1("fobjc-exceptions"), +flagpd1("fobjc-gc"), +flagpd1("fobjc-gc-only"), +flagpd1("fobjc-infer-related-result-type"), +flagpd1("fobjc-legacy-dispatch"), +flagpd1("fobjc-link-runtime"), +flagpd1("fobjc-new-property"), +flagpd1("fobjc-nonfragile-abi"), +joinpd1("fobjc-nonfragile-abi-version="), +joinpd1("fobjc-runtime="), +flagpd1("fobjc-runtime-has-weak"), +flagpd1("fobjc-sender-dependent-dispatch"), +flagpd1("fobjc-subscripting-legacy-runtime"), +flagpd1("fobjc-weak"), +flagpd1("fomit-frame-pointer"), +flagpd1("fopenmp"), +joinpd1("fopenmp="), +joinpd1("fopenmp-cuda-blocks-per-sm="), +flagpd1("fopenmp-cuda-force-full-runtime"), +flagpd1("fopenmp-cuda-mode"), +joinpd1("fopenmp-cuda-number-of-sm="), +joinpd1("fopenmp-cuda-teams-reduction-recs-num="), +flagpd1("fopenmp-enable-irbuilder"), +sepd1("fopenmp-host-ir-file-path"), +flagpd1("fopenmp-is-device"), +flagpd1("fopenmp-optimistic-collapse"), +flagpd1("fopenmp-relocatable-target"), +flagpd1("fopenmp-simd"), +.{ + .name = "fopenmp-targets=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fopenmp-use-tls"), +joinpd1("fopenmp-version="), +sepd1("foperator-arrow-depth"), +joinpd1("foperator-arrow-depth="), +joinpd1("foptimization-record-file="), +joinpd1("foptimization-record-passes="), +flagpd1("foptimize-sibling-calls"), +flagpd1("force_cpusubtype_ALL"), +flagpd1("force_flat_namespace"), +sepd1("force_load"), +joinpd1("fforce-addr"), +flagpd1("forder-file-instrumentation"), +joinpd1("foutput-class-dir="), +joinpd1("foverride-record-layout="), +flagpd1("fpack-struct"), +joinpd1("fpack-struct="), +flagpd1("fpadding-on-unsigned-fixed-point"), +flagpd1("fparse-all-comments"), +flagpd1("fpascal-strings"), +joinpd1("fpass-plugin="), +joinpd1("fpatchable-function-entry="), +joinpd1("fpatchable-function-entry-offset="), +flagpd1("fpcc-struct-return"), +flagpd1("fpch-preprocess"), +flagpd1("fpch-validate-input-files-content"), +flagpd1("fpic"), +flagpd1("fpie"), +flagpd1("fplt"), +joinpd1("fplugin="), +joinpd1("fprebuilt-module-path="), +flagpd1("fpreserve-as-comments"), +flagpd1("fpreserve-vec3-type"), +flagpd1("fprofile-arcs"), +joinpd1("fprofile-dir="), +joinpd1("fprofile-exclude-files="), +joinpd1("fprofile-filter-files="), +flagpd1("fprofile-generate"), +joinpd1("fprofile-generate="), +flagpd1("fprofile-instr-generate"), +joinpd1("fprofile-instr-generate="), +flagpd1("fprofile-instr-use"), +joinpd1("fprofile-instr-use="), +joinpd1("fprofile-instrument="), +joinpd1("fprofile-instrument-path="), +joinpd1("fprofile-instrument-use-path="), +sepd1("fprofile-remapping-file"), +joinpd1("fprofile-remapping-file="), +flagpd1("fprofile-sample-accurate"), +flagpd1("fprofile-sample-use"), +joinpd1("fprofile-sample-use="), +flagpd1("fprofile-use"), +joinpd1("fprofile-use="), +sepd1("framework"), +joinpd1("frandom-seed="), +flagpd1("freciprocal-math"), +flagpd1("frecord-command-line"), +joinpd1("frecord-marker="), +flagpd1("ffree-form"), +flagpd1("fno-free-form"), +flagpd1("freg-struct-return"), +flagpd1("fregister-global-dtors-with-atexit"), +flagpd1("frelaxed-template-template-args"), +flagpd1("freroll-loops"), +flagpd1("fretain-comments-from-system-headers"), +flagpd1("frewrite-imports"), +flagpd1("frewrite-includes"), +sepd1("frewrite-map-file"), +joinpd1("frewrite-map-file="), +flagpd1("ffriend-injection"), +flagpd1("fno-friend-injection"), +flagpd1("ffrontend-optimize"), +flagpd1("fno-frontend-optimize"), +flagpd1("fropi"), +flagpd1("frounding-math"), +flagpd1("frtlib-add-rpath"), +flagpd1("frtti"), +flagpd1("frwpi"), +.{ + .name = "fsanitize=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fsanitize-address-field-padding="), +flagpd1("fsanitize-address-globals-dead-stripping"), +flagpd1("fsanitize-address-poison-custom-array-cookie"), +flagpd1("fsanitize-address-use-after-scope"), +flagpd1("fsanitize-address-use-odr-indicator"), +joinpd1("fsanitize-blacklist="), +flagpd1("fsanitize-cfi-canonical-jump-tables"), +flagpd1("fsanitize-cfi-cross-dso"), +flagpd1("fsanitize-cfi-icall-generalize-pointers"), +.{ + .name = "fsanitize-coverage=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fsanitize-coverage-8bit-counters"), +flagpd1("fsanitize-coverage-indirect-calls"), +flagpd1("fsanitize-coverage-inline-8bit-counters"), +flagpd1("fsanitize-coverage-no-prune"), +flagpd1("fsanitize-coverage-pc-table"), +flagpd1("fsanitize-coverage-stack-depth"), +flagpd1("fsanitize-coverage-trace-bb"), +flagpd1("fsanitize-coverage-trace-cmp"), +flagpd1("fsanitize-coverage-trace-div"), +flagpd1("fsanitize-coverage-trace-gep"), +flagpd1("fsanitize-coverage-trace-pc"), +flagpd1("fsanitize-coverage-trace-pc-guard"), +joinpd1("fsanitize-coverage-type="), +joinpd1("fsanitize-hwaddress-abi="), +flagpd1("fsanitize-link-c++-runtime"), +flagpd1("fsanitize-link-runtime"), +flagpd1("fsanitize-memory-track-origins"), +joinpd1("fsanitize-memory-track-origins="), +flagpd1("fsanitize-memory-use-after-dtor"), +flagpd1("fsanitize-minimal-runtime"), +flagpd1("fsanitize-recover"), +.{ + .name = "fsanitize-recover=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fsanitize-stats"), +joinpd1("fsanitize-system-blacklist="), +flagpd1("fsanitize-thread-atomics"), +flagpd1("fsanitize-thread-func-entry-exit"), +flagpd1("fsanitize-thread-memory-access"), +.{ + .name = "fsanitize-trap=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fsanitize-undefined-strip-path-components="), +flagpd1("fsanitize-undefined-trap-on-error"), +flagpd1("fsave-optimization-record"), +joinpd1("fsave-optimization-record="), +flagpd1("fseh-exceptions"), +flagpd1("fshort-enums"), +flagpd1("fshort-wchar"), +flagpd1("fshow-column"), +joinpd1("fshow-overloads="), +flagpd1("fshow-source-location"), +flagpd1("fsignaling-math"), +flagpd1("fsigned-bitfields"), +flagpd1("fsigned-char"), +flagpd1("fsigned-wchar"), +flagpd1("fsigned-zeros"), +flagpd1("fsized-deallocation"), +flagpd1("fsjlj-exceptions"), +flagpd1("fslp-vectorize"), +flagpd1("fspell-checking"), +sepd1("fspell-checking-limit"), +joinpd1("fspell-checking-limit="), +flagpd1("fsplit-dwarf-inlining"), +flagpd1("fsplit-lto-unit"), +flagpd1("fsplit-stack"), +flagpd1("fstack-protector"), +flagpd1("fstack-protector-all"), +flagpd1("fstack-protector-strong"), +flagpd1("fstack-size-section"), +flagpd1("fstandalone-debug"), +flagpd1("fstrict-aliasing"), +flagpd1("fstrict-enums"), +flagpd1("fstrict-float-cast-overflow"), +flagpd1("fstrict-overflow"), +flagpd1("fstrict-return"), +flagpd1("fstrict-vtable-pointers"), +flagpd1("fstruct-path-tbaa"), +flagpd1("fsycl-is-device"), +joinpd1("fsymbol-partition="), +flagpd1("fsyntax-only"), +sepd1("ftabstop"), +joinpd1("ftabstop="), +sepd1("ftemplate-backtrace-limit"), +joinpd1("ftemplate-backtrace-limit="), +sepd1("ftemplate-depth"), +joinpd1("ftemplate-depth-"), +joinpd1("ftemplate-depth="), +flagpd1("ftest-coverage"), +joinpd1("ftest-module-file-extension="), +joinpd1("fthin-link-bitcode="), +joinpd1("fthinlto-index="), +flagpd1("fthreadsafe-statics"), +flagpd1("ftime-report"), +flagpd1("ftime-trace"), +joinpd1("ftime-trace-granularity="), +joinpd1("ftls-model="), +joinpd1("ftrap-function="), +flagpd1("ftrapping-math"), +flagpd1("ftrapv"), +sepd1("ftrapv-handler"), +joinpd1("ftrapv-handler="), +flagpd1("ftrigraphs"), +joinpd1("ftrivial-auto-var-init="), +sepd1("ftype-visibility"), +sepd1("function-alignment"), +flagpd1("ffunction-attribute-list"), +flagpd1("fno-function-attribute-list"), +flagpd1("funique-section-names"), +flagpd1("funit-at-a-time"), +flagpd1("funknown-anytype"), +flagpd1("funroll-loops"), +flagpd1("funsafe-math-optimizations"), +flagpd1("funsigned-bitfields"), +flagpd1("funsigned-char"), +flagpd1("funwind-tables"), +flagpd1("fuse-cxa-atexit"), +flagpd1("fuse-init-array"), +joinpd1("fuse-ld="), +flagpd1("fuse-line-directives"), +flagpd1("fuse-register-sized-bitfield-access"), +flagpd1("fvalidate-ast-input-files-content"), +joinpd1("fveclib="), +flagpd1("fvectorize"), +flagpd1("fverbose-asm"), +flagpd1("fvirtual-function-elimination"), +sepd1("fvisibility"), +joinpd1("fvisibility="), +flagpd1("fvisibility-global-new-delete-hidden"), +flagpd1("fvisibility-inlines-hidden"), +flagpd1("fvisibility-ms-compat"), +flagpd1("fwasm-exceptions"), +joinpd1("fwchar-type="), +flagpd1("fwhole-program-vtables"), +flagpd1("fwrapv"), +flagpd1("fwritable-strings"), +flagpd1("fxray-always-emit-customevents"), +flagpd1("fxray-always-emit-typedevents"), +jspd1("fxray-always-instrument="), +jspd1("fxray-attr-list="), +jspd1("fxray-instruction-threshold"), +jspd1("fxray-instruction-threshold="), +flagpd1("fxray-instrument"), +jspd1("fxray-instrumentation-bundle="), +flagpd1("fxray-link-deps"), +jspd1("fxray-modes="), +jspd1("fxray-never-instrument="), +flagpd1("fzero-initialized-in-bss"), +flagpd1("fzvector"), +flagpd1("g0"), +flagpd1("g1"), +flagpd1("g2"), +flagpd1("g3"), +flagpd1("g"), +.{ + .name = "gcc-toolchain=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("gcc-toolchain"), +flagpd1("gcodeview"), +flagpd1("gcodeview-ghash"), +joinpd1("gcoff"), +flagpd1("gcolumn-info"), +flagpd1("fgcse-after-reload"), +flagpd1("fno-gcse-after-reload"), +flagpd1("fgcse"), +flagpd1("fno-gcse"), +flagpd1("fgcse-las"), +flagpd1("fno-gcse-las"), +flagpd1("fgcse-sm"), +flagpd1("fno-gcse-sm"), +flagpd1("gdwarf"), +flagpd1("gdwarf-2"), +flagpd1("gdwarf-3"), +flagpd1("gdwarf-4"), +flagpd1("gdwarf-5"), +flagpd1("gdwarf-aranges"), +flagpd1("gembed-source"), +sepd1("gen-cdb-fragment-path"), +flagpd1("gen-reproducer"), +flagpd1("gfull"), +flagpd1("ggdb"), +flagpd1("ggdb0"), +flagpd1("ggdb1"), +flagpd1("ggdb2"), +flagpd1("ggdb3"), +flagpd1("ggnu-pubnames"), +flagpd1("ginline-line-tables"), +flagpd1("gline-directives-only"), +flagpd1("gline-tables-only"), +flagpd1("glldb"), +flagpd1("gmlt"), +flagpd1("gmodules"), +flagpd1("gno-codeview-ghash"), +flagpd1("gno-column-info"), +flagpd1("gno-embed-source"), +flagpd1("gno-gnu-pubnames"), +flagpd1("gno-inline-line-tables"), +flagpd1("gno-pubnames"), +flagpd1("gno-record-command-line"), +flagpd1("gno-strict-dwarf"), +flagpd1("fgnu"), +flagpd1("fno-gnu"), +.{ + .name = "gpu-max-threads-per-block=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("gpubnames"), +flagpd1("grecord-command-line"), +flagpd1("gsce"), +flagpd1("gsplit-dwarf"), +joinpd1("gsplit-dwarf="), +joinpd1("gstabs"), +flagpd1("gstrict-dwarf"), +flagpd1("gtoggle"), +flagpd1("gused"), +joinpd1("gvms"), +joinpd1("gxcoff"), +flagpd1("gz"), +joinpd1("gz="), +sepd1("header-include-file"), +joinpd1("headerpad_max_install_names"), +.{ + .name = "help", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "hip-device-lib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "hip-device-lib-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "hip-link", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +jspd1("idirafter"), +jspd1("iframework"), +jspd1("iframeworkwithsysroot"), +.{ + .name = "imacros", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("image_base"), +flagpd1("fimplement-inlines"), +flagpd1("fno-implement-inlines"), +flagpd1("fimplicit-none"), +flagpd1("fno-implicit-none"), +flagpd1("fimplicit-templates"), +flagpd1("fno-implicit-templates"), +sepd1("imultilib"), +.{ + .name = "include", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("include-pch"), +flagpd1("index-header-map"), +sepd1("init"), +flagpd1("finit-local-zero"), +flagpd1("fno-init-local-zero"), +flagpd1("init-only"), +flagpd1("finline-functions-called-once"), +flagpd1("fno-inline-functions-called-once"), +flagpd1("finline-small-functions"), +flagpd1("fno-inline-small-functions"), +sepd1("install_name"), +flagpd1("finteger-4-integer-8"), +flagpd1("fno-integer-4-integer-8"), +jspd1("interface-stub-version="), +jspd1("internal-externc-isystem"), +jspd1("internal-isystem"), +flagpd1("fintrinsic-modules-path"), +flagpd1("fno-intrinsic-modules-path"), +flagpd1("fipa-cp"), +flagpd1("fno-ipa-cp"), +jspd1("iprefix"), +jspd1("iquote"), +jspd1("isysroot"), +jspd1("isystem"), +jspd1("isystem-after"), +jspd1("ivfsoverlay"), +flagpd1("fivopts"), +flagpd1("fno-ivopts"), +jspd1("iwithprefix"), +jspd1("iwithprefixbefore"), +jspd1("iwithsysroot"), +flagpd1("keep_private_externs"), +.{ + .name = "l", + .syntax = .joined_or_separate, + .zig_equivalent = .l, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("lazy_framework"), +sepd1("lazy_library"), +.{ + .name = "libomptarget-nvptx-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "linker-option=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("load"), +flagpd1("m16"), +flagpd1("m32"), +flagpd1("m3dnow"), +flagpd1("m3dnowa"), +flagpd1("m64"), +flagpd1("m80387"), +joinpd1("mabi="), +flagpd1("mabi=ieeelongdouble"), +flagpd1("mabicalls"), +joinpd1("mabs="), +flagpd1("madx"), +flagpd1("maes"), +sepd1("main-file-name"), +.{ + .name = "malign-branch=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("malign-branch-boundary="), +joinpd1("malign-branch-prefix-size="), +flagpd1("malign-double"), +joinpd1("malign-functions="), +joinpd1("malign-jumps="), +joinpd1("malign-loops="), +flagpd1("maltivec"), +joinpd1("mamdgpu-debugger-abi="), +joinpd1("mappletvos-version-min="), +joinpd1("mappletvsimulator-version-min="), +joinpd1("march="), +flagpd1("marm"), +joinpd1("masm="), +flagpd1("masm-verbose"), +flagpd1("massembler-fatal-warnings"), +flagpd1("massembler-no-warn"), +flagpd1("matomics"), +flagpd1("mavx"), +flagpd1("mavx2"), +flagpd1("mavx512bf16"), +flagpd1("mavx512bitalg"), +flagpd1("mavx512bw"), +flagpd1("mavx512cd"), +flagpd1("mavx512dq"), +flagpd1("mavx512er"), +flagpd1("mavx512f"), +flagpd1("mavx512ifma"), +flagpd1("mavx512pf"), +flagpd1("mavx512vbmi"), +flagpd1("mavx512vbmi2"), +flagpd1("mavx512vl"), +flagpd1("mavx512vnni"), +flagpd1("mavx512vp2intersect"), +flagpd1("mavx512vpopcntdq"), +flagpd1("fmax-identifier-length"), +flagpd1("fno-max-identifier-length"), +flagpd1("mbackchain"), +flagpd1("mbig-endian"), +flagpd1("mbmi"), +flagpd1("mbmi2"), +flagpd1("mbranch-likely"), +joinpd1("mbranch-protection="), +flagpd1("mbranch-target-enforce"), +flagpd1("mbranches-within-32B-boundaries"), +flagpd1("mbulk-memory"), +flagpd1("mcheck-zero-division"), +flagpd1("mcldemote"), +flagpd1("mclflushopt"), +flagpd1("mclwb"), +flagpd1("mclzero"), +joinpd1("mcmodel="), +flagpd1("mcmodel=medany"), +flagpd1("mcmodel=medlow"), +flagpd1("mcmpb"), +flagpd1("mcmse"), +sepd1("mcode-model"), +flagpd1("mcode-object-v3"), +joinpd1("mcompact-branches="), +joinpd1("mconsole"), +flagpd1("mconstant-cfstrings"), +flagpd1("mconstructor-aliases"), +joinpd1("mcpu="), +flagpd1("mcpu=?"), +flagpd1("mcrbits"), +flagpd1("mcrc"), +flagpd1("mcumode"), +flagpd1("mcx16"), +sepd1("mdebug-pass"), +joinpd1("mdefault-build-attributes"), +flagpd1("mdirect-move"), +flagpd1("mdisable-tail-calls"), +joinpd1("mdll"), +flagpd1("mdouble-float"), +flagpd1("mdsp"), +flagpd1("mdspr2"), +joinpd1("mdynamic-no-pic"), +sepd1("meabi"), +flagpd1("membedded-data"), +flagpd1("menable-no-infs"), +flagpd1("menable-no-nans"), +flagpd1("menable-unsafe-fp-math"), +flagpd1("menqcmd"), +flagpd1("fmerge-constants"), +flagpd1("fno-merge-constants"), +flagpd1("mexception-handling"), +flagpd1("mexecute-only"), +flagpd1("mextern-sdata"), +flagpd1("mf16c"), +flagpd1("mfancy-math-387"), +flagpd1("mfentry"), +flagpd1("mfix-and-continue"), +flagpd1("mfix-cortex-a53-835769"), +flagpd1("mfloat128"), +sepd1("mfloat-abi"), +joinpd1("mfloat-abi="), +flagpd1("mfma"), +flagpd1("mfma4"), +flagpd1("mfp32"), +flagpd1("mfp64"), +sepd1("mfpmath"), +joinpd1("mfpmath="), +flagpd1("mfprnd"), +joinpd1("mfpu="), +flagpd1("mfpxx"), +joinpd1("mframe-pointer="), +flagpd1("mfsgsbase"), +flagpd1("mfxsr"), +flagpd1("mgeneral-regs-only"), +flagpd1("mgfni"), +flagpd1("mginv"), +flagpd1("mglibc"), +flagpd1("mglobal-merge"), +flagpd1("mgpopt"), +flagpd1("mhard-float"), +flagpd1("mhvx"), +joinpd1("mhvx="), +joinpd1("mhvx-length="), +flagpd1("mhtm"), +joinpd1("mhwdiv="), +joinpd1("mhwmult="), +flagpd1("miamcu"), +flagpd1("mieee-fp"), +flagpd1("mieee-rnd-near"), +flagpd1("migrate"), +flagpd1("no-finalize-removal"), +flagpd1("no-ns-alloc-error"), +flagpd1("mimplicit-float"), +joinpd1("mimplicit-it="), +flagpd1("mincremental-linker-compatible"), +joinpd1("mindirect-jump="), +flagpd1("minline-all-stringops"), +flagpd1("minvariant-function-descriptors"), +flagpd1("minvpcid"), +joinpd1("mios-simulator-version-min="), +joinpd1("mios-version-min="), +joinpd1("miphoneos-version-min="), +joinpd1("miphonesimulator-version-min="), +flagpd1("mips1"), +flagpd1("mips16"), +flagpd1("mips2"), +flagpd1("mips3"), +flagpd1("mips32"), +flagpd1("mips32r2"), +flagpd1("mips32r3"), +flagpd1("mips32r5"), +flagpd1("mips32r6"), +flagpd1("mips4"), +flagpd1("mips5"), +flagpd1("mips64"), +flagpd1("mips64r2"), +flagpd1("mips64r3"), +flagpd1("mips64r5"), +flagpd1("mips64r6"), +flagpd1("misel"), +flagpd1("mkernel"), +flagpd1("mldc1-sdc1"), +sepd1("mlimit-float-precision"), +sepd1("mlink-bitcode-file"), +sepd1("mlink-builtin-bitcode"), +sepd1("mlink-cuda-bitcode"), +joinpd1("mlinker-version="), +flagpd1("mlittle-endian"), +sepd1("mllvm"), +flagpd1("mlocal-sdata"), +flagpd1("mlong-calls"), +flagpd1("mlong-double-128"), +flagpd1("mlong-double-64"), +flagpd1("mlong-double-80"), +flagpd1("mlongcall"), +flagpd1("mlwp"), +flagpd1("mlzcnt"), +joinpd1("mmacos-version-min="), +joinpd1("mmacosx-version-min="), +flagpd1("mmadd4"), +joinpd1("mmcu="), +flagpd1("mmemops"), +flagpd1("mmfcrf"), +flagpd1("mmfocrf"), +flagpd1("mmicromips"), +flagpd1("mmmx"), +flagpd1("mmovbe"), +flagpd1("mmovdir64b"), +flagpd1("mmovdiri"), +flagpd1("mmpx"), +flagpd1("mms-bitfields"), +flagpd1("mmsa"), +flagpd1("mmt"), +flagpd1("mmultivalue"), +flagpd1("mmutable-globals"), +flagpd1("mmwaitx"), +joinpd1("mnan="), +flagpd1("mno-3dnow"), +flagpd1("mno-3dnowa"), +flagpd1("mno-80387"), +flagpd1("mno-abicalls"), +flagpd1("mno-adx"), +flagpd1("mno-aes"), +flagpd1("mno-altivec"), +flagpd1("mno-atomics"), +flagpd1("mno-avx"), +flagpd1("mno-avx2"), +flagpd1("mno-avx512bf16"), +flagpd1("mno-avx512bitalg"), +flagpd1("mno-avx512bw"), +flagpd1("mno-avx512cd"), +flagpd1("mno-avx512dq"), +flagpd1("mno-avx512er"), +flagpd1("mno-avx512f"), +flagpd1("mno-avx512ifma"), +flagpd1("mno-avx512pf"), +flagpd1("mno-avx512vbmi"), +flagpd1("mno-avx512vbmi2"), +flagpd1("mno-avx512vl"), +flagpd1("mno-avx512vnni"), +flagpd1("mno-avx512vp2intersect"), +flagpd1("mno-avx512vpopcntdq"), +flagpd1("mno-backchain"), +flagpd1("mno-bmi"), +flagpd1("mno-bmi2"), +flagpd1("mno-branch-likely"), +flagpd1("mno-bulk-memory"), +flagpd1("mno-check-zero-division"), +flagpd1("mno-cldemote"), +flagpd1("mno-clflushopt"), +flagpd1("mno-clwb"), +flagpd1("mno-clzero"), +flagpd1("mno-cmpb"), +flagpd1("mno-code-object-v3"), +flagpd1("mno-constant-cfstrings"), +flagpd1("mno-crbits"), +flagpd1("mno-crc"), +flagpd1("mno-cumode"), +flagpd1("mno-cx16"), +joinpd1("mno-default-build-attributes"), +flagpd1("mno-dsp"), +flagpd1("mno-dspr2"), +flagpd1("mno-embedded-data"), +flagpd1("mno-enqcmd"), +flagpd1("mno-exception-handling"), +flagpd1("mnoexecstack"), +flagpd1("mno-execute-only"), +flagpd1("mno-extern-sdata"), +flagpd1("mno-f16c"), +flagpd1("mno-fix-cortex-a53-835769"), +flagpd1("mno-float128"), +flagpd1("mno-fma"), +flagpd1("mno-fma4"), +flagpd1("mno-fprnd"), +flagpd1("mno-fsgsbase"), +flagpd1("mno-fxsr"), +flagpd1("mno-gfni"), +flagpd1("mno-ginv"), +flagpd1("mno-global-merge"), +flagpd1("mno-gpopt"), +flagpd1("mno-hvx"), +flagpd1("mno-htm"), +flagpd1("mno-iamcu"), +flagpd1("mno-implicit-float"), +flagpd1("mno-incremental-linker-compatible"), +flagpd1("mno-inline-all-stringops"), +flagpd1("mno-invariant-function-descriptors"), +flagpd1("mno-invpcid"), +flagpd1("mno-isel"), +flagpd1("mno-ldc1-sdc1"), +flagpd1("mno-local-sdata"), +flagpd1("mno-long-calls"), +flagpd1("mno-longcall"), +flagpd1("mno-lwp"), +flagpd1("mno-lzcnt"), +flagpd1("mno-madd4"), +flagpd1("mno-memops"), +flagpd1("mno-mfcrf"), +flagpd1("mno-mfocrf"), +flagpd1("mno-micromips"), +flagpd1("mno-mips16"), +flagpd1("mno-mmx"), +flagpd1("mno-movbe"), +flagpd1("mno-movdir64b"), +flagpd1("mno-movdiri"), +flagpd1("mno-movt"), +flagpd1("mno-mpx"), +flagpd1("mno-ms-bitfields"), +flagpd1("mno-msa"), +flagpd1("mno-mt"), +flagpd1("mno-multivalue"), +flagpd1("mno-mutable-globals"), +flagpd1("mno-mwaitx"), +flagpd1("mno-neg-immediates"), +flagpd1("mno-nontrapping-fptoint"), +flagpd1("mno-nvj"), +flagpd1("mno-nvs"), +flagpd1("mno-odd-spreg"), +flagpd1("mno-omit-leaf-frame-pointer"), +flagpd1("mno-outline"), +flagpd1("mno-packed-stack"), +flagpd1("mno-packets"), +flagpd1("mno-pascal-strings"), +flagpd1("mno-pclmul"), +flagpd1("mno-pconfig"), +flagpd1("mno-pie-copy-relocations"), +flagpd1("mno-pku"), +flagpd1("mno-popcnt"), +flagpd1("mno-popcntd"), +flagpd1("mno-power8-vector"), +flagpd1("mno-power9-vector"), +flagpd1("mno-prefetchwt1"), +flagpd1("mno-prfchw"), +flagpd1("mno-ptwrite"), +flagpd1("mno-pure-code"), +flagpd1("mno-qpx"), +flagpd1("mno-rdpid"), +flagpd1("mno-rdrnd"), +flagpd1("mno-rdseed"), +flagpd1("mno-red-zone"), +flagpd1("mno-reference-types"), +flagpd1("mno-relax"), +flagpd1("mno-relax-all"), +flagpd1("mno-relax-pic-calls"), +flagpd1("mno-restrict-it"), +flagpd1("mno-retpoline"), +flagpd1("mno-retpoline-external-thunk"), +flagpd1("mno-rtd"), +flagpd1("mno-rtm"), +flagpd1("mno-sahf"), +flagpd1("mno-save-restore"), +flagpd1("mno-sgx"), +flagpd1("mno-sha"), +flagpd1("mno-shstk"), +flagpd1("mno-sign-ext"), +flagpd1("mno-simd128"), +flagpd1("mno-soft-float"), +flagpd1("mno-spe"), +flagpd1("mno-speculative-load-hardening"), +flagpd1("mno-sram-ecc"), +flagpd1("mno-sse"), +flagpd1("mno-sse2"), +flagpd1("mno-sse3"), +flagpd1("mno-sse4"), +flagpd1("mno-sse4.1"), +flagpd1("mno-sse4.2"), +flagpd1("mno-sse4a"), +flagpd1("mno-ssse3"), +flagpd1("mno-stack-arg-probe"), +flagpd1("mno-stackrealign"), +flagpd1("mno-tail-call"), +flagpd1("mno-tbm"), +flagpd1("mno-thumb"), +flagpd1("mno-tls-direct-seg-refs"), +flagpd1("mno-unaligned-access"), +flagpd1("mno-unimplemented-simd128"), +flagpd1("mno-vaes"), +flagpd1("mno-virt"), +flagpd1("mno-vpclmulqdq"), +flagpd1("mno-vsx"), +flagpd1("mno-vx"), +flagpd1("mno-vzeroupper"), +flagpd1("mno-waitpkg"), +flagpd1("mno-warn-nonportable-cfstrings"), +flagpd1("mno-wavefrontsize64"), +flagpd1("mno-wbnoinvd"), +flagpd1("mno-x87"), +flagpd1("mno-xgot"), +flagpd1("mno-xnack"), +flagpd1("mno-xop"), +flagpd1("mno-xsave"), +flagpd1("mno-xsavec"), +flagpd1("mno-xsaveopt"), +flagpd1("mno-xsaves"), +flagpd1("mno-zero-initialized-in-bss"), +flagpd1("mno-zvector"), +flagpd1("mnocrc"), +flagpd1("mno-direct-move"), +flagpd1("mnontrapping-fptoint"), +flagpd1("mnop-mcount"), +flagpd1("mno-crypto"), +flagpd1("mnvj"), +flagpd1("mnvs"), +flagpd1("modd-spreg"), +sepd1("module-dependency-dir"), +flagpd1("module-file-deps"), +flagpd1("module-file-info"), +flagpd1("fmodule-private"), +flagpd1("fno-module-private"), +flagpd1("fmodulo-sched-allow-regmoves"), +flagpd1("fno-modulo-sched-allow-regmoves"), +flagpd1("fmodulo-sched"), +flagpd1("fno-modulo-sched"), +flagpd1("momit-leaf-frame-pointer"), +joinpd1("moslib="), +flagpd1("moutline"), +flagpd1("mpacked-stack"), +flagpd1("mpackets"), +flagpd1("mpascal-strings"), +flagpd1("mpclmul"), +flagpd1("mpconfig"), +flagpd1("mpie-copy-relocations"), +flagpd1("mpku"), +flagpd1("mpopcnt"), +flagpd1("mpopcntd"), +flagpd1("mcrypto"), +flagpd1("mpower8-vector"), +flagpd1("mpower9-vector"), +joinpd1("mprefer-vector-width="), +flagpd1("mprefetchwt1"), +flagpd1("mprfchw"), +flagpd1("mptwrite"), +flagpd1("mpure-code"), +flagpd1("mqdsp6-compat"), +flagpd1("mqpx"), +flagpd1("mrdpid"), +flagpd1("mrdrnd"), +flagpd1("mrdseed"), +flagpd1("mreassociate"), +flagpd1("mrecip"), +.{ + .name = "mrecip=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("mrecord-mcount"), +flagpd1("mred-zone"), +flagpd1("mreference-types"), +sepd1("mregparm"), +joinpd1("mregparm="), +flagpd1("mrelax"), +flagpd1("mrelax-all"), +flagpd1("mrelax-pic-calls"), +.{ + .name = "mrelax-relocations", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("mrelocation-model"), +flagpd1("mrestrict-it"), +flagpd1("mretpoline"), +flagpd1("mretpoline-external-thunk"), +flagpd1("mrtd"), +flagpd1("mrtm"), +flagpd1("msahf"), +flagpd1("msave-restore"), +flagpd1("msave-temp-labels"), +flagpd1("msecure-plt"), +flagpd1("msgx"), +flagpd1("msha"), +flagpd1("mshstk"), +flagpd1("msign-ext"), +joinpd1("msign-return-address="), +joinpd1("msign-return-address-key="), +flagpd1("msimd128"), +flagpd1("msingle-float"), +joinpd1("msmall-data-threshold="), +flagpd1("msoft-float"), +flagpd1("mspe"), +flagpd1("mspeculative-load-hardening"), +flagpd1("msram-ecc"), +flagpd1("msse"), +flagpd1("msse2"), +flagpd1("msse3"), +flagpd1("msse4"), +flagpd1("msse4.1"), +flagpd1("msse4.2"), +flagpd1("msse4a"), +flagpd1("mssse3"), +joinpd1("mstack-alignment="), +flagpd1("mstack-arg-probe"), +joinpd1("mstack-probe-size="), +flagpd1("mstackrealign"), +flagpd1("mstrict-align"), +sepd1("mt-migrate-directory"), +flagpd1("mtail-call"), +flagpd1("mtbm"), +sepd1("mthread-model"), +joinpd1("mthreads"), +flagpd1("mthumb"), +flagpd1("mtls-direct-seg-refs"), +joinpd1("mtls-size="), +sepd1("mtp"), +joinpd1("mtp="), +joinpd1("mtune="), +flagpd1("mtune=?"), +joinpd1("mtvos-simulator-version-min="), +joinpd1("mtvos-version-min="), +flagpd1("muclibc"), +flagpd1("multi_module"), +sepd1("multiply_defined"), +sepd1("multiply_defined_unused"), +flagpd1("munaligned-access"), +joinpd1("municode"), +flagpd1("munimplemented-simd128"), +flagpd1("munwind-tables"), +flagpd1("mv5"), +flagpd1("mv55"), +flagpd1("mv60"), +flagpd1("mv62"), +flagpd1("mv65"), +flagpd1("mv66"), +flagpd1("mvaes"), +flagpd1("mvirt"), +flagpd1("mvpclmulqdq"), +flagpd1("mvsx"), +flagpd1("mvx"), +flagpd1("mvzeroupper"), +flagpd1("mwaitpkg"), +flagpd1("mwarn-nonportable-cfstrings"), +joinpd1("mwatchos-simulator-version-min="), +joinpd1("mwatchos-version-min="), +joinpd1("mwatchsimulator-version-min="), +flagpd1("mwavefrontsize64"), +flagpd1("mwbnoinvd"), +joinpd1("mwindows"), +flagpd1("mx32"), +flagpd1("mx87"), +flagpd1("mxgot"), +flagpd1("mxnack"), +flagpd1("mxop"), +flagpd1("mxsave"), +flagpd1("mxsavec"), +flagpd1("mxsaveopt"), +flagpd1("mxsaves"), +flagpd1("mzvector"), +flagpd1("n"), +flagpd1("new-struct-path-tbaa"), +flagpd1("no_dead_strip_inits_and_terms"), +flagpd1("no-canonical-prefixes"), +flagpd1("no-code-completion-globals"), +flagpd1("no-code-completion-ns-level-decls"), +flagpd1("no-cpp-precomp"), +.{ + .name = "no-cuda-gpu-arch=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-cuda-include-ptx=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-cuda-noopt-device-debug", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-cuda-version-check", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("no-emit-llvm-uselists"), +flagpd1("no-implicit-float"), +.{ + .name = "no-integrated-cpp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-pedantic", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("no-pie"), +flagpd1("no-pthread"), +flagpd1("no-struct-path-tbaa"), +.{ + .name = "no-system-header-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("nobuiltininc"), +flagpd1("nocpp"), +flagpd1("nocudainc"), +flagpd1("nodefaultlibs"), +flagpd1("nofixprebinding"), +flagpd1("nogpulib"), +flagpd1("nolibc"), +flagpd1("nomultidefs"), +flagpd1("fnon-call-exceptions"), +flagpd1("fno-non-call-exceptions"), +flagpd1("nopie"), +flagpd1("noprebind"), +flagpd1("noprofilelib"), +flagpd1("noseglinkedit"), +flagpd1("nostartfiles"), +flagpd1("nostdinc"), +flagpd1("nostdinc++"), +flagpd1("nostdlib"), +flagpd1("nostdlibinc"), +flagpd1("nostdlib++"), +flagpd1("nostdsysteminc"), +.{ + .name = "o", + .syntax = .joined_or_separate, + .zig_equivalent = .o, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("objc-isystem"), +flagpd1("objcmt-atomic-property"), +flagpd1("objcmt-migrate-all"), +flagpd1("objcmt-migrate-annotation"), +flagpd1("objcmt-migrate-designated-init"), +flagpd1("objcmt-migrate-instancetype"), +flagpd1("objcmt-migrate-literals"), +flagpd1("objcmt-migrate-ns-macros"), +flagpd1("objcmt-migrate-property"), +flagpd1("objcmt-migrate-property-dot-syntax"), +flagpd1("objcmt-migrate-protocol-conformance"), +flagpd1("objcmt-migrate-readonly-property"), +flagpd1("objcmt-migrate-readwrite-property"), +flagpd1("objcmt-migrate-subscripting"), +flagpd1("objcmt-ns-nonatomic-iosonly"), +flagpd1("objcmt-returns-innerpointer-property"), +joinpd1("objcmt-whitelist-dir-path="), +jspd1("objcxx-isystem"), +flagpd1("object"), +sepd1("opt-record-file"), +sepd1("opt-record-format"), +sepd1("opt-record-passes"), +sepd1("output-asm-variant"), +flagpd1("p"), +flagpd1("fpack-derived"), +flagpd1("fno-pack-derived"), +jspd1("pagezero_size"), +.{ + .name = "pass-exit-codes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("pch-through-hdrstop-create"), +flagpd1("pch-through-hdrstop-use"), +joinpd1("pch-through-header="), +.{ + .name = "pedantic", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "pedantic-errors", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fpeel-loops"), +flagpd1("fno-peel-loops"), +flagpd1("fpermissive"), +flagpd1("fno-permissive"), +flagpd1("pg"), +flagpd1("pic-is-pie"), +sepd1("pic-level"), +flagpd1("pie"), +.{ + .name = "pipe", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("plugin"), +.{ + .name = "plugin-arg-", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("preamble-bytes="), +flagpd1("prebind"), +flagpd1("prebind_all_twolevel_modules"), +flagpd1("fprefetch-loop-arrays"), +flagpd1("fno-prefetch-loop-arrays"), +flagpd1("preload"), +flagpd1("print-dependency-directives-minimized-source"), +.{ + .name = "print-effective-triple", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-file-name=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("print-ivar-layout"), +.{ + .name = "print-libgcc-file-name", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-multi-directory", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-multi-lib", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-multi-os-directory", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("print-preamble"), +.{ + .name = "print-prog-name=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-resource-dir", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-search-dirs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("print-stats"), +.{ + .name = "print-supported-cpus", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-target-triple", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fprintf"), +flagpd1("fno-printf"), +flagpd1("private_bundle"), +flagpd1("fprofile-correction"), +flagpd1("fno-profile-correction"), +flagpd1("fprofile"), +flagpd1("fno-profile"), +flagpd1("fprofile-generate-sampling"), +flagpd1("fno-profile-generate-sampling"), +flagpd1("fprofile-reusedist"), +flagpd1("fno-profile-reusedist"), +flagpd1("fprofile-values"), +flagpd1("fno-profile-values"), +flagpd1("fprotect-parens"), +flagpd1("fno-protect-parens"), +flagpd1("pthread"), +flagpd1("pthreads"), +.{ + .name = "ptxas-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("r"), +flagpd1("frange-check"), +flagpd1("fno-range-check"), +flagpd1("rdynamic"), +sepd1("read_only_relocs"), +flagpd1("freal-4-real-10"), +flagpd1("fno-real-4-real-10"), +flagpd1("freal-4-real-16"), +flagpd1("fno-real-4-real-16"), +flagpd1("freal-4-real-8"), +flagpd1("fno-real-4-real-8"), +flagpd1("freal-8-real-10"), +flagpd1("fno-real-8-real-10"), +flagpd1("freal-8-real-16"), +flagpd1("fno-real-8-real-16"), +flagpd1("freal-8-real-4"), +flagpd1("fno-real-8-real-4"), +flagpd1("frealloc-lhs"), +flagpd1("fno-realloc-lhs"), +sepd1("record-command-line"), +flagpd1("frecursive"), +flagpd1("fno-recursive"), +flagpd1("fregs-graph"), +flagpd1("fno-regs-graph"), +flagpd1("relaxed-aliasing"), +.{ + .name = "relocatable-pch", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("remap"), +sepd1("remap-file"), +flagpd1("frename-registers"), +flagpd1("fno-rename-registers"), +flagpd1("freorder-blocks"), +flagpd1("fno-reorder-blocks"), +flagpd1("frepack-arrays"), +flagpd1("fno-repack-arrays"), +sepd1("resource-dir"), +joinpd1("resource-dir="), +flagpd1("rewrite-legacy-objc"), +flagpd1("rewrite-macros"), +flagpd1("rewrite-objc"), +flagpd1("rewrite-test"), +flagpd1("fripa"), +flagpd1("fno-ripa"), +sepd1("rpath"), +.{ + .name = "rsp-quoting=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "rtlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("s"), +.{ + .name = "save-stats", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-stats=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-temps", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-temps=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fschedule-insns2"), +flagpd1("fno-schedule-insns2"), +flagpd1("fschedule-insns"), +flagpd1("fno-schedule-insns"), +flagpd1("fsecond-underscore"), +flagpd1("fno-second-underscore"), +.{ + .name = "sectalign", + .syntax = .{ .multi_arg = 3 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "sectcreate", + .syntax = .{ .multi_arg = 3 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "sectobjectsymbols", + .syntax = .{ .multi_arg = 2 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "sectorder", + .syntax = .{ .multi_arg = 3 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("fsee"), +flagpd1("fno-see"), +jspd1("seg1addr"), +sepd1("seg_addr_table"), +sepd1("seg_addr_table_filename"), +.{ + .name = "segaddr", + .syntax = .{ .multi_arg = 2 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "segcreate", + .syntax = .{ .multi_arg = 3 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("seglinkedit"), +.{ + .name = "segprot", + .syntax = .{ .multi_arg = 3 }, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("segs_read_"), +sepd1("segs_read_only_addr"), +sepd1("segs_read_write_addr"), +flagpd1("setup-static-analyzer"), +.{ + .name = "shared", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("shared-libgcc"), +flagpd1("shared-libsan"), +flagpd1("show-encoding"), +.{ + .name = "show-includes", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("show-inst"), +flagpd1("fsign-zero"), +flagpd1("fno-sign-zero"), +flagpd1("fsignaling-nans"), +flagpd1("fno-signaling-nans"), +flagpd1("single_module"), +flagpd1("fsingle-precision-constant"), +flagpd1("fno-single-precision-constant"), +flagpd1("fspec-constr-count"), +flagpd1("fno-spec-constr-count"), +.{ + .name = "specs", + .syntax = .separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "specs=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +sepd1("split-dwarf-file"), +sepd1("split-dwarf-output"), +flagpd1("split-stacks"), +flagpd1("fstack-arrays"), +flagpd1("fno-stack-arrays"), +flagpd1("fstack-check"), +flagpd1("fno-stack-check"), +sepd1("stack-protector"), +sepd1("stack-protector-buffer-size"), +.{ + .name = "static", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("static-define"), +flagpd1("static-libgcc"), +flagpd1("static-libgfortran"), +flagpd1("static-libsan"), +flagpd1("static-libstdc++"), +flagpd1("static-openmp"), +flagpd1("static-pie"), +joinpd1("stats-file="), +.{ + .name = "std=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +joinpd1("std-default="), +.{ + .name = "stdlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +jspd1("stdlib++-isystem"), +flagpd1("fstrength-reduce"), +flagpd1("fno-strength-reduce"), +jspd1("sub_library"), +jspd1("sub_umbrella"), +flagpd1("sys-header-deps"), +.{ + .name = "system-header-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("t"), +.{ + .name = "target=", + .syntax = .joined, + .zig_equivalent = .target, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +sepd1("target-abi"), +sepd1("target-cpu"), +sepd1("target-feature"), +.{ + .name = "target", + .syntax = .separate, + .zig_equivalent = .target, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +sepd1("target-linker-version"), +joinpd1("target-sdk-version="), +flagpd1("templight-dump"), +flagpd1("test-coverage"), +flagpd1("time"), +flagpd1("ftls-model"), +flagpd1("fno-tls-model"), +flagpd1("ftracer"), +flagpd1("fno-tracer"), +.{ + .name = "traditional", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "traditional-cpp", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("ftree-dce"), +flagpd1("fno-tree-dce"), +flagpd1("ftree_loop_im"), +flagpd1("fno-tree_loop_im"), +flagpd1("ftree_loop_ivcanon"), +flagpd1("fno-tree_loop_ivcanon"), +flagpd1("ftree_loop_linear"), +flagpd1("fno-tree_loop_linear"), +flagpd1("ftree-salias"), +flagpd1("fno-tree-salias"), +flagpd1("ftree-ter"), +flagpd1("fno-tree-ter"), +flagpd1("ftree-vectorizer-verbose"), +flagpd1("fno-tree-vectorizer-verbose"), +flagpd1("ftree-vrp"), +flagpd1("fno-tree-vrp"), +.{ + .name = "trigraphs", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("trim-egraph"), +sepd1("triple"), +joinpd1("triple="), +flagpd1("twolevel_namespace"), +flagpd1("twolevel_namespace_hints"), +jspd1("u"), +sepd1("umbrella"), +flagpd1("undef"), +jspd1("undefined"), +flagpd1("funderscoring"), +flagpd1("fno-underscoring"), +sepd1("unexported_symbols_list"), +flagpd1("funroll-all-loops"), +flagpd1("fno-unroll-all-loops"), +flagpd1("funsafe-loop-optimizations"), +flagpd1("fno-unsafe-loop-optimizations"), +flagpd1("funswitch-loops"), +flagpd1("fno-unswitch-loops"), +.{ + .name = "unwindlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +flagpd1("fuse-linker-plugin"), +flagpd1("fno-use-linker-plugin"), +flagpd1("v"), +flagpd1("fvariable-expansion-in-unroller"), +flagpd1("fno-variable-expansion-in-unroller"), +flagpd1("fvect-cost-model"), +flagpd1("fno-vect-cost-model"), +flagpd1("vectorize-loops"), +flagpd1("vectorize-slp"), +flagpd1("verify"), +.{ + .name = "verify=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "verify-debug-info", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +flagpd1("verify-ignore-unexpected"), +.{ + .name = "verify-ignore-unexpected=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +flagpd1("verify-pch"), +flagpd1("version"), +.{ + .name = "via-file-asm", + .syntax = .flag, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +joinpd1("vtordisp-mode="), +flagpd1("w"), +sepd1("weak_framework"), +sepd1("weak_library"), +sepd1("weak_reference_mismatches"), +joinpd1("weak-l"), +flagpd1("fweb"), +flagpd1("fno-web"), +flagpd1("whatsloaded"), +flagpd1("fwhole-file"), +flagpd1("fno-whole-file"), +flagpd1("fwhole-program"), +flagpd1("fno-whole-program"), +flagpd1("whyload"), +jspd1("working-directory"), +joinpd1("working-directory="), +jspd1("x"), +joinpd1("y"), +sepd1("z"), +};}; diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 78aa278005..23df042cbe 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -113,6 +113,7 @@ const Error = extern enum { TargetHasNoDynamicLinker, InvalidAbiVersion, InvalidOperatingSystemVersion, + UnknownClangOption, }; const FILE = std.c.FILE; @@ -1215,3 +1216,157 @@ fn convertSlice(slice: [][:0]u8, ptr: *[*][*:0]u8, len: *usize) !void { } ptr.* = new_slice.ptr; } + +const clang_args = @import("clang_options.zig").list; + +// ABI warning +pub const ClangArgIterator = extern struct { + has_next: bool, + zig_equivalent: ZigEquivalent, + only_arg: [*:0]const u8, + second_arg: [*:0]const u8, + other_args_ptr: [*]const [*:0]const u8, + other_args_len: usize, + argv_ptr: [*]const [*:0]const u8, + argv_len: usize, + next_index: usize, + + // ABI warning + pub const ZigEquivalent = extern enum { + target, + o, + c, + other, + positional, + l, + }; + + fn init(argv: []const [*:0]const u8) ClangArgIterator { + return .{ + .next_index = 2, // `zig cc foo` this points to `foo` + .has_next = argv.len > 2, + .zig_equivalent = undefined, + .only_arg = undefined, + .second_arg = undefined, + .other_args_ptr = undefined, + .other_args_len = undefined, + .argv_ptr = argv.ptr, + .argv_len = argv.len, + }; + } + + fn next(self: *ClangArgIterator) !void { + assert(self.has_next); + assert(self.next_index < self.argv_len); + // In this state we know that the parameter we are looking at is a root parameter + // rather than an argument to a parameter. + self.other_args_ptr = self.argv_ptr + self.next_index; + self.other_args_len = 1; // We adjust this value below when necessary. + const arg = mem.span(self.argv_ptr[self.next_index]); + self.next_index += 1; + defer { + if (self.next_index >= self.argv_len) self.has_next = false; + } + + if (!mem.startsWith(u8, arg, "-")) { + self.zig_equivalent = .positional; + self.only_arg = arg.ptr; + return; + } + + find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) { + .flag => if (clang_arg.matchEql(arg)) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr; + + break :find_clang_arg; + }, + .joined, .comma_joined => { + // Example: --target=foo + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len != 0) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr + prefix_len; // This will skip over the "--target=" part. + + break :find_clang_arg; + } + }, + .joined_or_separate => { + // Examples: `-lfoo`, `-l foo` + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len == arg.len) { + if (self.next_index >= self.argv_len) { + std.debug.warn("Expected parameter after '{}'\n", .{arg}); + process.exit(1); + } + self.only_arg = self.argv_ptr[self.next_index]; + self.next_index += 1; + self.other_args_len += 1; + self.zig_equivalent = clang_arg.zig_equivalent; + + break :find_clang_arg; + } else if (prefix_len != 0) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr + prefix_len; + + break :find_clang_arg; + } + }, + .joined_and_separate => { + // Example: `-Xopenmp-target=riscv64-linux-unknown foo` + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len != 0) { + self.only_arg = arg.ptr + prefix_len; + if (self.next_index >= self.argv_len) { + std.debug.warn("Expected parameter after '{}'\n", .{arg}); + process.exit(1); + } + self.second_arg = self.argv_ptr[self.next_index]; + self.next_index += 1; + self.other_args_len += 1; + self.zig_equivalent = clang_arg.zig_equivalent; + break :find_clang_arg; + } + }, + .separate => if (clang_arg.matchEql(arg)) { + if (self.next_index >= self.argv_len) { + std.debug.warn("Expected parameter after '{}'\n", .{arg}); + process.exit(1); + } + self.only_arg = self.argv_ptr[self.next_index]; + self.next_index += 1; + self.other_args_len += 1; + self.zig_equivalent = clang_arg.zig_equivalent; + break :find_clang_arg; + }, + .remaining_args_joined => { + const prefix_len = clang_arg.matchStartsWith(arg); + if (prefix_len != 0) { + @panic("TODO"); + } + }, + .multi_arg => if (clang_arg.matchEql(arg)) { + @panic("TODO"); + }, + } + else { + std.debug.warn("Unknown Clang option: '{}'\n", .{arg}); + process.exit(1); + } + } +}; + +export fn stage2_clang_arg_iterator( + result: *ClangArgIterator, + argc: usize, + argv: [*]const [*:0]const u8, +) void { + result.* = ClangArgIterator.init(argv[0..argc]); +} + +export fn stage2_clang_arg_next(it: *ClangArgIterator) Error { + it.next() catch |err| switch (err) { + error.UnknownClangOption => return .UnknownClangOption, + }; + return .None; +} diff --git a/src/codegen.cpp b/src/codegen.cpp index c2ce2ac3eb..7729172c2f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9778,7 +9778,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { Termination term; ZigList args = {}; args.append(buf_ptr(self_exe_path)); - args.append("cc"); + args.append("clang"); Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path)); add_cc_args(g, args, buf_ptr(out_dep_path), false); diff --git a/src/error.cpp b/src/error.cpp index 2e92a98217..c246ea5f31 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -83,6 +83,7 @@ const char *err_str(Error err) { case ErrorTargetHasNoDynamicLinker: return "target has no dynamic linker"; case ErrorInvalidAbiVersion: return "invalid C ABI version"; case ErrorInvalidOperatingSystemVersion: return "invalid operating system version"; + case ErrorUnknownClangOption: return "unknown Clang option"; } return "(invalid error)"; } diff --git a/src/link.cpp b/src/link.cpp index 0ae47c8432..b340206b14 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -2008,7 +2008,7 @@ static const char *get_def_lib(CodeGen *parent, const char *name, Buf *def_in_fi ZigList args = {}; args.append(buf_ptr(self_exe_path)); - args.append("cc"); + args.append("clang"); args.append("-x"); args.append("c"); args.append(buf_ptr(def_in_file)); diff --git a/src/main.cpp b/src/main.cpp index 76d6eadb14..f850b0bc47 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,7 +36,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " build-lib [source] create library from source or object files\n" " build-obj [source] create object from source or assembly\n" " builtin show the source code of @import(\"builtin\")\n" - " cc C compiler\n" + " cc use Zig as a drop-in C compiler\n" " fmt parse files and render in canonical zig format\n" " id print the base64-encoded compiler id\n" " init-exe initialize a `zig build` application in the cwd\n" @@ -271,7 +271,7 @@ static int main0(int argc, char **argv) { return 0; } - if (argc >= 2 && (strcmp(argv[1], "cc") == 0 || + if (argc >= 2 && (strcmp(argv[1], "clang") == 0 || strcmp(argv[1], "-cc1") == 0 || strcmp(argv[1], "-cc1as") == 0)) { return ZigClang_main(argc, argv); @@ -575,9 +575,55 @@ static int main0(int argc, char **argv) { return (term.how == TerminationIdClean) ? term.code : -1; } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) { return stage2_fmt(argc, argv); - } - - for (int i = 1; i < argc; i += 1) { + } else if (argc >= 2 && strcmp(argv[1], "cc") == 0) { + const char *o_arg = nullptr; + bool c_arg = false; + Stage2ClangArgIterator it; + stage2_clang_arg_iterator(&it, argc, argv); + while (it.has_next) { + if ((err = stage2_clang_arg_next(&it))) { + fprintf(stderr, "unable to parse command line parameters: %s\n", err_str(err)); + return EXIT_FAILURE; + } + switch (it.kind) { + case Stage2ClangArgTarget: // example: -target riscv64-linux-unknown + target_string = it.only_arg; + break; + case Stage2ClangArgO: // -o + o_arg = it.only_arg; + break; + case Stage2ClangArgC: // -c + c_arg = true; + break; + case Stage2ClangArgOther: + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + break; + case Stage2ClangArgPositional: { + CFile *c_file = heap::c_allocator.create(); + c_file->source_path = it.only_arg; + c_source_files.append(c_file); + break; + } + case Stage2ClangArgL: // -l + if (strcmp(it.only_arg, "c") == 0) + have_libc = true; + link_libs.append(it.only_arg); + break; + } + } + if (!c_arg) { + cmd = CmdBuild; + out_type = OutTypeExe; + if (o_arg == nullptr) { + zig_panic("TODO set out name to a.out"); + } + } else { + cmd = CmdBuild; + out_type = OutTypeObj; + } + } else for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; if (arg[0] == '-') { diff --git a/src/stage2.cpp b/src/stage2.cpp index a8d8b7cf97..c83b1aa77c 100644 --- a/src/stage2.cpp +++ b/src/stage2.cpp @@ -304,3 +304,15 @@ enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths) { return ErrorNone; } + +void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it, + size_t argc, char **argv) +{ + const char *msg = "stage0 called stage2_clang_arg_iterator"; + stage2_panic(msg, strlen(msg)); +} + +enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it) { + const char *msg = "stage0 called stage2_clang_arg_next"; + stage2_panic(msg, strlen(msg)); +} diff --git a/src/stage2.h b/src/stage2.h index 9ba7e062b1..2abdc4c513 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -105,6 +105,7 @@ enum Error { ErrorTargetHasNoDynamicLinker, ErrorInvalidAbiVersion, ErrorInvalidOperatingSystemVersion, + ErrorUnknownClangOption, }; // ABI warning @@ -316,4 +317,34 @@ struct Stage2NativePaths { // ABI warning ZIG_EXTERN_C enum Error stage2_detect_native_paths(struct Stage2NativePaths *native_paths); +// ABI warning +enum Stage2ClangArg { + Stage2ClangArgTarget, + Stage2ClangArgO, + Stage2ClangArgC, + Stage2ClangArgOther, + Stage2ClangArgPositional, + Stage2ClangArgL, +}; + +// ABI warning +struct Stage2ClangArgIterator { + bool has_next; + enum Stage2ClangArg kind; + const char *only_arg; + const char *second_arg; + const char **other_args_ptr; + size_t other_args_len; + const char **argv_ptr; + size_t argv_len; + size_t next_index; +}; + +// ABI warning +ZIG_EXTERN_C void stage2_clang_arg_iterator(struct Stage2ClangArgIterator *it, + size_t argc, char **argv); + +// ABI warning +ZIG_EXTERN_C enum Error stage2_clang_arg_next(struct Stage2ClangArgIterator *it); + #endif diff --git a/tools/process_headers.zig b/tools/process_headers.zig index abdc9fabf9..7c9befcffa 100644 --- a/tools/process_headers.zig +++ b/tools/process_headers.zig @@ -1,14 +1,14 @@ -// To get started, run this tool with no args and read the help message. -// -// The build systems of musl-libc and glibc require specifying a single target -// architecture. Meanwhile, Zig supports out-of-the-box cross compilation for -// every target. So the process to create libc headers that Zig ships is to use -// this tool. -// First, use the musl/glibc build systems to create installations of all the -// targets in the `glibc_targets`/`musl_targets` variables. -// Next, run this tool to create a new directory which puts .h files into -// subdirectories, with `generic` being files that apply to all architectures. -// You'll then have to manually update Zig source repo with these new files. +//! To get started, run this tool with no args and read the help message. +//! +//! The build systems of musl-libc and glibc require specifying a single target +//! architecture. Meanwhile, Zig supports out-of-the-box cross compilation for +//! every target. So the process to create libc headers that Zig ships is to use +//! this tool. +//! First, use the musl/glibc build systems to create installations of all the +//! targets in the `glibc_targets`/`musl_targets` variables. +//! Next, run this tool to create a new directory which puts .h files into +//! subdirectories, with `generic` being files that apply to all architectures. +//! You'll then have to manually update Zig source repo with these new files. const std = @import("std"); const Arch = std.Target.Cpu.Arch; diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig new file mode 100644 index 0000000000..863c67b68d --- /dev/null +++ b/tools/update_clang_options.zig @@ -0,0 +1,274 @@ +//! To get started, run this tool with no args and read the help message. +//! +//! Clang has a file "options.td" which describes all of its command line parameter options. +//! When using `zig cc`, Zig acts as a proxy between the user and Clang. It does not need +//! to understand all the parameters, but it does need to understand some of them, such as +//! the target. This means that Zig must understand when a C command line parameter expects +//! to "consume" the next parameter on the command line. +//! +//! For example, `-z -target` would mean to pass `-target` to the linker, whereas `-E -target` +//! would mean that the next parameter specifies the target. + +const std = @import("std"); +const fs = std.fs; +const assert = std.debug.assert; +const json = std.json; + +const KnownOpt = struct { + name: []const u8, + + /// Corresponds to stage.zig ClangArgIterator.Kind + ident: []const u8, +}; + +const known_options = [_]KnownOpt{ + .{ + .name = "target", + .ident = "target", + }, + .{ + .name = "o", + .ident = "o", + }, + .{ + .name = "c", + .ident = "c", + }, + .{ + .name = "l", + .ident = "l", + }, +}; + +const blacklisted_options = [_][]const u8{}; + +fn knownOption(name: []const u8) ?[]const u8 { + const chopped_name = if (std.mem.endsWith(u8, name, "=")) name[0 .. name.len - 1] else name; + for (known_options) |item| { + if (std.mem.eql(u8, chopped_name, item.name)) { + return item.ident; + } + } + return null; +} + +pub fn main() anyerror!void { + var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); + defer arena.deinit(); + + const allocator = &arena.allocator; + const args = try std.process.argsAlloc(allocator); + + if (args.len <= 1) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + if (std.mem.eql(u8, args[1], "--help")) { + usageAndExit(std.io.getStdOut(), args[0], 0); + } + if (args.len < 3) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + + const llvm_tblgen_exe = args[1]; + if (std.mem.startsWith(u8, llvm_tblgen_exe, "-")) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + + const llvm_src_root = args[2]; + if (std.mem.startsWith(u8, llvm_src_root, "-")) { + usageAndExit(std.io.getStdErr(), args[0], 1); + } + + const child_args = [_][]const u8{ + llvm_tblgen_exe, + "--dump-json", + try std.fmt.allocPrint(allocator, "{}/clang/include/clang/Driver/Options.td", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={}/llvm/include", .{llvm_src_root}), + try std.fmt.allocPrint(allocator, "-I={}/clang/include/clang/Driver", .{llvm_src_root}), + }; + + const child_result = try std.ChildProcess.exec2(.{ + .allocator = allocator, + .argv = &child_args, + .max_output_bytes = 100 * 1024 * 1024, + }); + + std.debug.warn("{}\n", .{child_result.stderr}); + + const json_text = switch (child_result.term) { + .Exited => |code| if (code == 0) child_result.stdout else { + std.debug.warn("llvm-tblgen exited with code {}\n", .{code}); + std.process.exit(1); + }, + else => { + std.debug.warn("llvm-tblgen crashed\n", .{}); + std.process.exit(1); + }, + }; + + var parser = json.Parser.init(allocator, false); + const tree = try parser.parse(json_text); + const root_map = &tree.root.Object; + + var all_names = std.ArrayList([]const u8).init(allocator); + { + var it = root_map.iterator(); + it_map: while (it.next()) |kv| { + if (kv.key.len == 0) continue; + if (kv.key[0] == '!') continue; + if (kv.value != .Object) continue; + if (!kv.value.Object.contains("NumArgs")) continue; + if (!kv.value.Object.contains("Name")) continue; + for (blacklisted_options) |blacklisted_key| { + if (std.mem.eql(u8, blacklisted_key, kv.key)) continue :it_map; + } + if (kv.value.Object.get("Name").?.value.String.len == 0) continue; + try all_names.append(kv.key); + } + } + std.sort.sort([]const u8, all_names.span(), nameLessThan); + + var stdout_bos = std.io.bufferedOutStream(std.io.getStdOut().outStream()); + const stdout = stdout_bos.outStream(); + try stdout.writeAll( + \\// This file is generated by tools/update_clang_options.zig. + \\// zig fmt: off + \\usingnamespace @import("clang_options.zig"); + \\pub const data = blk: { @setEvalBranchQuota(6000); break :blk &[_]CliArg{ + \\ + ); + + for (all_names.span()) |key| { + const obj = &root_map.get(key).?.value.Object; + const name = obj.get("Name").?.value.String; + var pd1 = false; + var pd2 = false; + var pslash = false; + for (obj.get("Prefixes").?.value.Array.span()) |prefix_json| { + const prefix = prefix_json.String; + if (std.mem.eql(u8, prefix, "-")) { + pd1 = true; + } else if (std.mem.eql(u8, prefix, "--")) { + pd2 = true; + } else if (std.mem.eql(u8, prefix, "/")) { + pslash = true; + } else { + std.debug.warn("{} (key {}) has unrecognized prefix '{}'\n", .{ name, key, prefix }); + std.process.exit(1); + } + } + const num_args = @intCast(u8, obj.get("NumArgs").?.value.Integer); + const syntax_str: []const u8 = blk: { + for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { + const superclass = superclass_json.String; + if (std.mem.eql(u8, superclass, "Joined")) { + break :blk ".joined"; + } else if (std.mem.eql(u8, superclass, "CLJoined")) { + break :blk ".joined"; + } else if (std.mem.eql(u8, superclass, "CLIgnoredJoined")) { + break :blk ".joined"; + } else if (std.mem.eql(u8, superclass, "CLCompileJoined")) { + break :blk ".joined"; + } else if (std.mem.eql(u8, superclass, "JoinedOrSeparate")) { + break :blk ".joined_or_separate"; + } else if (std.mem.eql(u8, superclass, "CLJoinedOrSeparate")) { + break :blk ".joined_or_separate"; + } else if (std.mem.eql(u8, superclass, "CLCompileJoinedOrSeparate")) { + break :blk ".joined_or_separate"; + } else if (std.mem.eql(u8, superclass, "Flag")) { + break :blk ".flag"; + } else if (std.mem.eql(u8, superclass, "CLFlag")) { + break :blk ".flag"; + } else if (std.mem.eql(u8, superclass, "CLIgnoredFlag")) { + break :blk ".flag"; + } else if (std.mem.eql(u8, superclass, "Separate")) { + break :blk ".separate"; + } else if (std.mem.eql(u8, superclass, "JoinedAndSeparate")) { + break :blk ".joined_and_separate"; + } else if (std.mem.eql(u8, superclass, "CommaJoined")) { + break :blk ".comma_joined"; + } else if (std.mem.eql(u8, superclass, "CLRemainingArgsJoined")) { + break :blk ".remaining_args_joined"; + } else if (std.mem.eql(u8, superclass, "MultiArg")) { + break :blk try std.fmt.allocPrint(allocator, ".{{ .multi_arg = {} }}", .{num_args}); + } + } + if (std.mem.eql(u8, name, "")) { + break :blk ".flag"; + } else if (std.mem.eql(u8, name, "")) { + break :blk ".flag"; + } + const kind_def = obj.get("Kind").?.value.Object.get("def").?.value.String; + if (std.mem.eql(u8, kind_def, "KIND_FLAG")) { + break :blk ".flag"; + } + std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); + for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { + std.debug.warn(" {}\n", .{superclass_json.String}); + } + std.process.exit(1); + }; + if (knownOption(name)) |ident| { + try stdout.print( + \\.{{ + \\ .name = "{}", + \\ .syntax = {}, + \\ .zig_equivalent = .{}, + \\ .pd1 = {}, + \\ .pd2 = {}, + \\ .psl = {}, + \\}}, + \\ + , .{ name, syntax_str, ident, pd1, pd2, pslash }); + } else if (pd1 and !pd2 and !pslash and + std.mem.eql(u8, syntax_str, ".flag")) + { + try stdout.print("flagpd1(\"{}\"),\n", .{name}); + } else if (pd1 and !pd2 and !pslash and + std.mem.eql(u8, syntax_str, ".joined")) + { + try stdout.print("joinpd1(\"{}\"),\n", .{name}); + } else if (pd1 and !pd2 and !pslash and + std.mem.eql(u8, syntax_str, ".joined_or_separate")) + { + try stdout.print("jspd1(\"{}\"),\n", .{name}); + } else if (pd1 and !pd2 and !pslash and + std.mem.eql(u8, syntax_str, ".separate")) + { + try stdout.print("sepd1(\"{}\"),\n", .{name}); + } else { + try stdout.print( + \\.{{ + \\ .name = "{}", + \\ .syntax = {}, + \\ .zig_equivalent = .other, + \\ .pd1 = {}, + \\ .pd2 = {}, + \\ .psl = {}, + \\}}, + \\ + , .{ name, syntax_str, pd1, pd2, pslash }); + } + } + + try stdout.writeAll( + \\};}; + \\ + ); + + try stdout_bos.flush(); +} + +fn nameLessThan(a: []const u8, b: []const u8) bool { + return std.mem.lessThan(u8, a, b); +} + +fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { + file.outStream().print( + \\Usage: {} /path/to/llvm-tblgen /path/to/git/llvm/llvm-project + \\ + \\Prints to stdout Zig code which you can use to replace the file src-self-hosted/clang_options_data.zig. + \\ + , .{arg0}) catch std.process.exit(1); + std.process.exit(code); +} From 0eee98edc1e505486a9ec51a331d3aa322fce9ee Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 21 Mar 2020 15:29:52 -0400 Subject: [PATCH 64/79] zig cc improvements * The generated options data file is sorted now in a way that makes sure longer prefixes are first. This prevents collisions with some parameters. * Add support for `-fPIC`, `-fno-PIC`, `-nostdlib`, `-shared`, `-rdynamic`, `-Wl,-soname`, `-Wl,-rpath` * Better support for `-o`. * Disable generating h files * Shared library support. * Better positional argument support. --- src-self-hosted/clang_options.zig | 6 +- src-self-hosted/clang_options_data.zig | 2952 ++++++++++++------------ src-self-hosted/stage2.zig | 11 +- src/main.cpp | 149 +- src/stage2.h | 8 + tools/update_clang_options.zig | 260 ++- 6 files changed, 1838 insertions(+), 1548 deletions(-) diff --git a/src-self-hosted/clang_options.zig b/src-self-hosted/clang_options.zig index 9fa35b8f9a..538f281706 100644 --- a/src-self-hosted/clang_options.zig +++ b/src-self-hosted/clang_options.zig @@ -20,7 +20,7 @@ pub const CliArg = struct { /// Prefixed by "/" psl: bool = false, - const Syntax = union(enum) { + pub const Syntax = union(enum) { /// A flag with no values. flag, @@ -46,7 +46,7 @@ pub const CliArg = struct { multi_arg: u8, }; - fn matchEql(self: CliArg, arg: []const u8) bool { + pub fn matchEql(self: CliArg, arg: []const u8) bool { if (self.pd1 and arg.len >= self.name.len + 1 and mem.startsWith(u8, arg, "-") and mem.eql(u8, arg[1..], self.name)) { @@ -65,7 +65,7 @@ pub const CliArg = struct { return false; } - fn matchStartsWith(self: CliArg, arg: []const u8) usize { + pub fn matchStartsWith(self: CliArg, arg: []const u8) usize { if (self.pd1 and arg.len >= self.name.len + 1 and mem.startsWith(u8, arg, "-") and mem.startsWith(u8, arg[1..], self.name)) { diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig index a88f3583c9..a21069f93c 100644 --- a/src-self-hosted/clang_options_data.zig +++ b/src-self-hosted/clang_options_data.zig @@ -2,21 +2,13 @@ // zig fmt: off usingnamespace @import("clang_options.zig"); pub const data = blk: { @setEvalBranchQuota(6000); break :blk &[_]CliArg{ -jspd1("A"), -joinpd1("A-"), -jspd1("B"), flagpd1("C"), flagpd1("CC"), -jspd1("D"), flagpd1("E"), flagpd1("EB"), flagpd1("EL"), flagpd1("Eonly"), -jspd1("F"), -jspd1("G"), -joinpd1("G="), flagpd1("H"), -jspd1("I"), .{ .name = "", .syntax = .flag, @@ -26,42 +18,25 @@ jspd1("I"), .psl = false, }, flagpd1("I-"), -jspd1("J"), -jspd1("L"), flagpd1("M"), flagpd1("MD"), -jspd1("MF"), flagpd1("MG"), -jspd1("MJ"), flagpd1("MM"), flagpd1("MMD"), flagpd1("MP"), -jspd1("MQ"), -jspd1("MT"), flagpd1("MV"), flagpd1("Mach"), -joinpd1("O"), flagpd1("O0"), flagpd1("O4"), flagpd1("O"), flagpd1("ObjC"), flagpd1("ObjC++"), -joinpd1("Ofast"), flagpd1("P"), flagpd1("Q"), flagpd1("Qn"), flagpd1("Qunused-arguments"), flagpd1("Qy"), -joinpd1("R"), -joinpd1("Rpass="), -joinpd1("Rpass-analysis="), -joinpd1("Rpass-missed="), flagpd1("S"), -jspd1("T"), -jspd1("Tbss"), -jspd1("Tdata"), -jspd1("Ttext"), -jspd1("U"), .{ .name = "", .syntax = .flag, @@ -70,74 +45,24 @@ jspd1("U"), .pd2 = false, .psl = false, }, -jspd1("V"), flagpd1("WCL4"), -joinpd1("W"), -.{ - .name = "Wa,", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("Wall"), flagpd1("Wdeprecated"), -joinpd1("Wframe-larger-than="), -.{ - .name = "Wl,", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, -joinpd1("Wlarge-by-value-copy="), flagpd1("Wlarge-by-value-copy"), -joinpd1("Wlarger-than-"), -joinpd1("Wlarger-than="), flagpd1("Wno-deprecated"), -joinpd1("Wno-nonportable-cfstrings"), flagpd1("Wno-rewrite-macros"), flagpd1("Wno-write-strings"), -joinpd1("Wnonportable-cfstrings"), -.{ - .name = "Wp,", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("Wwrite-strings"), flagpd1("X"), -joinpd1("X"), sepd1("Xanalyzer"), -.{ - .name = "Xarch_", - .syntax = .joined_and_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, sepd1("Xassembler"), sepd1("Xclang"), sepd1("Xcuda-fatbinary"), sepd1("Xcuda-ptxas"), sepd1("Xlinker"), sepd1("Xopenmp-target"), -.{ - .name = "Xopenmp-target=", - .syntax = .joined_and_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, sepd1("Xpreprocessor"), flagpd1("Z"), -joinpd1("Z"), flagpd1("Z-Xlinker-no-demangle"), flagpd1("Z-reserved-lib-cckext"), flagpd1("Z-reserved-lib-stdc++"), @@ -150,23 +75,7 @@ sepd1("Zlinker-input"), .pd2 = true, .psl = false, }, -.{ - .name = "CLASSPATH=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("###"), -.{ - .name = "AI", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Brepro", .syntax = .flag, @@ -207,14 +116,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "D", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "E", .syntax = .flag, @@ -223,14 +124,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "EH", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "EP", .syntax = .flag, @@ -239,14 +132,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "F", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "FA", .syntax = .flag, @@ -255,14 +140,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "FA", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "FC", .syntax = .flag, @@ -271,22 +148,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "FI", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "FR", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "FS", .syntax = .flag, @@ -295,78 +156,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "FU", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fa", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fd", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fe", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fi", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fm", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fo", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fp", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Fr", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Fx", .syntax = .flag, @@ -559,14 +348,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Gs", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Gv", .syntax = .flag, @@ -631,14 +412,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "I", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "J", .syntax = .flag, @@ -695,14 +468,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "MP", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "MT", .syntax = .flag, @@ -719,14 +484,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "O", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "P", .syntax = .flag, @@ -775,14 +532,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Qpar-report", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Qsafe_fp_loads", .syntax = .flag, @@ -815,22 +564,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Qvec-report", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "RTC", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "TC", .syntax = .flag, @@ -847,30 +580,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Tc", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Tp", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "U", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "V", .syntax = .flag, @@ -975,14 +684,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Yc", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Yd", .syntax = .flag, @@ -991,22 +692,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Yl", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "Yu", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Z7", .syntax = .flag, @@ -1047,14 +732,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "ZW", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Za", .syntax = .flag, @@ -1063,14 +740,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Zc:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Zc:__cplusplus", .syntax = .flag, @@ -1287,14 +956,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Zm", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Zo", .syntax = .flag, @@ -1311,14 +972,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "Zp", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "Zp", .syntax = .flag, @@ -1343,14 +996,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "arch:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "await", .syntax = .flag, @@ -1375,38 +1020,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "cgthreads", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "clang:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "clr", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "constexpr:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "d1PP", .syntax = .flag, @@ -1423,14 +1036,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "d2", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "d2FastFail", .syntax = .flag, @@ -1471,30 +1076,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "doc", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "errorReport", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "execution-charset:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "fallback", .syntax = .flag, @@ -1503,14 +1084,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "favor", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "fp:except", .syntax = .flag, @@ -1551,18 +1124,10 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "guard:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "help", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .passthrough, .pd1 = true, .pd2 = false, .psl = true, @@ -1583,14 +1148,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "imsvc", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "kernel", .syntax = .flag, @@ -1607,14 +1164,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "link", - .syntax = .remaining_args_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "nologo", .syntax = .flag, @@ -1623,14 +1172,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "o", - .syntax = .joined_or_separate, - .zig_equivalent = .o, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "openmp", .syntax = .flag, @@ -1703,22 +1244,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "source-charset:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, -.{ - .name = "std:", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "u", .syntax = .flag, @@ -1751,14 +1276,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "vd", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "vmb", .syntax = .flag, @@ -1815,14 +1332,6 @@ flagpd1("###"), .pd2 = false, .psl = true, }, -.{ - .name = "w", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = true, -}, .{ .name = "w", .syntax = .flag, @@ -1895,14 +1404,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "analyzer-output", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "assemble", .syntax = .flag, @@ -1919,14 +1420,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "assert=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "bootclasspath", .syntax = .separate, @@ -1935,14 +1428,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "bootclasspath=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "classpath", .syntax = .separate, @@ -1951,14 +1436,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "classpath=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "comments", .syntax = .flag, @@ -1999,14 +1476,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "debug=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "define-macro", .syntax = .separate, @@ -2015,14 +1484,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "define-macro=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "dependencies", .syntax = .flag, @@ -2039,14 +1500,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "dyld-prefix=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "encoding", .syntax = .separate, @@ -2055,14 +1508,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "encoding=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "entry", .syntax = .flag, @@ -2079,14 +1524,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "extdirs=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "extra-warnings", .syntax = .flag, @@ -2103,14 +1540,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "for-linker=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "force-link", .syntax = .separate, @@ -2119,14 +1548,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "force-link=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "help-hidden", .syntax = .flag, @@ -2135,22 +1556,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "imacros=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "include=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "include-barrier", .syntax = .flag, @@ -2167,14 +1572,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "include-directory=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "include-directory-after", .syntax = .separate, @@ -2183,14 +1580,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "include-directory-after=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "include-prefix", .syntax = .separate, @@ -2199,14 +1588,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "include-prefix=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "include-with-prefix", .syntax = .separate, @@ -2215,14 +1596,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "include-with-prefix=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "include-with-prefix-after", .syntax = .separate, @@ -2231,14 +1604,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "include-with-prefix-after=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "include-with-prefix-before", .syntax = .separate, @@ -2247,14 +1612,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "include-with-prefix-before=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "language", .syntax = .separate, @@ -2263,14 +1620,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "language=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "library-directory", .syntax = .separate, @@ -2279,14 +1628,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "library-directory=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "mhwdiv", .syntax = .separate, @@ -2295,14 +1636,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "mhwdiv=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "migrate", .syntax = .flag, @@ -2330,7 +1663,7 @@ flagpd1("###"), .{ .name = "no-standard-libraries", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .nostdlib, .pd1 = false, .pd2 = true, .psl = false, @@ -2359,14 +1692,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "optimize=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "output", .syntax = .separate, @@ -2375,14 +1700,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "output=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "output-class-directory", .syntax = .separate, @@ -2391,14 +1708,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "output-class-directory=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "param", .syntax = .separate, @@ -2407,14 +1716,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "param=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "precompile", .syntax = .flag, @@ -2431,14 +1732,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "prefix=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "preprocess", .syntax = .flag, @@ -2503,14 +1796,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "resource=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "rtlib", .syntax = .separate, @@ -2559,14 +1844,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "sysroot=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "target-help", .syntax = .flag, @@ -2591,14 +1868,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "undefine-macro=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "unsigned-char", .syntax = .flag, @@ -2631,22 +1900,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -.{ - .name = "warn-", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "warn-=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "write-dependencies", .syntax = .flag, @@ -2663,7 +1916,6 @@ flagpd1("###"), .pd2 = true, .psl = false, }, -joinpd1("a"), sepd1("add-plugin"), flagpd1("faggressive-function-elimination"), flagpd1("fno-aggressive-function-elimination"), @@ -2684,9 +1936,7 @@ flagpd1("cfg-add-implicit-dtors"), flagpd1("unoptimized-cfg"), flagpd1("analyze"), sepd1("analyze-function"), -joinpd1("analyze-function="), sepd1("analyzer-checker"), -joinpd1("analyzer-checker="), flagpd1("analyzer-checker-help"), flagpd1("analyzer-checker-help-alpha"), flagpd1("analyzer-checker-help-developer"), @@ -2695,32 +1945,23 @@ flagpd1("analyzer-checker-option-help-alpha"), flagpd1("analyzer-checker-option-help-developer"), sepd1("analyzer-config"), sepd1("analyzer-config-compatibility-mode"), -joinpd1("analyzer-config-compatibility-mode="), flagpd1("analyzer-config-help"), sepd1("analyzer-constraints"), -joinpd1("analyzer-constraints="), flagpd1("analyzer-disable-all-checks"), sepd1("analyzer-disable-checker"), -joinpd1("analyzer-disable-checker="), flagpd1("analyzer-disable-retry-exhausted"), flagpd1("analyzer-display-progress"), sepd1("analyzer-dump-egraph"), -joinpd1("analyzer-dump-egraph="), sepd1("analyzer-inline-max-stack-depth"), -joinpd1("analyzer-inline-max-stack-depth="), sepd1("analyzer-inlining-mode"), -joinpd1("analyzer-inlining-mode="), flagpd1("analyzer-list-enabled-checkers"), sepd1("analyzer-max-loop"), flagpd1("analyzer-opt-analyze-headers"), flagpd1("analyzer-opt-analyze-nested-blocks"), sepd1("analyzer-output"), -joinpd1("analyzer-output="), sepd1("analyzer-purge"), -joinpd1("analyzer-purge="), flagpd1("analyzer-stats"), sepd1("analyzer-store"), -joinpd1("analyzer-store="), flagpd1("analyzer-viz-egraph-graphviz"), flagpd1("analyzer-werror"), flagpd1("fslp-vectorize-aggressive"), @@ -2735,7 +1976,6 @@ flagpd1("fhonor-infinites"), flagpd1("fno-honor-infinites"), flagpd1("findirect-virtual-calls"), sepd1("fnew-alignment"), -joinpd1("objcmt-white-list-dir-path="), flagpd1("faligned-new"), flagpd1("fno-aligned-new"), flagpd1("fsched-interblock"), @@ -2912,27 +2152,16 @@ flagpd1("arcmt-migrate-emit-errors"), sepd1("arcmt-migrate-report-output"), flagpd1("arcmt-modify"), flagpd1("ast-dump"), -joinpd1("ast-dump="), flagpd1("ast-dump-all"), -joinpd1("ast-dump-all="), sepd1("ast-dump-filter"), flagpd1("ast-dump-lookups"), flagpd1("ast-list"), sepd1("ast-merge"), flagpd1("ast-print"), flagpd1("ast-view"), -.{ - .name = "autocomplete=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("fautomatic"), flagpd1("fno-automatic"), sepd1("aux-triple"), -jspd1("b"), flagpd1("fbackslash"), flagpd1("fno-backslash"), flagpd1("fbacktrace"), @@ -2953,12 +2182,10 @@ sepd1("bundle_loader"), .pd2 = false, .psl = false, }, -jspd1("c-isystem"), flagpd1("fcaller-saves"), flagpd1("fno-caller-saves"), flagpd1("cc1"), flagpd1("cc1as"), -joinpd1("ccc-"), flagpd1("ccc-arcmt-check"), sepd1("ccc-arcmt-migrate"), flagpd1("ccc-arcmt-modify"), @@ -2973,14 +2200,6 @@ sepd1("chain-include"), flagpd1("fcheck-array-temporaries"), flagpd1("fno-check-array-temporaries"), flagpd1("cl-denorms-are-zero"), -.{ - .name = "cl-ext=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("cl-fast-relaxed-math"), flagpd1("cl-finite-math-only"), flagpd1("cl-fp32-correctly-rounded-divide-sqrt"), @@ -2989,13 +2208,10 @@ flagpd1("cl-mad-enable"), flagpd1("cl-no-signed-zeros"), flagpd1("cl-opt-disable"), flagpd1("cl-single-precision-constant"), -joinpd1("cl-std="), flagpd1("cl-strict-aliasing"), flagpd1("cl-uniform-work-group-size"), flagpd1("cl-unsafe-math-optimizations"), -jspd1("client_name"), sepd1("code-completion-at"), -joinpd1("code-completion-at="), flagpd1("code-completion-brief-comments"), flagpd1("code-completion-macros"), flagpd1("code-completion-patterns"), @@ -3008,7 +2224,6 @@ flagpd1("code-completion-with-fixits"), .pd2 = true, .psl = false, }, -jspd1("compatibility_version"), flagpd1("compiler-options-dump"), .{ .name = "compress-debug-sections", @@ -3018,14 +2233,6 @@ flagpd1("compiler-options-dump"), .pd2 = true, .psl = false, }, -.{ - .name = "compress-debug-sections=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, .{ .name = "config", .syntax = .separate, @@ -3034,22 +2241,6 @@ flagpd1("compiler-options-dump"), .pd2 = true, .psl = false, }, -.{ - .name = "config-system-dir=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "config-user-dir=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "coverage", .syntax = .flag, @@ -3060,12 +2251,9 @@ flagpd1("compiler-options-dump"), }, flagpd1("coverage-cfg-checksum"), sepd1("coverage-data-file"), -joinpd1("coverage-data-file="), flagpd1("coverage-exit-block-before-body"), flagpd1("coverage-no-function-names-in-data"), sepd1("coverage-notes-file"), -joinpd1("coverage-notes-file="), -joinpd1("coverage-version="), flagpd1("cpp"), flagpd1("cpp-precomp"), flagpd1("fcray-pointer"), @@ -3086,14 +2274,6 @@ flagpd1("fno-cray-pointer"), .pd2 = true, .psl = false, }, -.{ - .name = "cuda-gpu-arch=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "cuda-host-only", .syntax = .flag, @@ -3102,14 +2282,6 @@ flagpd1("fno-cray-pointer"), .pd2 = true, .psl = false, }, -.{ - .name = "cuda-include-ptx=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "cuda-noopt-device-debug", .syntax = .flag, @@ -3118,14 +2290,6 @@ flagpd1("fno-cray-pointer"), .pd2 = true, .psl = false, }, -.{ - .name = "cuda-path=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "cuda-path-ignore-env", .syntax = .flag, @@ -3134,23 +2298,18 @@ flagpd1("fno-cray-pointer"), .pd2 = true, .psl = false, }, -jspd1("current_version"), -jspd1("cxx-isystem"), flagpd1("dA"), flagpd1("dD"), flagpd1("dI"), flagpd1("dM"), flagpd1("d"), -joinpd1("d"), flagpd1("fd-lines-as-code"), flagpd1("fno-d-lines-as-code"), flagpd1("fd-lines-as-comments"), flagpd1("fno-d-lines-as-comments"), flagpd1("dead_strip"), flagpd1("debug-forward-template-params"), -joinpd1("debug-info-kind="), flagpd1("debug-info-macro"), -joinpd1("debugger-tuning="), flagpd1("fdefault-double-8"), flagpd1("fno-default-double-8"), sepd1("default-function-attr"), @@ -3163,14 +2322,6 @@ flagpd1("fno-default-real-8"), sepd1("defsym"), sepd1("dependency-dot"), sepd1("dependency-file"), -.{ - .name = "dependent-lib=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("detailed-preprocessing-record"), flagpd1("fdevirtualize"), flagpd1("fno-devirtualize"), @@ -3190,14 +2341,6 @@ flagpd1("disable-red-zone"), flagpd1("discard-value-names"), flagpd1("fdollar-ok"), flagpd1("fno-dollar-ok"), -.{ - .name = "driver-mode=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("dump-coverage-mapping"), flagpd1("dump-deserialized-decls"), flagpd1("fdump-fortran-optimized"), @@ -3216,13 +2359,10 @@ sepd1("dwarf-debug-flags"), sepd1("dwarf-debug-producer"), flagpd1("dwarf-explicit-import"), flagpd1("dwarf-ext-refs"), -joinpd1("dwarf-version="), sepd1("dylib_file"), flagpd1("dylinker"), -jspd1("dylinker_install_name"), flagpd1("dynamic"), flagpd1("dynamiclib"), -jspd1("e"), flagpd1("feliminate-unused-debug-types"), flagpd1("fno-eliminate-unused-debug-types"), flagpd1("emit-ast"), @@ -3241,24 +2381,24 @@ flagpd1("emit-obj"), flagpd1("emit-pch"), flagpd1("enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang"), sepd1("error-on-deserialized-decl"), -joinpd1("error-on-deserialized-decl="), sepd1("exported_symbols_list"), flagpd1("fexternal-blas"), flagpd1("fno-external-blas"), flagpd1("ff2c"), flagpd1("fno-f2c"), -flagpd1("fPIC"), +.{ + .name = "fPIC", + .syntax = .flag, + .zig_equivalent = .pic, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fPIE"), flagpd1("faccess-control"), -joinpd1("faddress-space-map-mangling="), flagpd1("faddrsig"), flagpd1("falign-functions"), -joinpd1("falign-functions="), -joinpd1("falign-jumps="), -joinpd1("falign-labels="), -joinpd1("falign-loops="), flagpd1("faligned-allocation"), -joinpd1("faligned-new="), flagpd1("fallow-editor-placeholders"), flagpd1("fallow-half-arguments-and-returns"), flagpd1("fallow-pch-with-compiler-errors"), @@ -3281,18 +2421,12 @@ flagpd1("fasynchronous-unwind-tables"), flagpd1("ffat-lto-objects"), flagpd1("fno-fat-lto-objects"), flagpd1("fauto-profile"), -joinpd1("fauto-profile="), flagpd1("fauto-profile-accurate"), flagpd1("fautolink"), -joinpd1("fblas-matmul-limit="), flagpd1("fblocks"), flagpd1("fblocks-runtime-optional"), -joinpd1("fbootclasspath="), flagpd1("fborland-extensions"), sepd1("fbracket-depth"), -joinpd1("fbracket-depth="), -joinpd1("fbuild-session-file="), -joinpd1("fbuild-session-timestamp="), flagpd1("fbuiltin"), flagpd1("fbuiltin-module-map"), flagpd1("fcall-saved-x10"), @@ -3307,46 +2441,24 @@ flagpd1("fcall-saved-x9"), flagpd1("fcaret-diagnostics"), sepd1("fcaret-diagnostics-max-lines"), flagpd1("fcf-protection"), -joinpd1("fcf-protection="), -joinpd1("fcf-runtime-abi="), flagpd1("fchar8_t"), -joinpd1("fcheck="), flagpd1("fcheck-new"), flagpd1("fno-check-new"), -joinpd1("fclang-abi-compat="), -joinpd1("fclasspath="), -joinpd1("fcoarray="), flagpd1("fcolor-diagnostics"), -.{ - .name = "fcomment-block-commands=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fcommon"), -joinpd1("fcompile-resource="), flagpd1("fcomplete-member-pointers"), flagpd1("fconcepts-ts"), flagpd1("fconst-strings"), flagpd1("fconstant-cfstrings"), sepd1("fconstant-string-class"), -joinpd1("fconstant-string-class="), sepd1("fconstexpr-backtrace-limit"), -joinpd1("fconstexpr-backtrace-limit="), sepd1("fconstexpr-depth"), -joinpd1("fconstexpr-depth="), sepd1("fconstexpr-steps"), -joinpd1("fconstexpr-steps="), flagpd1("fconvergent-functions"), -joinpd1("fconvert="), flagpd1("fcoroutines-ts"), flagpd1("fcoverage-mapping"), -joinpd1("fcrash-diagnostics-dir="), flagpd1("fcreate-profile"), flagpd1("fcs-profile-generate"), -joinpd1("fcs-profile-generate="), flagpd1("fcuda-allow-variadic-functions"), flagpd1("fcuda-approx-transcendentals"), flagpd1("fcuda-flush-denormals-to-zero"), @@ -3358,14 +2470,11 @@ flagpd1("fcxx-modules"), flagpd1("fc++-static-destructors"), flagpd1("fdata-sections"), sepd1("fdebug-compilation-dir"), -joinpd1("fdebug-compilation-dir="), -joinpd1("fdebug-default-version="), flagpd1("fdebug-info-for-profiling"), flagpd1("fdebug-macro"), flagpd1("fdebug-pass-arguments"), flagpd1("fdebug-pass-manager"), flagpd1("fdebug-pass-structure"), -joinpd1("fdebug-prefix-map="), flagpd1("fdebug-ranges-base-address"), flagpd1("fdebug-types-section"), flagpd1("fdebugger-cast-result-to-id"), @@ -3373,25 +2482,17 @@ flagpd1("fdebugger-objc-literal"), flagpd1("fdebugger-support"), flagpd1("fdeclare-opencl-builtins"), flagpd1("fdeclspec"), -joinpd1("fdefault-calling-conv="), flagpd1("fdelayed-template-parsing"), flagpd1("fdelete-null-pointer-checks"), -joinpd1("fdenormal-fp-math="), -joinpd1("fdepfile-entry="), flagpd1("fdeprecated-macro"), flagpd1("fdiagnostics-absolute-paths"), flagpd1("fdiagnostics-color"), -joinpd1("fdiagnostics-color="), flagpd1("fdiagnostics-fixit-info"), sepd1("fdiagnostics-format"), -joinpd1("fdiagnostics-format="), -joinpd1("fdiagnostics-hotness-threshold="), flagpd1("fdiagnostics-parseable-fixits"), flagpd1("fdiagnostics-print-source-range-info"), sepd1("fdiagnostics-show-category"), -joinpd1("fdiagnostics-show-category="), flagpd1("fdiagnostics-show-hotness"), -joinpd1("fdiagnostics-show-location="), flagpd1("fdiagnostics-show-note-include-stack"), flagpd1("fdiagnostics-show-option"), flagpd1("fdiagnostics-show-template-tree"), @@ -3409,7 +2510,6 @@ flagpd1("fdwarf-exceptions"), flagpd1("felide-constructors"), flagpd1("feliminate-unused-debug-symbols"), flagpd1("fembed-bitcode"), -joinpd1("fembed-bitcode="), flagpd1("fembed-bitcode-marker"), flagpd1("femit-all-decls"), flagpd1("femit-coverage-data"), @@ -3417,24 +2517,17 @@ flagpd1("femit-coverage-notes"), flagpd1("femit-debug-entry-values"), flagpd1("femulated-tls"), flagpd1("fencode-extended-block-signature"), -joinpd1("fencoding="), sepd1("ferror-limit"), -joinpd1("ferror-limit="), flagpd1("fescaping-block-tail-calls"), flagpd1("fexceptions"), -joinpd1("fexcess-precision="), -joinpd1("fexec-charset="), flagpd1("fexperimental-isel"), flagpd1("fexperimental-new-constant-interpreter"), flagpd1("fexperimental-new-pass-manager"), -joinpd1("fextdirs="), flagpd1("fexternc-nounwind"), flagpd1("ffake-address-space-map"), flagpd1("ffast-math"), -joinpd1("ffile-prefix-map="), flagpd1("ffine-grained-bitfield-accesses"), flagpd1("ffinite-math-only"), -joinpd1("ffixed-line-length-"), flagpd1("ffixed-point"), flagpd1("ffixed-r19"), flagpd1("ffixed-r9"), @@ -3474,18 +2567,12 @@ flagpd1("fforbid-guard-variables"), flagpd1("fforce-dwarf-frame"), flagpd1("fforce-emit-vtables"), flagpd1("fforce-enable-int128"), -joinpd1("ffp-contract="), -joinpd1("ffp-exception-behavior="), -joinpd1("ffp-model="), -joinpd1("ffpe-trap="), -joinpd1("ffree-line-length-"), flagpd1("ffreestanding"), flagpd1("ffunction-sections"), flagpd1("fgnu89-inline"), flagpd1("fgnu-inline-asm"), flagpd1("fgnu-keywords"), flagpd1("fgnu-runtime"), -joinpd1("fgnuc-version="), flagpd1("fgpu-allow-device-init"), flagpd1("fgpu-rdc"), flagpd1("fheinous-gnu-extensions"), @@ -3499,17 +2586,11 @@ sepd1("filetype"), flagpd1("fimplicit-module-maps"), flagpd1("fimplicit-modules"), flagpd1("finclude-default-header"), -joinpd1("finit-character="), -joinpd1("finit-integer="), -joinpd1("finit-logical="), -joinpd1("finit-real="), flagpd1("finline"), flagpd1("finline-functions"), flagpd1("finline-hint-functions"), -joinpd1("finline-limit="), flagpd1("finline-limit"), flagpd1("fno-inline-limit"), -joinpd1("finput-charset="), flagpd1("finstrument-function-entry-bare"), flagpd1("finstrument-functions"), flagpd1("finstrument-functions-after-inlining"), @@ -3520,59 +2601,36 @@ flagpd1("fix-what-you-can"), flagpd1("ffixed-form"), flagpd1("fno-fixed-form"), flagpd1("fixit"), -joinpd1("fixit="), flagpd1("fixit-recompile"), flagpd1("fixit-to-temporary"), flagpd1("fjump-tables"), flagpd1("fkeep-static-consts"), flagpd1("flat_namespace"), flagpd1("flax-vector-conversions"), -joinpd1("flax-vector-conversions="), flagpd1("flimit-debug-info"), -joinpd1("flimited-precision="), flagpd1("ffloat-store"), flagpd1("fno-float-store"), flagpd1("flto"), -joinpd1("flto="), -joinpd1("flto-jobs="), flagpd1("flto-unit"), flagpd1("flto-visibility-public-std"), sepd1("fmacro-backtrace-limit"), -joinpd1("fmacro-backtrace-limit="), -joinpd1("fmacro-prefix-map="), flagpd1("fmath-errno"), -joinpd1("fmax-array-constructor="), -joinpd1("fmax-errors="), -joinpd1("fmax-stack-var-size="), -joinpd1("fmax-subrecord-length="), -joinpd1("fmax-type-align="), flagpd1("fmerge-all-constants"), flagpd1("fmerge-functions"), sepd1("fmessage-length"), -joinpd1("fmessage-length="), sepd1("fmodule-feature"), -joinpd1("fmodule-file="), flagpd1("fmodule-file-deps"), -joinpd1("fmodule-format="), sepd1("fmodule-implementation-of"), -joinpd1("fmodule-map-file="), flagpd1("fmodule-map-file-home-is-cwd"), flagpd1("fmodule-maps"), sepd1("fmodule-name"), -joinpd1("fmodule-name="), flagpd1("fmodules"), -joinpd1("fmodules-cache-path="), flagpd1("fmodules-codegen"), flagpd1("fmodules-debuginfo"), flagpd1("fmodules-decluse"), flagpd1("fmodules-disable-diagnostic-validation"), -joinpd1("fmodules-embed-all-files"), -joinpd1("fmodules-embed-file="), flagpd1("fmodules-hash-content"), -joinpd1("fmodules-ignore-macro="), flagpd1("fmodules-local-submodule-visibility"), -joinpd1("fmodules-prune-after="), -joinpd1("fmodules-prune-interval="), flagpd1("fmodules-search-all"), flagpd1("fmodules-strict-context-hash"), flagpd1("fmodules-strict-decluse"), @@ -3582,19 +2640,22 @@ flagpd1("fmodules-validate-input-files-content"), flagpd1("fmodules-validate-once-per-build-session"), flagpd1("fmodules-validate-system-headers"), flagpd1("fms-compatibility"), -joinpd1("fms-compatibility-version="), flagpd1("fms-extensions"), -joinpd1("fms-memptr-rep="), flagpd1("fms-volatile"), -joinpd1("fmsc-version="), flagpd1("fmudflap"), flagpd1("fmudflapth"), flagpd1("fnative-half-arguments-and-returns"), flagpd1("fnative-half-type"), flagpd1("fnested-functions"), -joinpd1("fnew-alignment="), flagpd1("fnext-runtime"), -flagpd1("fno-PIC"), +.{ + .name = "fno-PIC", + .syntax = .flag, + .zig_equivalent = .no_pic, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("fno-PIE"), flagpd1("fno-access-control"), flagpd1("fno-addrsig"), @@ -3616,7 +2677,6 @@ flagpd1("fno-bitfield-type-align"), flagpd1("fno-blocks"), flagpd1("fno-borland-extensions"), flagpd1("fno-builtin"), -joinpd1("fno-builtin-"), flagpd1("fno-caret-diagnostics"), flagpd1("fno-char8_t"), flagpd1("fno-color-diagnostics"), @@ -3755,54 +2815,22 @@ flagpd1("fno-rtlib-add-rpath"), flagpd1("fno-rtti"), flagpd1("fno-rtti-data"), flagpd1("fno-rwpi"), -.{ - .name = "fno-sanitize=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fno-sanitize-address-poison-custom-array-cookie"), flagpd1("fno-sanitize-address-use-after-scope"), flagpd1("fno-sanitize-address-use-odr-indicator"), flagpd1("fno-sanitize-blacklist"), flagpd1("fno-sanitize-cfi-canonical-jump-tables"), flagpd1("fno-sanitize-cfi-cross-dso"), -.{ - .name = "fno-sanitize-coverage=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fno-sanitize-link-c++-runtime"), flagpd1("fno-sanitize-link-runtime"), flagpd1("fno-sanitize-memory-track-origins"), flagpd1("fno-sanitize-memory-use-after-dtor"), flagpd1("fno-sanitize-minimal-runtime"), flagpd1("fno-sanitize-recover"), -.{ - .name = "fno-sanitize-recover=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fno-sanitize-stats"), flagpd1("fno-sanitize-thread-atomics"), flagpd1("fno-sanitize-thread-func-entry-exit"), flagpd1("fno-sanitize-thread-memory-access"), -.{ - .name = "fno-sanitize-trap=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fno-sanitize-undefined-trap-on-error"), flagpd1("fno-save-optimization-record"), flagpd1("fno-short-enums"), @@ -3858,14 +2886,11 @@ flagpd1("fno-xray-always-emit-customevents"), flagpd1("fno-xray-always-emit-typedevents"), flagpd1("fno-xray-instrument"), flagpd1("fnoxray-link-deps"), -joinpd1("fobjc-abi-version="), flagpd1("fobjc-arc"), -joinpd1("fobjc-arc-cxxlib="), flagpd1("fobjc-arc-exceptions"), flagpd1("fobjc-atdefs"), flagpd1("fobjc-call-cxx-cdtors"), flagpd1("fobjc-convert-messages-to-runtime-calls"), -joinpd1("fobjc-dispatch-method="), flagpd1("fobjc-exceptions"), flagpd1("fobjc-gc"), flagpd1("fobjc-gc-only"), @@ -3874,91 +2899,50 @@ flagpd1("fobjc-legacy-dispatch"), flagpd1("fobjc-link-runtime"), flagpd1("fobjc-new-property"), flagpd1("fobjc-nonfragile-abi"), -joinpd1("fobjc-nonfragile-abi-version="), -joinpd1("fobjc-runtime="), flagpd1("fobjc-runtime-has-weak"), flagpd1("fobjc-sender-dependent-dispatch"), flagpd1("fobjc-subscripting-legacy-runtime"), flagpd1("fobjc-weak"), flagpd1("fomit-frame-pointer"), flagpd1("fopenmp"), -joinpd1("fopenmp="), -joinpd1("fopenmp-cuda-blocks-per-sm="), flagpd1("fopenmp-cuda-force-full-runtime"), flagpd1("fopenmp-cuda-mode"), -joinpd1("fopenmp-cuda-number-of-sm="), -joinpd1("fopenmp-cuda-teams-reduction-recs-num="), flagpd1("fopenmp-enable-irbuilder"), sepd1("fopenmp-host-ir-file-path"), flagpd1("fopenmp-is-device"), flagpd1("fopenmp-optimistic-collapse"), flagpd1("fopenmp-relocatable-target"), flagpd1("fopenmp-simd"), -.{ - .name = "fopenmp-targets=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fopenmp-use-tls"), -joinpd1("fopenmp-version="), sepd1("foperator-arrow-depth"), -joinpd1("foperator-arrow-depth="), -joinpd1("foptimization-record-file="), -joinpd1("foptimization-record-passes="), flagpd1("foptimize-sibling-calls"), flagpd1("force_cpusubtype_ALL"), flagpd1("force_flat_namespace"), sepd1("force_load"), -joinpd1("fforce-addr"), flagpd1("forder-file-instrumentation"), -joinpd1("foutput-class-dir="), -joinpd1("foverride-record-layout="), flagpd1("fpack-struct"), -joinpd1("fpack-struct="), flagpd1("fpadding-on-unsigned-fixed-point"), flagpd1("fparse-all-comments"), flagpd1("fpascal-strings"), -joinpd1("fpass-plugin="), -joinpd1("fpatchable-function-entry="), -joinpd1("fpatchable-function-entry-offset="), flagpd1("fpcc-struct-return"), flagpd1("fpch-preprocess"), flagpd1("fpch-validate-input-files-content"), flagpd1("fpic"), flagpd1("fpie"), flagpd1("fplt"), -joinpd1("fplugin="), -joinpd1("fprebuilt-module-path="), flagpd1("fpreserve-as-comments"), flagpd1("fpreserve-vec3-type"), flagpd1("fprofile-arcs"), -joinpd1("fprofile-dir="), -joinpd1("fprofile-exclude-files="), -joinpd1("fprofile-filter-files="), flagpd1("fprofile-generate"), -joinpd1("fprofile-generate="), flagpd1("fprofile-instr-generate"), -joinpd1("fprofile-instr-generate="), flagpd1("fprofile-instr-use"), -joinpd1("fprofile-instr-use="), -joinpd1("fprofile-instrument="), -joinpd1("fprofile-instrument-path="), -joinpd1("fprofile-instrument-use-path="), sepd1("fprofile-remapping-file"), -joinpd1("fprofile-remapping-file="), flagpd1("fprofile-sample-accurate"), flagpd1("fprofile-sample-use"), -joinpd1("fprofile-sample-use="), flagpd1("fprofile-use"), -joinpd1("fprofile-use="), sepd1("framework"), -joinpd1("frandom-seed="), flagpd1("freciprocal-math"), flagpd1("frecord-command-line"), -joinpd1("frecord-marker="), flagpd1("ffree-form"), flagpd1("fno-free-form"), flagpd1("freg-struct-return"), @@ -3969,7 +2953,6 @@ flagpd1("fretain-comments-from-system-headers"), flagpd1("frewrite-imports"), flagpd1("frewrite-includes"), sepd1("frewrite-map-file"), -joinpd1("frewrite-map-file="), flagpd1("ffriend-injection"), flagpd1("fno-friend-injection"), flagpd1("ffrontend-optimize"), @@ -3979,31 +2962,13 @@ flagpd1("frounding-math"), flagpd1("frtlib-add-rpath"), flagpd1("frtti"), flagpd1("frwpi"), -.{ - .name = "fsanitize=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, -joinpd1("fsanitize-address-field-padding="), flagpd1("fsanitize-address-globals-dead-stripping"), flagpd1("fsanitize-address-poison-custom-array-cookie"), flagpd1("fsanitize-address-use-after-scope"), flagpd1("fsanitize-address-use-odr-indicator"), -joinpd1("fsanitize-blacklist="), flagpd1("fsanitize-cfi-canonical-jump-tables"), flagpd1("fsanitize-cfi-cross-dso"), flagpd1("fsanitize-cfi-icall-generalize-pointers"), -.{ - .name = "fsanitize-coverage=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fsanitize-coverage-8bit-counters"), flagpd1("fsanitize-coverage-indirect-calls"), flagpd1("fsanitize-coverage-inline-8bit-counters"), @@ -4016,45 +2981,22 @@ flagpd1("fsanitize-coverage-trace-div"), flagpd1("fsanitize-coverage-trace-gep"), flagpd1("fsanitize-coverage-trace-pc"), flagpd1("fsanitize-coverage-trace-pc-guard"), -joinpd1("fsanitize-coverage-type="), -joinpd1("fsanitize-hwaddress-abi="), flagpd1("fsanitize-link-c++-runtime"), flagpd1("fsanitize-link-runtime"), flagpd1("fsanitize-memory-track-origins"), -joinpd1("fsanitize-memory-track-origins="), flagpd1("fsanitize-memory-use-after-dtor"), flagpd1("fsanitize-minimal-runtime"), flagpd1("fsanitize-recover"), -.{ - .name = "fsanitize-recover=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("fsanitize-stats"), -joinpd1("fsanitize-system-blacklist="), flagpd1("fsanitize-thread-atomics"), flagpd1("fsanitize-thread-func-entry-exit"), flagpd1("fsanitize-thread-memory-access"), -.{ - .name = "fsanitize-trap=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, -joinpd1("fsanitize-undefined-strip-path-components="), flagpd1("fsanitize-undefined-trap-on-error"), flagpd1("fsave-optimization-record"), -joinpd1("fsave-optimization-record="), flagpd1("fseh-exceptions"), flagpd1("fshort-enums"), flagpd1("fshort-wchar"), flagpd1("fshow-column"), -joinpd1("fshow-overloads="), flagpd1("fshow-source-location"), flagpd1("fsignaling-math"), flagpd1("fsigned-bitfields"), @@ -4066,7 +3008,6 @@ flagpd1("fsjlj-exceptions"), flagpd1("fslp-vectorize"), flagpd1("fspell-checking"), sepd1("fspell-checking-limit"), -joinpd1("fspell-checking-limit="), flagpd1("fsplit-dwarf-inlining"), flagpd1("fsplit-lto-unit"), flagpd1("fsplit-stack"), @@ -4083,31 +3024,18 @@ flagpd1("fstrict-return"), flagpd1("fstrict-vtable-pointers"), flagpd1("fstruct-path-tbaa"), flagpd1("fsycl-is-device"), -joinpd1("fsymbol-partition="), flagpd1("fsyntax-only"), sepd1("ftabstop"), -joinpd1("ftabstop="), sepd1("ftemplate-backtrace-limit"), -joinpd1("ftemplate-backtrace-limit="), sepd1("ftemplate-depth"), -joinpd1("ftemplate-depth-"), -joinpd1("ftemplate-depth="), flagpd1("ftest-coverage"), -joinpd1("ftest-module-file-extension="), -joinpd1("fthin-link-bitcode="), -joinpd1("fthinlto-index="), flagpd1("fthreadsafe-statics"), flagpd1("ftime-report"), flagpd1("ftime-trace"), -joinpd1("ftime-trace-granularity="), -joinpd1("ftls-model="), -joinpd1("ftrap-function="), flagpd1("ftrapping-math"), flagpd1("ftrapv"), sepd1("ftrapv-handler"), -joinpd1("ftrapv-handler="), flagpd1("ftrigraphs"), -joinpd1("ftrivial-auto-var-init="), sepd1("ftype-visibility"), sepd1("function-alignment"), flagpd1("ffunction-attribute-list"), @@ -4122,35 +3050,24 @@ flagpd1("funsigned-char"), flagpd1("funwind-tables"), flagpd1("fuse-cxa-atexit"), flagpd1("fuse-init-array"), -joinpd1("fuse-ld="), flagpd1("fuse-line-directives"), flagpd1("fuse-register-sized-bitfield-access"), flagpd1("fvalidate-ast-input-files-content"), -joinpd1("fveclib="), flagpd1("fvectorize"), flagpd1("fverbose-asm"), flagpd1("fvirtual-function-elimination"), sepd1("fvisibility"), -joinpd1("fvisibility="), flagpd1("fvisibility-global-new-delete-hidden"), flagpd1("fvisibility-inlines-hidden"), flagpd1("fvisibility-ms-compat"), flagpd1("fwasm-exceptions"), -joinpd1("fwchar-type="), flagpd1("fwhole-program-vtables"), flagpd1("fwrapv"), flagpd1("fwritable-strings"), flagpd1("fxray-always-emit-customevents"), flagpd1("fxray-always-emit-typedevents"), -jspd1("fxray-always-instrument="), -jspd1("fxray-attr-list="), -jspd1("fxray-instruction-threshold"), -jspd1("fxray-instruction-threshold="), flagpd1("fxray-instrument"), -jspd1("fxray-instrumentation-bundle="), flagpd1("fxray-link-deps"), -jspd1("fxray-modes="), -jspd1("fxray-never-instrument="), flagpd1("fzero-initialized-in-bss"), flagpd1("fzvector"), flagpd1("g0"), @@ -4158,18 +3075,9 @@ flagpd1("g1"), flagpd1("g2"), flagpd1("g3"), flagpd1("g"), -.{ - .name = "gcc-toolchain=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, sepd1("gcc-toolchain"), flagpd1("gcodeview"), flagpd1("gcodeview-ghash"), -joinpd1("gcoff"), flagpd1("gcolumn-info"), flagpd1("fgcse-after-reload"), flagpd1("fno-gcse-after-reload"), @@ -4211,53 +3119,23 @@ flagpd1("gno-record-command-line"), flagpd1("gno-strict-dwarf"), flagpd1("fgnu"), flagpd1("fno-gnu"), -.{ - .name = "gpu-max-threads-per-block=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("gpubnames"), flagpd1("grecord-command-line"), flagpd1("gsce"), flagpd1("gsplit-dwarf"), -joinpd1("gsplit-dwarf="), -joinpd1("gstabs"), flagpd1("gstrict-dwarf"), flagpd1("gtoggle"), flagpd1("gused"), -joinpd1("gvms"), -joinpd1("gxcoff"), flagpd1("gz"), -joinpd1("gz="), sepd1("header-include-file"), -joinpd1("headerpad_max_install_names"), .{ .name = "help", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .passthrough, .pd1 = true, .pd2 = true, .psl = false, }, -.{ - .name = "hip-device-lib=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "hip-device-lib-path=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "hip-link", .syntax = .flag, @@ -4266,17 +3144,6 @@ joinpd1("headerpad_max_install_names"), .pd2 = true, .psl = false, }, -jspd1("idirafter"), -jspd1("iframework"), -jspd1("iframeworkwithsysroot"), -.{ - .name = "imacros", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, sepd1("image_base"), flagpd1("fimplement-inlines"), flagpd1("fno-implement-inlines"), @@ -4285,14 +3152,6 @@ flagpd1("fno-implicit-none"), flagpd1("fimplicit-templates"), flagpd1("fno-implicit-templates"), sepd1("imultilib"), -.{ - .name = "include", - .syntax = .joined_or_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, sepd1("include-pch"), flagpd1("index-header-map"), sepd1("init"), @@ -4306,51 +3165,15 @@ flagpd1("fno-inline-small-functions"), sepd1("install_name"), flagpd1("finteger-4-integer-8"), flagpd1("fno-integer-4-integer-8"), -jspd1("interface-stub-version="), -jspd1("internal-externc-isystem"), -jspd1("internal-isystem"), flagpd1("fintrinsic-modules-path"), flagpd1("fno-intrinsic-modules-path"), flagpd1("fipa-cp"), flagpd1("fno-ipa-cp"), -jspd1("iprefix"), -jspd1("iquote"), -jspd1("isysroot"), -jspd1("isystem"), -jspd1("isystem-after"), -jspd1("ivfsoverlay"), flagpd1("fivopts"), flagpd1("fno-ivopts"), -jspd1("iwithprefix"), -jspd1("iwithprefixbefore"), -jspd1("iwithsysroot"), flagpd1("keep_private_externs"), -.{ - .name = "l", - .syntax = .joined_or_separate, - .zig_equivalent = .l, - .pd1 = true, - .pd2 = false, - .psl = false, -}, sepd1("lazy_framework"), sepd1("lazy_library"), -.{ - .name = "libomptarget-nvptx-path=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "linker-option=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, sepd1("load"), flagpd1("m16"), flagpd1("m32"), @@ -4358,34 +3181,14 @@ flagpd1("m3dnow"), flagpd1("m3dnowa"), flagpd1("m64"), flagpd1("m80387"), -joinpd1("mabi="), flagpd1("mabi=ieeelongdouble"), flagpd1("mabicalls"), -joinpd1("mabs="), flagpd1("madx"), flagpd1("maes"), sepd1("main-file-name"), -.{ - .name = "malign-branch=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, -joinpd1("malign-branch-boundary="), -joinpd1("malign-branch-prefix-size="), flagpd1("malign-double"), -joinpd1("malign-functions="), -joinpd1("malign-jumps="), -joinpd1("malign-loops="), flagpd1("maltivec"), -joinpd1("mamdgpu-debugger-abi="), -joinpd1("mappletvos-version-min="), -joinpd1("mappletvsimulator-version-min="), -joinpd1("march="), flagpd1("marm"), -joinpd1("masm="), flagpd1("masm-verbose"), flagpd1("massembler-fatal-warnings"), flagpd1("massembler-no-warn"), @@ -4414,7 +3217,6 @@ flagpd1("mbig-endian"), flagpd1("mbmi"), flagpd1("mbmi2"), flagpd1("mbranch-likely"), -joinpd1("mbranch-protection="), flagpd1("mbranch-target-enforce"), flagpd1("mbranches-within-32B-boundaries"), flagpd1("mbulk-memory"), @@ -4423,32 +3225,25 @@ flagpd1("mcldemote"), flagpd1("mclflushopt"), flagpd1("mclwb"), flagpd1("mclzero"), -joinpd1("mcmodel="), flagpd1("mcmodel=medany"), flagpd1("mcmodel=medlow"), flagpd1("mcmpb"), flagpd1("mcmse"), sepd1("mcode-model"), flagpd1("mcode-object-v3"), -joinpd1("mcompact-branches="), -joinpd1("mconsole"), flagpd1("mconstant-cfstrings"), flagpd1("mconstructor-aliases"), -joinpd1("mcpu="), flagpd1("mcpu=?"), flagpd1("mcrbits"), flagpd1("mcrc"), flagpd1("mcumode"), flagpd1("mcx16"), sepd1("mdebug-pass"), -joinpd1("mdefault-build-attributes"), flagpd1("mdirect-move"), flagpd1("mdisable-tail-calls"), -joinpd1("mdll"), flagpd1("mdouble-float"), flagpd1("mdsp"), flagpd1("mdspr2"), -joinpd1("mdynamic-no-pic"), sepd1("meabi"), flagpd1("membedded-data"), flagpd1("menable-no-infs"), @@ -4467,17 +3262,13 @@ flagpd1("mfix-and-continue"), flagpd1("mfix-cortex-a53-835769"), flagpd1("mfloat128"), sepd1("mfloat-abi"), -joinpd1("mfloat-abi="), flagpd1("mfma"), flagpd1("mfma4"), flagpd1("mfp32"), flagpd1("mfp64"), sepd1("mfpmath"), -joinpd1("mfpmath="), flagpd1("mfprnd"), -joinpd1("mfpu="), flagpd1("mfpxx"), -joinpd1("mframe-pointer="), flagpd1("mfsgsbase"), flagpd1("mfxsr"), flagpd1("mgeneral-regs-only"), @@ -4488,11 +3279,7 @@ flagpd1("mglobal-merge"), flagpd1("mgpopt"), flagpd1("mhard-float"), flagpd1("mhvx"), -joinpd1("mhvx="), -joinpd1("mhvx-length="), flagpd1("mhtm"), -joinpd1("mhwdiv="), -joinpd1("mhwmult="), flagpd1("miamcu"), flagpd1("mieee-fp"), flagpd1("mieee-rnd-near"), @@ -4500,16 +3287,10 @@ flagpd1("migrate"), flagpd1("no-finalize-removal"), flagpd1("no-ns-alloc-error"), flagpd1("mimplicit-float"), -joinpd1("mimplicit-it="), flagpd1("mincremental-linker-compatible"), -joinpd1("mindirect-jump="), flagpd1("minline-all-stringops"), flagpd1("minvariant-function-descriptors"), flagpd1("minvpcid"), -joinpd1("mios-simulator-version-min="), -joinpd1("mios-version-min="), -joinpd1("miphoneos-version-min="), -joinpd1("miphonesimulator-version-min="), flagpd1("mips1"), flagpd1("mips16"), flagpd1("mips2"), @@ -4533,7 +3314,6 @@ sepd1("mlimit-float-precision"), sepd1("mlink-bitcode-file"), sepd1("mlink-builtin-bitcode"), sepd1("mlink-cuda-bitcode"), -joinpd1("mlinker-version="), flagpd1("mlittle-endian"), sepd1("mllvm"), flagpd1("mlocal-sdata"), @@ -4544,10 +3324,7 @@ flagpd1("mlong-double-80"), flagpd1("mlongcall"), flagpd1("mlwp"), flagpd1("mlzcnt"), -joinpd1("mmacos-version-min="), -joinpd1("mmacosx-version-min="), flagpd1("mmadd4"), -joinpd1("mmcu="), flagpd1("mmemops"), flagpd1("mmfcrf"), flagpd1("mmfocrf"), @@ -4563,7 +3340,6 @@ flagpd1("mmt"), flagpd1("mmultivalue"), flagpd1("mmutable-globals"), flagpd1("mmwaitx"), -joinpd1("mnan="), flagpd1("mno-3dnow"), flagpd1("mno-3dnowa"), flagpd1("mno-80387"), @@ -4606,7 +3382,6 @@ flagpd1("mno-crbits"), flagpd1("mno-crc"), flagpd1("mno-cumode"), flagpd1("mno-cx16"), -joinpd1("mno-default-build-attributes"), flagpd1("mno-dsp"), flagpd1("mno-dspr2"), flagpd1("mno-embedded-data"), @@ -4761,7 +3536,6 @@ flagpd1("fno-modulo-sched-allow-regmoves"), flagpd1("fmodulo-sched"), flagpd1("fno-modulo-sched"), flagpd1("momit-leaf-frame-pointer"), -joinpd1("moslib="), flagpd1("moutline"), flagpd1("mpacked-stack"), flagpd1("mpackets"), @@ -4775,7 +3549,6 @@ flagpd1("mpopcntd"), flagpd1("mcrypto"), flagpd1("mpower8-vector"), flagpd1("mpower9-vector"), -joinpd1("mprefer-vector-width="), flagpd1("mprefetchwt1"), flagpd1("mprfchw"), flagpd1("mptwrite"), @@ -4787,19 +3560,10 @@ flagpd1("mrdrnd"), flagpd1("mrdseed"), flagpd1("mreassociate"), flagpd1("mrecip"), -.{ - .name = "mrecip=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("mrecord-mcount"), flagpd1("mred-zone"), flagpd1("mreference-types"), sepd1("mregparm"), -joinpd1("mregparm="), flagpd1("mrelax"), flagpd1("mrelax-all"), flagpd1("mrelax-pic-calls"), @@ -4825,11 +3589,8 @@ flagpd1("msgx"), flagpd1("msha"), flagpd1("mshstk"), flagpd1("msign-ext"), -joinpd1("msign-return-address="), -joinpd1("msign-return-address-key="), flagpd1("msimd128"), flagpd1("msingle-float"), -joinpd1("msmall-data-threshold="), flagpd1("msoft-float"), flagpd1("mspe"), flagpd1("mspeculative-load-hardening"), @@ -4842,31 +3603,22 @@ flagpd1("msse4.1"), flagpd1("msse4.2"), flagpd1("msse4a"), flagpd1("mssse3"), -joinpd1("mstack-alignment="), flagpd1("mstack-arg-probe"), -joinpd1("mstack-probe-size="), flagpd1("mstackrealign"), flagpd1("mstrict-align"), sepd1("mt-migrate-directory"), flagpd1("mtail-call"), flagpd1("mtbm"), sepd1("mthread-model"), -joinpd1("mthreads"), flagpd1("mthumb"), flagpd1("mtls-direct-seg-refs"), -joinpd1("mtls-size="), sepd1("mtp"), -joinpd1("mtp="), -joinpd1("mtune="), flagpd1("mtune=?"), -joinpd1("mtvos-simulator-version-min="), -joinpd1("mtvos-version-min="), flagpd1("muclibc"), flagpd1("multi_module"), sepd1("multiply_defined"), sepd1("multiply_defined_unused"), flagpd1("munaligned-access"), -joinpd1("municode"), flagpd1("munimplemented-simd128"), flagpd1("munwind-tables"), flagpd1("mv5"), @@ -4883,12 +3635,8 @@ flagpd1("mvx"), flagpd1("mvzeroupper"), flagpd1("mwaitpkg"), flagpd1("mwarn-nonportable-cfstrings"), -joinpd1("mwatchos-simulator-version-min="), -joinpd1("mwatchos-version-min="), -joinpd1("mwatchsimulator-version-min="), flagpd1("mwavefrontsize64"), flagpd1("mwbnoinvd"), -joinpd1("mwindows"), flagpd1("mx32"), flagpd1("mx87"), flagpd1("mxgot"), @@ -4906,22 +3654,6 @@ flagpd1("no-canonical-prefixes"), flagpd1("no-code-completion-globals"), flagpd1("no-code-completion-ns-level-decls"), flagpd1("no-cpp-precomp"), -.{ - .name = "no-cuda-gpu-arch=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "no-cuda-include-ptx=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, .{ .name = "no-cuda-noopt-device-debug", .syntax = .flag, @@ -4959,14 +3691,6 @@ flagpd1("no-implicit-float"), flagpd1("no-pie"), flagpd1("no-pthread"), flagpd1("no-struct-path-tbaa"), -.{ - .name = "no-system-header-prefix=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("nobuiltininc"), flagpd1("nocpp"), flagpd1("nocudainc"), @@ -4984,19 +3708,17 @@ flagpd1("noseglinkedit"), flagpd1("nostartfiles"), flagpd1("nostdinc"), flagpd1("nostdinc++"), -flagpd1("nostdlib"), -flagpd1("nostdlibinc"), -flagpd1("nostdlib++"), -flagpd1("nostdsysteminc"), .{ - .name = "o", - .syntax = .joined_or_separate, - .zig_equivalent = .o, + .name = "nostdlib", + .syntax = .flag, + .zig_equivalent = .nostdlib, .pd1 = true, .pd2 = false, .psl = false, }, -jspd1("objc-isystem"), +flagpd1("nostdlibinc"), +flagpd1("nostdlib++"), +flagpd1("nostdsysteminc"), flagpd1("objcmt-atomic-property"), flagpd1("objcmt-migrate-all"), flagpd1("objcmt-migrate-annotation"), @@ -5012,8 +3734,6 @@ flagpd1("objcmt-migrate-readwrite-property"), flagpd1("objcmt-migrate-subscripting"), flagpd1("objcmt-ns-nonatomic-iosonly"), flagpd1("objcmt-returns-innerpointer-property"), -joinpd1("objcmt-whitelist-dir-path="), -jspd1("objcxx-isystem"), flagpd1("object"), sepd1("opt-record-file"), sepd1("opt-record-format"), @@ -5022,7 +3742,6 @@ sepd1("output-asm-variant"), flagpd1("p"), flagpd1("fpack-derived"), flagpd1("fno-pack-derived"), -jspd1("pagezero_size"), .{ .name = "pass-exit-codes", .syntax = .flag, @@ -5033,7 +3752,6 @@ jspd1("pagezero_size"), }, flagpd1("pch-through-hdrstop-create"), flagpd1("pch-through-hdrstop-use"), -joinpd1("pch-through-header="), .{ .name = "pedantic", .syntax = .flag, @@ -5061,21 +3779,12 @@ flagpd1("pie"), .{ .name = "pipe", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .ignore, .pd1 = true, .pd2 = true, .psl = false, }, sepd1("plugin"), -.{ - .name = "plugin-arg-", - .syntax = .joined_and_separate, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, -joinpd1("preamble-bytes="), flagpd1("prebind"), flagpd1("prebind_all_twolevel_modules"), flagpd1("fprefetch-loop-arrays"), @@ -5090,14 +3799,6 @@ flagpd1("print-dependency-directives-minimized-source"), .pd2 = true, .psl = false, }, -.{ - .name = "print-file-name=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, flagpd1("print-ivar-layout"), .{ .name = "print-libgcc-file-name", @@ -5132,14 +3833,6 @@ flagpd1("print-ivar-layout"), .psl = false, }, flagpd1("print-preamble"), -.{ - .name = "print-prog-name=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, .{ .name = "print-resource-dir", .syntax = .flag, @@ -5190,18 +3883,17 @@ flagpd1("fprotect-parens"), flagpd1("fno-protect-parens"), flagpd1("pthread"), flagpd1("pthreads"), -.{ - .name = "ptxas-path=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("r"), flagpd1("frange-check"), flagpd1("fno-range-check"), -flagpd1("rdynamic"), +.{ + .name = "rdynamic", + .syntax = .flag, + .zig_equivalent = .rdynamic, + .pd1 = true, + .pd2 = false, + .psl = false, +}, sepd1("read_only_relocs"), flagpd1("freal-4-real-10"), flagpd1("fno-real-4-real-10"), @@ -5240,7 +3932,6 @@ flagpd1("fno-reorder-blocks"), flagpd1("frepack-arrays"), flagpd1("fno-repack-arrays"), sepd1("resource-dir"), -joinpd1("resource-dir="), flagpd1("rewrite-legacy-objc"), flagpd1("rewrite-macros"), flagpd1("rewrite-objc"), @@ -5248,22 +3939,6 @@ flagpd1("rewrite-test"), flagpd1("fripa"), flagpd1("fno-ripa"), sepd1("rpath"), -.{ - .name = "rsp-quoting=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, -.{ - .name = "rtlib=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, flagpd1("s"), .{ .name = "save-stats", @@ -5273,14 +3948,6 @@ flagpd1("s"), .pd2 = true, .psl = false, }, -.{ - .name = "save-stats=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, .{ .name = "save-temps", .syntax = .flag, @@ -5289,14 +3956,6 @@ flagpd1("s"), .pd2 = true, .psl = false, }, -.{ - .name = "save-temps=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, flagpd1("fschedule-insns2"), flagpd1("fno-schedule-insns2"), flagpd1("fschedule-insns"), @@ -5305,7 +3964,7 @@ flagpd1("fsecond-underscore"), flagpd1("fno-second-underscore"), .{ .name = "sectalign", - .syntax = .{ .multi_arg = 3 }, + .syntax = .{.multi_arg=3}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, @@ -5313,7 +3972,7 @@ flagpd1("fno-second-underscore"), }, .{ .name = "sectcreate", - .syntax = .{ .multi_arg = 3 }, + .syntax = .{.multi_arg=3}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, @@ -5321,7 +3980,7 @@ flagpd1("fno-second-underscore"), }, .{ .name = "sectobjectsymbols", - .syntax = .{ .multi_arg = 2 }, + .syntax = .{.multi_arg=2}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, @@ -5329,7 +3988,7 @@ flagpd1("fno-second-underscore"), }, .{ .name = "sectorder", - .syntax = .{ .multi_arg = 3 }, + .syntax = .{.multi_arg=3}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, @@ -5337,12 +3996,11 @@ flagpd1("fno-second-underscore"), }, flagpd1("fsee"), flagpd1("fno-see"), -jspd1("seg1addr"), sepd1("seg_addr_table"), sepd1("seg_addr_table_filename"), .{ .name = "segaddr", - .syntax = .{ .multi_arg = 2 }, + .syntax = .{.multi_arg=2}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, @@ -5350,7 +4008,7 @@ sepd1("seg_addr_table_filename"), }, .{ .name = "segcreate", - .syntax = .{ .multi_arg = 3 }, + .syntax = .{.multi_arg=3}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, @@ -5359,20 +4017,19 @@ sepd1("seg_addr_table_filename"), flagpd1("seglinkedit"), .{ .name = "segprot", - .syntax = .{ .multi_arg = 3 }, + .syntax = .{.multi_arg=3}, .zig_equivalent = .other, .pd1 = true, .pd2 = false, .psl = false, }, -joinpd1("segs_read_"), sepd1("segs_read_only_addr"), sepd1("segs_read_write_addr"), flagpd1("setup-static-analyzer"), .{ .name = "shared", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .shared, .pd1 = true, .pd2 = true, .psl = false, @@ -5406,14 +4063,6 @@ flagpd1("fno-spec-constr-count"), .pd2 = true, .psl = false, }, -.{ - .name = "specs=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, sepd1("split-dwarf-file"), sepd1("split-dwarf-output"), flagpd1("split-stacks"), @@ -5438,47 +4087,10 @@ flagpd1("static-libsan"), flagpd1("static-libstdc++"), flagpd1("static-openmp"), flagpd1("static-pie"), -joinpd1("stats-file="), -.{ - .name = "std=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, -joinpd1("std-default="), -.{ - .name = "stdlib=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, -jspd1("stdlib++-isystem"), flagpd1("fstrength-reduce"), flagpd1("fno-strength-reduce"), -jspd1("sub_library"), -jspd1("sub_umbrella"), flagpd1("sys-header-deps"), -.{ - .name = "system-header-prefix=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = false, - .pd2 = true, - .psl = false, -}, flagpd1("t"), -.{ - .name = "target=", - .syntax = .joined, - .zig_equivalent = .target, - .pd1 = false, - .pd2 = true, - .psl = false, -}, sepd1("target-abi"), sepd1("target-cpu"), sepd1("target-feature"), @@ -5491,7 +4103,6 @@ sepd1("target-feature"), .psl = false, }, sepd1("target-linker-version"), -joinpd1("target-sdk-version="), flagpd1("templight-dump"), flagpd1("test-coverage"), flagpd1("time"), @@ -5541,13 +4152,10 @@ flagpd1("fno-tree-vrp"), }, flagpd1("trim-egraph"), sepd1("triple"), -joinpd1("triple="), flagpd1("twolevel_namespace"), flagpd1("twolevel_namespace_hints"), -jspd1("u"), sepd1("umbrella"), flagpd1("undef"), -jspd1("undefined"), flagpd1("funderscoring"), flagpd1("fno-underscoring"), sepd1("unexported_symbols_list"), @@ -5557,14 +4165,6 @@ flagpd1("funsafe-loop-optimizations"), flagpd1("fno-unsafe-loop-optimizations"), flagpd1("funswitch-loops"), flagpd1("fno-unswitch-loops"), -.{ - .name = "unwindlib=", - .syntax = .joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = true, - .psl = false, -}, flagpd1("fuse-linker-plugin"), flagpd1("fno-use-linker-plugin"), flagpd1("v"), @@ -5575,14 +4175,6 @@ flagpd1("fno-vect-cost-model"), flagpd1("vectorize-loops"), flagpd1("vectorize-slp"), flagpd1("verify"), -.{ - .name = "verify=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, .{ .name = "verify-debug-info", .syntax = .flag, @@ -5592,14 +4184,6 @@ flagpd1("verify"), .psl = false, }, flagpd1("verify-ignore-unexpected"), -.{ - .name = "verify-ignore-unexpected=", - .syntax = .comma_joined, - .zig_equivalent = .other, - .pd1 = true, - .pd2 = false, - .psl = false, -}, flagpd1("verify-pch"), flagpd1("version"), .{ @@ -5610,12 +4194,10 @@ flagpd1("version"), .pd2 = true, .psl = false, }, -joinpd1("vtordisp-mode="), flagpd1("w"), sepd1("weak_framework"), sepd1("weak_library"), sepd1("weak_reference_mismatches"), -joinpd1("weak-l"), flagpd1("fweb"), flagpd1("fno-web"), flagpd1("whatsloaded"), @@ -5624,9 +4206,1455 @@ flagpd1("fno-whole-file"), flagpd1("fwhole-program"), flagpd1("fno-whole-program"), flagpd1("whyload"), -jspd1("working-directory"), +sepd1("z"), +joinpd1("fsanitize-undefined-strip-path-components="), +joinpd1("fopenmp-cuda-teams-reduction-recs-num="), +joinpd1("analyzer-config-compatibility-mode="), +joinpd1("fpatchable-function-entry-offset="), +joinpd1("analyzer-inline-max-stack-depth="), +joinpd1("fsanitize-address-field-padding="), +joinpd1("fdiagnostics-hotness-threshold="), +joinpd1("fsanitize-memory-track-origins="), +joinpd1("mwatchos-simulator-version-min="), +joinpd1("mappletvsimulator-version-min="), +joinpd1("fobjc-nonfragile-abi-version="), +joinpd1("fprofile-instrument-use-path="), +jspd1("fxray-instrumentation-bundle="), +joinpd1("miphonesimulator-version-min="), +joinpd1("faddress-space-map-mangling="), +joinpd1("foptimization-record-passes="), +joinpd1("ftest-module-file-extension="), +jspd1("fxray-instruction-threshold="), +joinpd1("mno-default-build-attributes"), +joinpd1("mtvos-simulator-version-min="), +joinpd1("mwatchsimulator-version-min="), +.{ + .name = "include-with-prefix-before=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("objcmt-white-list-dir-path="), +joinpd1("error-on-deserialized-decl="), +joinpd1("fconstexpr-backtrace-limit="), +joinpd1("fdiagnostics-show-category="), +joinpd1("fdiagnostics-show-location="), +joinpd1("fopenmp-cuda-blocks-per-sm="), +joinpd1("fsanitize-system-blacklist="), +jspd1("fxray-instruction-threshold"), +joinpd1("headerpad_max_install_names"), +joinpd1("mios-simulator-version-min="), +.{ + .name = "include-with-prefix-after=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fms-compatibility-version="), +joinpd1("fopenmp-cuda-number-of-sm="), +joinpd1("foptimization-record-file="), +joinpd1("fpatchable-function-entry="), +joinpd1("fsave-optimization-record="), +joinpd1("ftemplate-backtrace-limit="), +.{ + .name = "gpu-max-threads-per-block=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("malign-branch-prefix-size="), +joinpd1("objcmt-whitelist-dir-path="), +joinpd1("Wno-nonportable-cfstrings"), +joinpd1("analyzer-disable-checker="), +joinpd1("fbuild-session-timestamp="), +joinpd1("fprofile-instrument-path="), +joinpd1("mdefault-build-attributes"), +joinpd1("msign-return-address-key="), +.{ + .name = "verify-ignore-unexpected=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "include-directory-after=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "compress-debug-sections=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "fcomment-block-commands=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("flax-vector-conversions="), +joinpd1("fmodules-embed-all-files"), +joinpd1("fmodules-prune-interval="), +joinpd1("foverride-record-layout="), +joinpd1("fprofile-instr-generate="), +joinpd1("fprofile-remapping-file="), +joinpd1("fsanitize-coverage-type="), +joinpd1("fsanitize-hwaddress-abi="), +joinpd1("ftime-trace-granularity="), +jspd1("fxray-always-instrument="), +jspd1("internal-externc-isystem"), +.{ + .name = "libomptarget-nvptx-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "no-system-header-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output-class-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("analyzer-inlining-mode="), +joinpd1("fconstant-string-class="), +joinpd1("fcrash-diagnostics-dir="), +joinpd1("fdebug-compilation-dir="), +joinpd1("fdebug-default-version="), +joinpd1("ffp-exception-behavior="), +joinpd1("fmacro-backtrace-limit="), +joinpd1("fmax-array-constructor="), +joinpd1("fprofile-exclude-files="), +joinpd1("ftrivial-auto-var-init="), +jspd1("fxray-never-instrument="), +jspd1("interface-stub-version="), +joinpd1("malign-branch-boundary="), +joinpd1("mappletvos-version-min="), +joinpd1("Wnonportable-cfstrings"), +joinpd1("fdefault-calling-conv="), +joinpd1("fmax-subrecord-length="), +joinpd1("fmodules-ignore-macro="), +.{ + .name = "fno-sanitize-coverage=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fobjc-dispatch-method="), +joinpd1("foperator-arrow-depth="), +joinpd1("fprebuilt-module-path="), +joinpd1("fprofile-filter-files="), +joinpd1("fspell-checking-limit="), +joinpd1("miphoneos-version-min="), +joinpd1("msmall-data-threshold="), +joinpd1("Wlarge-by-value-copy="), +joinpd1("analyzer-constraints="), +joinpd1("analyzer-dump-egraph="), +jspd1("compatibility_version"), +jspd1("dylinker_install_name"), +joinpd1("fcs-profile-generate="), +joinpd1("fmodules-prune-after="), +.{ + .name = "fno-sanitize-recover=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("iframeworkwithsysroot"), +joinpd1("mamdgpu-debugger-abi="), +joinpd1("mprefer-vector-width="), +joinpd1("msign-return-address="), +joinpd1("mwatchos-version-min="), +.{ + .name = "system-header-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-with-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("coverage-notes-file="), +joinpd1("fbuild-session-file="), +joinpd1("fdiagnostics-format="), +joinpd1("fmax-stack-var-size="), +joinpd1("fmodules-cache-path="), +joinpd1("fmodules-embed-file="), +joinpd1("fprofile-instrument="), +joinpd1("fprofile-sample-use="), +joinpd1("fsanitize-blacklist="), +.{ + .name = "hip-device-lib-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("mmacosx-version-min="), +.{ + .name = "no-cuda-include-ptx=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("Wframe-larger-than="), +joinpd1("code-completion-at="), +joinpd1("coverage-data-file="), +joinpd1("fblas-matmul-limit="), +joinpd1("fdiagnostics-color="), +joinpd1("ffixed-line-length-"), +joinpd1("flimited-precision="), +joinpd1("fprofile-instr-use="), +.{ + .name = "fsanitize-coverage=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fthin-link-bitcode="), +joinpd1("mbranch-protection="), +joinpd1("mmacos-version-min="), +joinpd1("pch-through-header="), +joinpd1("target-sdk-version="), +.{ + .name = "execution-charset:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "include-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "library-directory=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "config-system-dir=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fclang-abi-compat="), +joinpd1("fcompile-resource="), +joinpd1("fdebug-prefix-map="), +joinpd1("fdenormal-fp-math="), +joinpd1("fexcess-precision="), +joinpd1("ffree-line-length-"), +joinpd1("fmacro-prefix-map="), +.{ + .name = "fno-sanitize-trap=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fobjc-abi-version="), +joinpd1("foutput-class-dir="), +joinpd1("fprofile-generate="), +joinpd1("frewrite-map-file="), +.{ + .name = "fsanitize-recover=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fsymbol-partition="), +joinpd1("mcompact-branches="), +joinpd1("mstack-probe-size="), +joinpd1("mtvos-version-min="), joinpd1("working-directory="), +joinpd1("analyze-function="), +joinpd1("analyzer-checker="), +joinpd1("coverage-version="), +.{ + .name = "cuda-include-ptx=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("falign-functions="), +joinpd1("fconstexpr-depth="), +joinpd1("fconstexpr-steps="), +joinpd1("ffile-prefix-map="), +joinpd1("fmodule-map-file="), +joinpd1("fobjc-arc-cxxlib="), +jspd1("iwithprefixbefore"), +joinpd1("malign-functions="), +joinpd1("mios-version-min="), +joinpd1("mstack-alignment="), +.{ + .name = "no-cuda-gpu-arch=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +jspd1("working-directory"), +joinpd1("analyzer-output="), +.{ + .name = "config-user-dir=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("debug-info-kind="), +joinpd1("debugger-tuning="), +joinpd1("fcf-runtime-abi="), +joinpd1("finit-character="), +joinpd1("fmax-type-align="), +joinpd1("fmessage-length="), +.{ + .name = "fopenmp-targets=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fopenmp-version="), +joinpd1("fshow-overloads="), +joinpd1("ftemplate-depth-"), +joinpd1("ftemplate-depth="), +jspd1("fxray-attr-list="), +jspd1("internal-isystem"), +joinpd1("mlinker-version="), +.{ + .name = "print-file-name=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "print-prog-name=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +jspd1("stdlib++-isystem"), +joinpd1("Rpass-analysis="), +.{ + .name = "Xopenmp-target=", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "source-charset:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "analyzer-output", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "undefine-macro=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("analyzer-purge="), +joinpd1("analyzer-store="), +jspd1("current_version"), +joinpd1("fbootclasspath="), +joinpd1("fbracket-depth="), +joinpd1("fcf-protection="), +joinpd1("fdepfile-entry="), +joinpd1("fembed-bitcode="), +joinpd1("finput-charset="), +joinpd1("fmodule-format="), +joinpd1("fms-memptr-rep="), +joinpd1("fnew-alignment="), +joinpd1("frecord-marker="), +.{ + .name = "fsanitize-trap=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fthinlto-index="), +joinpd1("ftrap-function="), +joinpd1("ftrapv-handler="), +.{ + .name = "hip-device-lib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("mdynamic-no-pic"), +joinpd1("mframe-pointer="), +joinpd1("mindirect-jump="), +joinpd1("preamble-bytes="), +.{ + .name = "bootclasspath=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-gpu-arch=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "dependent-lib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("dwarf-version="), +joinpd1("falign-labels="), +joinpd1("fauto-profile="), +joinpd1("fexec-charset="), +joinpd1("fgnuc-version="), +joinpd1("finit-integer="), +joinpd1("finit-logical="), +joinpd1("finline-limit="), +joinpd1("fobjc-runtime="), +.{ + .name = "gcc-toolchain=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "linker-option=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "malign-branch=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("objcxx-isystem"), +joinpd1("vtordisp-mode="), +joinpd1("Rpass-missed="), +joinpd1("Wlarger-than-"), +joinpd1("Wlarger-than="), +.{ + .name = "define-macro=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("ast-dump-all="), +.{ + .name = "autocomplete=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("falign-jumps="), +joinpd1("falign-loops="), +joinpd1("faligned-new="), +joinpd1("ferror-limit="), +joinpd1("ffp-contract="), +joinpd1("fmodule-file="), +joinpd1("fmodule-name="), +joinpd1("fmsc-version="), +.{ + .name = "fno-sanitize=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("fpack-struct="), +joinpd1("fpass-plugin="), +joinpd1("fprofile-dir="), +joinpd1("fprofile-use="), +joinpd1("frandom-seed="), +joinpd1("gsplit-dwarf="), +jspd1("isystem-after"), +joinpd1("malign-jumps="), +joinpd1("malign-loops="), +joinpd1("mimplicit-it="), +jspd1("pagezero_size"), +joinpd1("resource-dir="), +.{ + .name = "dyld-prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "driver-mode=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fmax-errors="), +joinpd1("fno-builtin-"), +joinpd1("fvisibility="), +joinpd1("fwchar-type="), +jspd1("fxray-modes="), +jspd1("iwithsysroot"), +joinpd1("mhvx-length="), +jspd1("objc-isystem"), +.{ + .name = "rsp-quoting=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("std-default="), +jspd1("sub_umbrella"), +.{ + .name = "Qpar-report", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Qvec-report", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "errorReport", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "for-linker=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "force-link=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +jspd1("client_name"), +jspd1("cxx-isystem"), +joinpd1("fclasspath="), +joinpd1("finit-real="), +joinpd1("fforce-addr"), +joinpd1("ftls-model="), +jspd1("ivfsoverlay"), +jspd1("iwithprefix"), +joinpd1("mfloat-abi="), +.{ + .name = "plugin-arg-", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "ptxas-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-stats=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "save-temps=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +joinpd1("stats-file="), +jspd1("sub_library"), +.{ + .name = "CLASSPATH=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "constexpr:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "classpath=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cuda-path=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fencoding="), +joinpd1("ffp-model="), +joinpd1("ffpe-trap="), +joinpd1("flto-jobs="), +.{ + .name = "fsanitize=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("iframework"), +joinpd1("mtls-size="), +joinpd1("segs_read_"), +.{ + .name = "unwindlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cgthreads", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "encoding=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "language=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "optimize=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "resource=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("ast-dump="), +jspd1("c-isystem"), +joinpd1("fcoarray="), +joinpd1("fconvert="), +joinpd1("fextdirs="), +joinpd1("ftabstop="), +jspd1("idirafter"), +joinpd1("mregparm="), +jspd1("undefined"), +.{ + .name = "extdirs=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "imacros=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "sysroot=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fopenmp="), +joinpd1("fplugin="), +joinpd1("fuse-ld="), +joinpd1("fveclib="), +jspd1("isysroot"), +joinpd1("mcmodel="), +joinpd1("mconsole"), +joinpd1("mfpmath="), +joinpd1("mhwmult="), +joinpd1("mthreads"), +joinpd1("municode"), +joinpd1("mwindows"), +jspd1("seg1addr"), +.{ + .name = "assert=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "mhwdiv=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "output=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "prefix=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "cl-ext=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("cl-std="), +joinpd1("fcheck="), +.{ + .name = "imacros", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "include", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +jspd1("iprefix"), +jspd1("isystem"), +joinpd1("mhwdiv="), +joinpd1("moslib="), +.{ + .name = "mrecip=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "stdlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "target=", + .syntax = .joined, + .zig_equivalent = .target, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("triple="), +.{ + .name = "verify=", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +joinpd1("Rpass="), +.{ + .name = "Xarch_", + .syntax = .joined_and_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "clang:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "guard:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "debug=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "param=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +.{ + .name = "warn-=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("fixit="), +joinpd1("gstabs"), +joinpd1("gxcoff"), +jspd1("iquote"), +joinpd1("march="), +joinpd1("mtune="), +.{ + .name = "rtlib=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "specs=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +joinpd1("weak-l"), +joinpd1("Ofast"), +jspd1("Tdata"), +jspd1("Ttext"), +.{ + .name = "arch:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "favor", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "imsvc", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "warn-", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = false, + .pd2 = true, + .psl = false, +}, +joinpd1("flto="), +joinpd1("gcoff"), +joinpd1("mabi="), +joinpd1("mabs="), +joinpd1("masm="), +joinpd1("mcpu="), +joinpd1("mfpu="), +joinpd1("mhvx="), +joinpd1("mmcu="), +joinpd1("mnan="), +jspd1("Tbss"), +.{ + .name = "link", + .syntax = .remaining_args_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "std:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +joinpd1("ccc-"), +joinpd1("gvms"), +joinpd1("mdll"), +joinpd1("mtp="), +.{ + .name = "std=", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = true, + .psl = false, +}, +.{ + .name = "Wa,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "Wl,", + .syntax = .comma_joined, + .zig_equivalent = .wl, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "Wp,", + .syntax = .comma_joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "RTC", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zc:", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "clr", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "doc", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +joinpd1("gz="), +joinpd1("A-"), +joinpd1("G="), +jspd1("MF"), +jspd1("MJ"), +jspd1("MQ"), +jspd1("MT"), +.{ + .name = "AI", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "EH", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FA", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FI", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FR", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "FU", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fa", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fd", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fe", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fi", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fm", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fo", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fp", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Fr", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Gs", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "MP", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Tc", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Tp", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yc", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yl", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Yu", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "ZW", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zm", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "Zp", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "d2", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "vd", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +jspd1("A"), +jspd1("B"), +jspd1("D"), +jspd1("F"), +jspd1("G"), +jspd1("I"), +jspd1("J"), +jspd1("L"), +joinpd1("O"), +joinpd1("R"), +jspd1("T"), +jspd1("U"), +jspd1("V"), +joinpd1("W"), +joinpd1("X"), +joinpd1("Z"), +.{ + .name = "D", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "F", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "I", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "O", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "U", + .syntax = .joined_or_separate, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "o", + .syntax = .joined_or_separate, + .zig_equivalent = .o, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +.{ + .name = "w", + .syntax = .joined, + .zig_equivalent = .other, + .pd1 = true, + .pd2 = false, + .psl = true, +}, +joinpd1("a"), +jspd1("b"), +joinpd1("d"), +jspd1("e"), +.{ + .name = "l", + .syntax = .joined_or_separate, + .zig_equivalent = .l, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +.{ + .name = "o", + .syntax = .joined_or_separate, + .zig_equivalent = .o, + .pd1 = true, + .pd2 = false, + .psl = false, +}, +jspd1("u"), jspd1("x"), joinpd1("y"), -sepd1("z"), };}; diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 23df042cbe..73a053b853 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -1239,6 +1239,14 @@ pub const ClangArgIterator = extern struct { other, positional, l, + ignore, + passthrough, + pic, + no_pic, + nostdlib, + shared, + rdynamic, + wl, }; fn init(argv: []const [*:0]const u8) ClangArgIterator { @@ -1282,7 +1290,8 @@ pub const ClangArgIterator = extern struct { break :find_clang_arg; }, .joined, .comma_joined => { - // Example: --target=foo + // joined example: --target=foo + // comma_joined example: -Wl,-soname,libsoundio.so.2 const prefix_len = clang_arg.matchStartsWith(arg); if (prefix_len != 0) { self.zig_equivalent = clang_arg.zig_equivalent; diff --git a/src/main.cpp b/src/main.cpp index f850b0bc47..0bb6868f1a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -430,6 +430,7 @@ static int main0(int argc, char **argv) { bool enable_dump_analysis = false; bool enable_doc_generation = false; bool emit_bin = true; + const char *emit_bin_override_path = nullptr; bool emit_asm = false; bool emit_llvm_ir = false; bool emit_h = false; @@ -451,6 +452,7 @@ static int main0(int argc, char **argv) { bool function_sections = false; const char *mcpu = nullptr; CodeModel code_model = CodeModelDefault; + const char *override_soname = nullptr; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -576,10 +578,14 @@ static int main0(int argc, char **argv) { } else if (argc >= 2 && strcmp(argv[1], "fmt") == 0) { return stage2_fmt(argc, argv); } else if (argc >= 2 && strcmp(argv[1], "cc") == 0) { - const char *o_arg = nullptr; + emit_h = false; + bool c_arg = false; Stage2ClangArgIterator it; stage2_clang_arg_iterator(&it, argc, argv); + bool nostdlib = false; + bool is_shared_lib = false; + ZigList linker_args = {}; while (it.has_next) { if ((err = stage2_clang_arg_next(&it))) { fprintf(stderr, "unable to parse command line parameters: %s\n", err_str(err)); @@ -590,7 +596,8 @@ static int main0(int argc, char **argv) { target_string = it.only_arg; break; case Stage2ClangArgO: // -o - o_arg = it.only_arg; + emit_bin_override_path = it.only_arg; + enable_cache = CacheOptOn; break; case Stage2ClangArgC: // -c c_arg = true; @@ -601,9 +608,17 @@ static int main0(int argc, char **argv) { } break; case Stage2ClangArgPositional: { - CFile *c_file = heap::c_allocator.create(); - c_file->source_path = it.only_arg; - c_source_files.append(c_file); + Buf *arg_buf = buf_create_from_str(it.only_arg); + if (buf_ends_with_str(arg_buf, ".c") || + buf_ends_with_str(arg_buf, ".cpp") || + buf_ends_with_str(arg_buf, ".s")) + { + CFile *c_file = heap::c_allocator.create(); + c_file->source_path = it.only_arg; + c_source_files.append(c_file); + } else { + objects.append(it.only_arg); + } break; } case Stage2ClangArgL: // -l @@ -611,18 +626,111 @@ static int main0(int argc, char **argv) { have_libc = true; link_libs.append(it.only_arg); break; + case Stage2ClangArgIgnore: + break; + case Stage2ClangArgPassthrough: + // Never mind what we're doing, just pass the args directly. For example --help. + return ZigClang_main(argc, argv); + case Stage2ClangArgPIC: + want_pic = WantPICEnabled; + break; + case Stage2ClangArgNoPIC: + want_pic = WantPICDisabled; + break; + case Stage2ClangArgNoStdLib: + nostdlib = true; + break; + case Stage2ClangArgShared: + is_dynamic = true; + is_shared_lib = true; + break; + case Stage2ClangArgRDynamic: + rdynamic = true; + break; + case Stage2ClangArgWL: { + const char *arg = it.only_arg; + for (;;) { + size_t pos = 0; + while (arg[pos] != ',' && arg[pos] != 0) pos += 1; + linker_args.append(buf_create_from_mem(arg, pos)); + if (arg[pos] == 0) break; + arg += pos + 1; + } + break; + } } } + // Parse linker args + for (size_t i = 0; i < linker_args.length; i += 1) { + Buf *arg = linker_args.at(i); + if (buf_eql_str(arg, "-soname")) { + i += 1; + if (i >= linker_args.length) { + fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg)); + return EXIT_FAILURE; + } + Buf *soname_buf = linker_args.at(i); + override_soname = buf_ptr(soname_buf); + // use it as --name + // example: libsoundio.so.2 + size_t prefix = 0; + if (buf_starts_with_str(soname_buf, "lib")) { + prefix = 3; + } + size_t end = buf_len(soname_buf); + if (buf_ends_with_str(soname_buf, ".so")) { + end -= 3; + } else { + bool found_digit = false; + while (end > 0 && isdigit(buf_ptr(soname_buf)[end - 1])) { + found_digit = true; + end -= 1; + } + if (found_digit && end > 0 && buf_ptr(soname_buf)[end - 1] == '.') { + end -= 1; + } else { + end = buf_len(soname_buf); + } + if (buf_ends_with_str(buf_slice(soname_buf, prefix, end), ".so")) { + end -= 3; + } + } + out_name = buf_ptr(buf_slice(soname_buf, prefix, end)); + } else if (buf_eql_str(arg, "-rpath")) { + i += 1; + if (i >= linker_args.length) { + fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg)); + return EXIT_FAILURE; + } + Buf *rpath = linker_args.at(i); + rpath_list.append(buf_ptr(rpath)); + } else { + fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg)); + } + } + + if (!nostdlib && !have_libc) { + have_libc = true; + link_libs.append("c"); + } if (!c_arg) { cmd = CmdBuild; - out_type = OutTypeExe; - if (o_arg == nullptr) { - zig_panic("TODO set out name to a.out"); + if (is_shared_lib) { + out_type = OutTypeLib; + } else { + out_type = OutTypeExe; + } + if (emit_bin_override_path == nullptr) { + emit_bin_override_path = "a.out"; } } else { cmd = CmdBuild; out_type = OutTypeObj; } + if (c_source_files.length == 0 && objects.length == 0) { + // For example `zig cc` and no args should print the "no input files" message. + return ZigClang_main(argc, argv); + } } else for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; @@ -1184,6 +1292,18 @@ static int main0(int argc, char **argv) { buf_out_name = buf_alloc(); os_path_extname(&basename, buf_out_name, nullptr); } + if (need_name && buf_out_name == nullptr && objects.length == 1) { + Buf basename = BUF_INIT; + os_path_split(buf_create_from_str(objects.at(0)), nullptr, &basename); + buf_out_name = buf_alloc(); + os_path_extname(&basename, buf_out_name, nullptr); + } + if (need_name && buf_out_name == nullptr && emit_bin_override_path != nullptr) { + Buf basename = BUF_INIT; + os_path_split(buf_create_from_str(emit_bin_override_path), nullptr, &basename); + buf_out_name = buf_alloc(); + os_path_extname(&basename, buf_out_name, nullptr); + } if (need_name && buf_out_name == nullptr) { fprintf(stderr, "--name [name] not provided and unable to infer\n\n"); @@ -1259,6 +1379,10 @@ static int main0(int argc, char **argv) { g->function_sections = function_sections; g->code_model = code_model; + if (override_soname) { + g->override_soname = buf_create_from_str(override_soname); + } + for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); } @@ -1337,7 +1461,14 @@ static int main0(int argc, char **argv) { os_spawn_process(args, &term); return term.code; } else if (cmd == CmdBuild) { - if (g->enable_cache) { + if (emit_bin_override_path != nullptr) { + Buf *dest_path = buf_create_from_str(emit_bin_override_path); + if ((err = os_update_file(&g->bin_file_output_path, dest_path))) { + fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->bin_file_output_path), + buf_ptr(dest_path), err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } + } else if (g->enable_cache) { #if defined(ZIG_OS_WINDOWS) buf_replace(&g->bin_file_output_path, '/', '\\'); buf_replace(g->output_dir, '/', '\\'); diff --git a/src/stage2.h b/src/stage2.h index 2abdc4c513..6b94f8780a 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -325,6 +325,14 @@ enum Stage2ClangArg { Stage2ClangArgOther, Stage2ClangArgPositional, Stage2ClangArgL, + Stage2ClangArgIgnore, + Stage2ClangArgPassthrough, + Stage2ClangArgPIC, + Stage2ClangArgNoPIC, + Stage2ClangArgNoStdLib, + Stage2ClangArgShared, + Stage2ClangArgRDynamic, + Stage2ClangArgWL, }; // ABI warning diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index 863c67b68d..c820ee34a3 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -38,6 +38,42 @@ const known_options = [_]KnownOpt{ .name = "l", .ident = "l", }, + .{ + .name = "pipe", + .ident = "ignore", + }, + .{ + .name = "help", + .ident = "passthrough", + }, + .{ + .name = "fPIC", + .ident = "pic", + }, + .{ + .name = "fno-PIC", + .ident = "no_pic", + }, + .{ + .name = "nostdlib", + .ident = "nostdlib", + }, + .{ + .name = "no-standard-libraries", + .ident = "nostdlib", + }, + .{ + .name = "shared", + .ident = "shared", + }, + .{ + .name = "rdynamic", + .ident = "rdynamic", + }, + .{ + .name = "Wl,", + .ident = "wl", + }, }; const blacklisted_options = [_][]const u8{}; @@ -110,7 +146,7 @@ pub fn main() anyerror!void { const tree = try parser.parse(json_text); const root_map = &tree.root.Object; - var all_names = std.ArrayList([]const u8).init(allocator); + var all_objects = std.ArrayList(*json.ObjectMap).init(allocator); { var it = root_map.iterator(); it_map: while (it.next()) |kv| { @@ -123,10 +159,12 @@ pub fn main() anyerror!void { if (std.mem.eql(u8, blacklisted_key, kv.key)) continue :it_map; } if (kv.value.Object.get("Name").?.value.String.len == 0) continue; - try all_names.append(kv.key); + try all_objects.append(&kv.value.Object); } } - std.sort.sort([]const u8, all_names.span(), nameLessThan); + // Some options have multiple matches. As an example, "-Wl,foo" matches both + // "W" and "Wl,". So we sort this list in order of descending priority. + std.sort.sort(*json.ObjectMap, all_objects.span(), objectLessThan); var stdout_bos = std.io.bufferedOutStream(std.io.getStdOut().outStream()); const stdout = stdout_bos.outStream(); @@ -138,8 +176,7 @@ pub fn main() anyerror!void { \\ ); - for (all_names.span()) |key| { - const obj = &root_map.get(key).?.value.Object; + for (all_objects.span()) |obj| { const name = obj.get("Name").?.value.String; var pd1 = false; var pd2 = false; @@ -153,61 +190,12 @@ pub fn main() anyerror!void { } else if (std.mem.eql(u8, prefix, "/")) { pslash = true; } else { - std.debug.warn("{} (key {}) has unrecognized prefix '{}'\n", .{ name, key, prefix }); + std.debug.warn("{} has unrecognized prefix '{}'\n", .{ name, prefix }); std.process.exit(1); } } - const num_args = @intCast(u8, obj.get("NumArgs").?.value.Integer); - const syntax_str: []const u8 = blk: { - for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { - const superclass = superclass_json.String; - if (std.mem.eql(u8, superclass, "Joined")) { - break :blk ".joined"; - } else if (std.mem.eql(u8, superclass, "CLJoined")) { - break :blk ".joined"; - } else if (std.mem.eql(u8, superclass, "CLIgnoredJoined")) { - break :blk ".joined"; - } else if (std.mem.eql(u8, superclass, "CLCompileJoined")) { - break :blk ".joined"; - } else if (std.mem.eql(u8, superclass, "JoinedOrSeparate")) { - break :blk ".joined_or_separate"; - } else if (std.mem.eql(u8, superclass, "CLJoinedOrSeparate")) { - break :blk ".joined_or_separate"; - } else if (std.mem.eql(u8, superclass, "CLCompileJoinedOrSeparate")) { - break :blk ".joined_or_separate"; - } else if (std.mem.eql(u8, superclass, "Flag")) { - break :blk ".flag"; - } else if (std.mem.eql(u8, superclass, "CLFlag")) { - break :blk ".flag"; - } else if (std.mem.eql(u8, superclass, "CLIgnoredFlag")) { - break :blk ".flag"; - } else if (std.mem.eql(u8, superclass, "Separate")) { - break :blk ".separate"; - } else if (std.mem.eql(u8, superclass, "JoinedAndSeparate")) { - break :blk ".joined_and_separate"; - } else if (std.mem.eql(u8, superclass, "CommaJoined")) { - break :blk ".comma_joined"; - } else if (std.mem.eql(u8, superclass, "CLRemainingArgsJoined")) { - break :blk ".remaining_args_joined"; - } else if (std.mem.eql(u8, superclass, "MultiArg")) { - break :blk try std.fmt.allocPrint(allocator, ".{{ .multi_arg = {} }}", .{num_args}); - } - } - if (std.mem.eql(u8, name, "")) { - break :blk ".flag"; - } else if (std.mem.eql(u8, name, "")) { - break :blk ".flag"; - } - const kind_def = obj.get("Kind").?.value.Object.get("def").?.value.String; - if (std.mem.eql(u8, kind_def, "KIND_FLAG")) { - break :blk ".flag"; - } - std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); - for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { - std.debug.warn(" {}\n", .{superclass_json.String}); - } - std.process.exit(1); - }; + const syntax = objSyntax(obj); + if (knownOption(name)) |ident| { try stdout.print( \\.{{ @@ -219,22 +207,14 @@ pub fn main() anyerror!void { \\ .psl = {}, \\}}, \\ - , .{ name, syntax_str, ident, pd1, pd2, pslash }); - } else if (pd1 and !pd2 and !pslash and - std.mem.eql(u8, syntax_str, ".flag")) - { + , .{ name, syntax, ident, pd1, pd2, pslash }); + } else if (pd1 and !pd2 and !pslash and syntax == .flag) { try stdout.print("flagpd1(\"{}\"),\n", .{name}); - } else if (pd1 and !pd2 and !pslash and - std.mem.eql(u8, syntax_str, ".joined")) - { + } else if (pd1 and !pd2 and !pslash and syntax == .joined) { try stdout.print("joinpd1(\"{}\"),\n", .{name}); - } else if (pd1 and !pd2 and !pslash and - std.mem.eql(u8, syntax_str, ".joined_or_separate")) - { + } else if (pd1 and !pd2 and !pslash and syntax == .joined_or_separate) { try stdout.print("jspd1(\"{}\"),\n", .{name}); - } else if (pd1 and !pd2 and !pslash and - std.mem.eql(u8, syntax_str, ".separate")) - { + } else if (pd1 and !pd2 and !pslash and syntax == .separate) { try stdout.print("sepd1(\"{}\"),\n", .{name}); } else { try stdout.print( @@ -247,7 +227,7 @@ pub fn main() anyerror!void { \\ .psl = {}, \\}}, \\ - , .{ name, syntax_str, pd1, pd2, pslash }); + , .{ name, syntax, pd1, pd2, pslash }); } } @@ -259,8 +239,142 @@ pub fn main() anyerror!void { try stdout_bos.flush(); } -fn nameLessThan(a: []const u8, b: []const u8) bool { - return std.mem.lessThan(u8, a, b); +// TODO we should be able to import clang_options.zig but currently this is problematic because it will +// import stage2.zig and that causes a bunch of stuff to get exported +const Syntax = union(enum) { + /// A flag with no values. + flag, + + /// An option which prefixes its (single) value. + joined, + + /// An option which is followed by its value. + separate, + + /// An option which is either joined to its (non-empty) value, or followed by its value. + joined_or_separate, + + /// An option which is both joined to its (first) value, and followed by its (second) value. + joined_and_separate, + + /// An option followed by its values, which are separated by commas. + comma_joined, + + /// An option which consumes an optional joined argument and any other remaining arguments. + remaining_args_joined, + + /// An option which is which takes multiple (separate) arguments. + multi_arg: u8, + + pub fn format( + self: Syntax, + comptime fmt: []const u8, + options: std.fmt.FormatOptions, + out_stream: var, + ) !void { + switch (self) { + .multi_arg => |n| return out_stream.print(".{{.{}={}}}", .{ @tagName(self), n }), + else => return out_stream.print(".{}", .{@tagName(self)}), + } + } +}; + +fn objSyntax(obj: *json.ObjectMap) Syntax { + const num_args = @intCast(u8, obj.get("NumArgs").?.value.Integer); + for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { + const superclass = superclass_json.String; + if (std.mem.eql(u8, superclass, "Joined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "CLJoined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "CLIgnoredJoined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "CLCompileJoined")) { + return .joined; + } else if (std.mem.eql(u8, superclass, "JoinedOrSeparate")) { + return .joined_or_separate; + } else if (std.mem.eql(u8, superclass, "CLJoinedOrSeparate")) { + return .joined_or_separate; + } else if (std.mem.eql(u8, superclass, "CLCompileJoinedOrSeparate")) { + return .joined_or_separate; + } else if (std.mem.eql(u8, superclass, "Flag")) { + return .flag; + } else if (std.mem.eql(u8, superclass, "CLFlag")) { + return .flag; + } else if (std.mem.eql(u8, superclass, "CLIgnoredFlag")) { + return .flag; + } else if (std.mem.eql(u8, superclass, "Separate")) { + return .separate; + } else if (std.mem.eql(u8, superclass, "JoinedAndSeparate")) { + return .joined_and_separate; + } else if (std.mem.eql(u8, superclass, "CommaJoined")) { + return .comma_joined; + } else if (std.mem.eql(u8, superclass, "CLRemainingArgsJoined")) { + return .remaining_args_joined; + } else if (std.mem.eql(u8, superclass, "MultiArg")) { + return .{ .multi_arg = num_args }; + } + } + const name = obj.get("Name").?.value.String; + if (std.mem.eql(u8, name, "")) { + return .flag; + } else if (std.mem.eql(u8, name, "")) { + return .flag; + } + const kind_def = obj.get("Kind").?.value.Object.get("def").?.value.String; + if (std.mem.eql(u8, kind_def, "KIND_FLAG")) { + return .flag; + } + const key = obj.get("!name").?.value.String; + std.debug.warn("{} (key {}) has unrecognized superclasses:\n", .{ name, key }); + for (obj.get("!superclasses").?.value.Array.span()) |superclass_json| { + std.debug.warn(" {}\n", .{superclass_json.String}); + } + std.process.exit(1); +} + +fn syntaxMatchesWithEql(syntax: Syntax) bool { + return switch (syntax) { + .flag, + .separate, + .multi_arg, + => true, + + .joined, + .joined_or_separate, + .joined_and_separate, + .comma_joined, + .remaining_args_joined, + => false, + }; +} + +fn objectLessThan(a: *json.ObjectMap, b: *json.ObjectMap) bool { + // Priority is determined by exact matches first, followed by prefix matches in descending + // length, with key as a final tiebreaker. + const a_syntax = objSyntax(a); + const b_syntax = objSyntax(b); + + const a_match_with_eql = syntaxMatchesWithEql(a_syntax); + const b_match_with_eql = syntaxMatchesWithEql(b_syntax); + + if (a_match_with_eql and !b_match_with_eql) { + return true; + } else if (!a_match_with_eql and b_match_with_eql) { + return false; + } + + if (!a_match_with_eql and !b_match_with_eql) { + const a_name = a.get("Name").?.value.String; + const b_name = b.get("Name").?.value.String; + if (a_name.len != b_name.len) { + return a_name.len > b_name.len; + } + } + + const a_key = a.get("!name").?.value.String; + const b_key = b.get("!name").?.value.String; + return std.mem.lessThan(u8, a_key, b_key); } fn usageAndExit(file: fs.File, arg0: []const u8, code: u8) noreturn { From 4d9b458f8f722603dd0c303bddeca553948025fb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 21 Mar 2020 16:51:43 -0400 Subject: [PATCH 65/79] zig cc: support .cc and .cxx extensions --- src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 0bb6868f1a..fc73cb78d6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -610,7 +610,9 @@ static int main0(int argc, char **argv) { case Stage2ClangArgPositional: { Buf *arg_buf = buf_create_from_str(it.only_arg); if (buf_ends_with_str(arg_buf, ".c") || + buf_ends_with_str(arg_buf, ".cc") || buf_ends_with_str(arg_buf, ".cpp") || + buf_ends_with_str(arg_buf, ".cxx") || buf_ends_with_str(arg_buf, ".s")) { CFile *c_file = heap::c_allocator.create(); From 28ad78cb7f4a567ce6a595b8ff466e90b311f3e4 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Sat, 21 Mar 2020 16:38:58 -0400 Subject: [PATCH 66/79] =?UTF-8?q?rename=20"passthrough"=20=E2=86=92=20"dri?= =?UTF-8?q?ver=5Fpunt"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - punt when `-E` is supplied - punt when `-S` is supplied --- src-self-hosted/clang_options_data.zig | 24 +++++++++++++++++++----- src-self-hosted/stage2.zig | 2 +- src/main.cpp | 2 +- src/stage2.h | 2 +- tools/update_clang_options.zig | 10 +++++++++- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig index a21069f93c..bfd26c6de2 100644 --- a/src-self-hosted/clang_options_data.zig +++ b/src-self-hosted/clang_options_data.zig @@ -4,7 +4,14 @@ usingnamespace @import("clang_options.zig"); pub const data = blk: { @setEvalBranchQuota(6000); break :blk &[_]CliArg{ flagpd1("C"), flagpd1("CC"), -flagpd1("E"), +.{ + .name = "E", + .syntax = .flag, + .zig_equivalent = .driver_punt, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("EB"), flagpd1("EL"), flagpd1("Eonly"), @@ -36,7 +43,14 @@ flagpd1("Q"), flagpd1("Qn"), flagpd1("Qunused-arguments"), flagpd1("Qy"), -flagpd1("S"), +.{ + .name = "S", + .syntax = .flag, + .zig_equivalent = .driver_punt, + .pd1 = true, + .pd2 = false, + .psl = false, +}, .{ .name = "", .syntax = .flag, @@ -119,7 +133,7 @@ flagpd1("###"), .{ .name = "E", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .driver_punt, .pd1 = true, .pd2 = false, .psl = true, @@ -1127,7 +1141,7 @@ flagpd1("###"), .{ .name = "help", .syntax = .flag, - .zig_equivalent = .passthrough, + .zig_equivalent = .driver_punt, .pd1 = true, .pd2 = false, .psl = true, @@ -3131,7 +3145,7 @@ sepd1("header-include-file"), .{ .name = "help", .syntax = .flag, - .zig_equivalent = .passthrough, + .zig_equivalent = .driver_punt, .pd1 = true, .pd2 = true, .psl = false, diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 73a053b853..45fa2ec3e1 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -1240,7 +1240,7 @@ pub const ClangArgIterator = extern struct { positional, l, ignore, - passthrough, + driver_punt, pic, no_pic, nostdlib, diff --git a/src/main.cpp b/src/main.cpp index fc73cb78d6..d64b8dcdbe 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -630,7 +630,7 @@ static int main0(int argc, char **argv) { break; case Stage2ClangArgIgnore: break; - case Stage2ClangArgPassthrough: + case Stage2ClangArgDriverPunt: // Never mind what we're doing, just pass the args directly. For example --help. return ZigClang_main(argc, argv); case Stage2ClangArgPIC: diff --git a/src/stage2.h b/src/stage2.h index 6b94f8780a..5f233f9fc3 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -326,7 +326,7 @@ enum Stage2ClangArg { Stage2ClangArgPositional, Stage2ClangArgL, Stage2ClangArgIgnore, - Stage2ClangArgPassthrough, + Stage2ClangArgDriverPunt, Stage2ClangArgPIC, Stage2ClangArgNoPIC, Stage2ClangArgNoStdLib, diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index c820ee34a3..b4cec5afd9 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -44,7 +44,7 @@ const known_options = [_]KnownOpt{ }, .{ .name = "help", - .ident = "passthrough", + .ident = "driver_punt", }, .{ .name = "fPIC", @@ -74,6 +74,14 @@ const known_options = [_]KnownOpt{ .name = "Wl,", .ident = "wl", }, + .{ + .name = "E", + .ident = "driver_punt", + }, + .{ + .name = "S", + .ident = "driver_punt", + }, }; const blacklisted_options = [_][]const u8{}; From 4b0ddb817bb5d4effd8cd2dd0844ac278e35e1d5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 21 Mar 2020 20:32:48 -0400 Subject: [PATCH 67/79] zig cc: better support for the preprocessor option (-E) --- src-self-hosted/clang_options_data.zig | 8 ++-- src-self-hosted/stage2.zig | 1 + src/all_types.hpp | 2 + src/codegen.cpp | 22 +++++++--- src/main.cpp | 60 ++++++++++++++++++++++++-- src/os.cpp | 24 +++++++++++ src/os.hpp | 1 + src/stage2.h | 1 + tools/update_clang_options.zig | 10 ++++- 9 files changed, 115 insertions(+), 14 deletions(-) diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig index bfd26c6de2..b1796dce75 100644 --- a/src-self-hosted/clang_options_data.zig +++ b/src-self-hosted/clang_options_data.zig @@ -7,7 +7,7 @@ flagpd1("CC"), .{ .name = "E", .syntax = .flag, - .zig_equivalent = .driver_punt, + .zig_equivalent = .preprocess, .pd1 = true, .pd2 = false, .psl = false, @@ -133,7 +133,7 @@ flagpd1("###"), .{ .name = "E", .syntax = .flag, - .zig_equivalent = .driver_punt, + .zig_equivalent = .preprocess, .pd1 = true, .pd2 = false, .psl = true, @@ -1421,7 +1421,7 @@ flagpd1("###"), .{ .name = "assemble", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .driver_punt, .pd1 = false, .pd2 = true, .psl = false, @@ -1749,7 +1749,7 @@ flagpd1("###"), .{ .name = "preprocess", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .preprocess, .pd1 = false, .pd2 = true, .psl = false, diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 45fa2ec3e1..030e9694e8 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -1247,6 +1247,7 @@ pub const ClangArgIterator = extern struct { shared, rdynamic, wl, + preprocess, }; fn init(argv: []const [*:0]const u8) ClangArgIterator { diff --git a/src/all_types.hpp b/src/all_types.hpp index b1450f08da..aed03d4781 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2003,6 +2003,7 @@ enum WantCSanitize { struct CFile { ZigList args; const char *source_path; + const char *preprocessor_only_basename; }; // When adding fields, check if they should be added to the hash computation in build_with_cache @@ -2147,6 +2148,7 @@ struct CodeGen { // As an input parameter, mutually exclusive with enable_cache. But it gets // populated in codegen_build_and_link. Buf *output_dir; + Buf *c_artifact_dir; const char **libc_include_dir_list; size_t libc_include_dir_len; diff --git a/src/codegen.cpp b/src/codegen.cpp index 7729172c2f..7b481f7c21 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9723,13 +9723,17 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { buf_len(c_source_basename), 0); Buf *final_o_basename = buf_alloc(); - // We special case when doing build-obj for just one C file - if (main_output_dir_is_just_one_c_object_pre(g)) { - buf_init_from_buf(final_o_basename, g->root_out_name); + if (c_file->preprocessor_only_basename == nullptr) { + // We special case when doing build-obj for just one C file + if (main_output_dir_is_just_one_c_object_pre(g)) { + buf_init_from_buf(final_o_basename, g->root_out_name); + } else { + os_path_extname(c_source_basename, final_o_basename, nullptr); + } + buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); } else { - os_path_extname(c_source_basename, final_o_basename, nullptr); + buf_init_from_str(final_o_basename, c_file->preprocessor_only_basename); } - buf_append_str(final_o_basename, target_o_file_ext(g->zig_target)); CacheHash *cache_hash; if ((err = create_c_object_cache(g, &cache_hash, true))) { @@ -9780,13 +9784,18 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { args.append(buf_ptr(self_exe_path)); args.append("clang"); + if (c_file->preprocessor_only_basename != nullptr) { + args.append("-E"); + } else { + args.append("-c"); + } + Buf *out_dep_path = buf_sprintf("%s.d", buf_ptr(out_obj_path)); add_cc_args(g, args, buf_ptr(out_dep_path), false); args.append("-o"); args.append(buf_ptr(out_obj_path)); - args.append("-c"); args.append(buf_ptr(c_source_file)); for (size_t arg_i = 0; arg_i < c_file->args.length; arg_i += 1) { @@ -9841,6 +9850,7 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { os_path_join(artifact_dir, final_o_basename, o_final_path); } + g->c_artifact_dir = artifact_dir; g->link_objects.append(o_final_path); g->caches_to_release.append(cache_hash); diff --git a/src/main.cpp b/src/main.cpp index d64b8dcdbe..071b365d2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -453,6 +453,7 @@ static int main0(int argc, char **argv) { const char *mcpu = nullptr; CodeModel code_model = CodeModelDefault; const char *override_soname = nullptr; + bool only_preprocess = false; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -660,6 +661,9 @@ static int main0(int argc, char **argv) { } break; } + case Stage2ClangArgPreprocess: + only_preprocess = true; + break; } } // Parse linker args @@ -715,7 +719,28 @@ static int main0(int argc, char **argv) { have_libc = true; link_libs.append("c"); } - if (!c_arg) { + if (only_preprocess) { + cmd = CmdBuild; + out_type = OutTypeObj; + emit_bin = false; + // Transfer "objects" into c_source_files + for (size_t i = 0; i < objects.length; i += 1) { + CFile *c_file = heap::c_allocator.create(); + c_file->source_path = objects.at(i); + c_source_files.append(c_file); + } + for (size_t i = 0; i < c_source_files.length; i += 1) { + Buf *src_path; + if (emit_bin_override_path != nullptr) { + src_path = buf_create_from_str(emit_bin_override_path); + } else { + src_path = buf_create_from_str(c_source_files.at(i)->source_path); + } + Buf basename = BUF_INIT; + os_path_split(src_path, nullptr, &basename); + c_source_files.at(i)->preprocessor_only_basename = buf_ptr(&basename); + } + } else if (!c_arg) { cmd = CmdBuild; if (is_shared_lib) { out_type = OutTypeLib; @@ -1464,12 +1489,41 @@ static int main0(int argc, char **argv) { return term.code; } else if (cmd == CmdBuild) { if (emit_bin_override_path != nullptr) { +#if defined(ZIG_OS_WINDOWS) + buf_replace(g->output_dir, '/', '\\'); +#endif Buf *dest_path = buf_create_from_str(emit_bin_override_path); - if ((err = os_update_file(&g->bin_file_output_path, dest_path))) { - fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(&g->bin_file_output_path), + Buf *source_path; + if (only_preprocess) { + source_path = buf_alloc(); + Buf *pp_only_basename = buf_create_from_str( + c_source_files.at(0)->preprocessor_only_basename); + os_path_join(g->output_dir, pp_only_basename, source_path); + + } else { + source_path = &g->bin_file_output_path; + } + if ((err = os_update_file(source_path, dest_path))) { + fprintf(stderr, "unable to copy %s to %s: %s\n", buf_ptr(source_path), buf_ptr(dest_path), err_str(err)); return main_exit(root_progress_node, EXIT_FAILURE); } + } else if (only_preprocess) { +#if defined(ZIG_OS_WINDOWS) + buf_replace(g->c_artifact_dir, '/', '\\'); +#endif + // dump the preprocessed output to stdout + for (size_t i = 0; i < c_source_files.length; i += 1) { + Buf *source_path = buf_alloc(); + Buf *pp_only_basename = buf_create_from_str( + c_source_files.at(i)->preprocessor_only_basename); + os_path_join(g->c_artifact_dir, pp_only_basename, source_path); + if ((err = os_dump_file(source_path, stdout))) { + fprintf(stderr, "unable to read %s: %s\n", buf_ptr(source_path), + err_str(err)); + return main_exit(root_progress_node, EXIT_FAILURE); + } + } } else if (g->enable_cache) { #if defined(ZIG_OS_WINDOWS) buf_replace(&g->bin_file_output_path, '/', '\\'); diff --git a/src/os.cpp b/src/os.cpp index f65a578e17..351b61cd66 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1051,6 +1051,30 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) { } } +Error os_dump_file(Buf *src_path, FILE *dest_file) { + Error err; + + FILE *src_f = fopen(buf_ptr(src_path), "rb"); + if (!src_f) { + int err = errno; + if (err == ENOENT) { + return ErrorFileNotFound; + } else if (err == EACCES || err == EPERM) { + return ErrorAccess; + } else { + return ErrorFileSystem; + } + } + copy_open_files(src_f, dest_file); + if ((err = copy_open_files(src_f, dest_file))) { + fclose(src_f); + return err; + } + + fclose(src_f); + return ErrorNone; +} + #if defined(ZIG_OS_WINDOWS) static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; diff --git a/src/os.hpp b/src/os.hpp index 116861e8b5..e73e5e3aaa 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -129,6 +129,7 @@ void os_file_close(OsFile *file); Error ATTRIBUTE_MUST_USE os_write_file(Buf *full_path, Buf *contents); Error ATTRIBUTE_MUST_USE os_copy_file(Buf *src_path, Buf *dest_path); Error ATTRIBUTE_MUST_USE os_update_file(Buf *src_path, Buf *dest_path); +Error ATTRIBUTE_MUST_USE os_dump_file(Buf *src_path, FILE *dest_file); Error ATTRIBUTE_MUST_USE os_fetch_file(FILE *file, Buf *out_contents); Error ATTRIBUTE_MUST_USE os_fetch_file_path(Buf *full_path, Buf *out_contents); diff --git a/src/stage2.h b/src/stage2.h index 5f233f9fc3..15c4c604cd 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -333,6 +333,7 @@ enum Stage2ClangArg { Stage2ClangArgShared, Stage2ClangArgRDynamic, Stage2ClangArgWL, + Stage2ClangArgPreprocess, }; // ABI warning diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index b4cec5afd9..ccd4443130 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -76,12 +76,20 @@ const known_options = [_]KnownOpt{ }, .{ .name = "E", - .ident = "driver_punt", + .ident = "preprocess", + }, + .{ + .name = "preprocess", + .ident = "preprocess", }, .{ .name = "S", .ident = "driver_punt", }, + .{ + .name = "assemble", + .ident = "driver_punt", + }, }; const blacklisted_options = [_][]const u8{}; From 138dab45248c718b8d38fa0a8eefe56f40fe617c Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 22 Mar 2020 10:35:19 +1000 Subject: [PATCH 68/79] add number `_` separators for stage 2 tokenizer --- lib/std/zig/tokenizer.zig | 419 +++++++++++++++++++++++++++++++++----- 1 file changed, 370 insertions(+), 49 deletions(-) diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index f6c71479e7..8c9b39d34f 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -387,17 +387,23 @@ pub const Tokenizer = struct { DocComment, ContainerDocComment, Zero, - IntegerLiteral, - IntegerLiteralWithRadix, - IntegerLiteralWithRadixHex, - NumberDot, + IntegerLiteralDec, + IntegerLiteralDecNoUnderscore, + IntegerLiteralBin, + IntegerLiteralBinNoUnderscore, + IntegerLiteralOct, + IntegerLiteralOctNoUnderscore, + IntegerLiteralHex, + IntegerLiteralHexNoUnderscore, + NumberDotDec, NumberDotHex, - FloatFraction, + FloatFractionDec, + FloatFractionDecNoUnderscore, FloatFractionHex, + FloatFractionHexNoUnderscore, FloatExponentUnsigned, - FloatExponentUnsignedHex, FloatExponentNumber, - FloatExponentNumberHex, + FloatExponentNumberNoUnderscore, Ampersand, Caret, Percent, @@ -550,7 +556,7 @@ pub const Tokenizer = struct { result.id = Token.Id.IntegerLiteral; }, '1'...'9' => { - state = State.IntegerLiteral; + state = State.IntegerLiteralDec; result.id = Token.Id.IntegerLiteral; }, else => { @@ -1048,55 +1054,122 @@ pub const Tokenizer = struct { else => self.checkLiteralCharacter(), }, State.Zero => switch (c) { - 'b', 'o' => { - state = State.IntegerLiteralWithRadix; + 'b' => { + state = State.IntegerLiteralBinNoUnderscore; + }, + 'o' => { + state = State.IntegerLiteralOctNoUnderscore; }, 'x' => { - state = State.IntegerLiteralWithRadixHex; + state = State.IntegerLiteralHexNoUnderscore; }, else => { // reinterpret as a normal number self.index -= 1; - state = State.IntegerLiteral; + state = State.IntegerLiteralDec; }, }, - State.IntegerLiteral => switch (c) { - '.' => { - state = State.NumberDot; + State.IntegerLiteralBinNoUnderscore => switch (c) { + '0'...'1' => { + state = State.IntegerLiteralBin; }, - 'p', 'P', 'e', 'E' => { + else => { + result.id = Token.Id.Invalid; + }, + }, + State.IntegerLiteralBin => switch (c) { + '_' => { + state = State.IntegerLiteralBinNoUnderscore; + }, + '0'...'1' => {}, + '2'...'9', 'a'...'z', 'A'...'Z' => { + result.id = Token.Id.Invalid; + }, + else => break, + }, + State.IntegerLiteralOctNoUnderscore => switch (c) { + '0'...'7' => { + state = State.IntegerLiteralOct; + }, + else => { + result.id = Token.Id.Invalid; + }, + }, + State.IntegerLiteralOct => switch (c) { + '_' => { + state = State.IntegerLiteralOctNoUnderscore; + }, + '0'...'7' => {}, + '8'...'9', 'a'...'z', 'A'...'Z' => { + result.id = Token.Id.Invalid; + }, + else => break, + }, + State.IntegerLiteralDecNoUnderscore => switch (c) { + '0'...'9' => { + state = State.IntegerLiteralDec; + }, + else => { + result.id = Token.Id.Invalid; + }, + }, + State.IntegerLiteralDec => switch (c) { + '_' => { + state = State.IntegerLiteralDecNoUnderscore; + }, + '.' => { + state = State.NumberDotDec; + result.id = Token.Id.FloatLiteral; + }, + 'e', 'E' => { state = State.FloatExponentUnsigned; + result.id = Token.Id.FloatLiteral; }, '0'...'9' => {}, - else => break, - }, - State.IntegerLiteralWithRadix => switch (c) { - '.' => { - state = State.NumberDot; + 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => { + result.id = Token.Id.Invalid; }, - '0'...'9' => {}, else => break, }, - State.IntegerLiteralWithRadixHex => switch (c) { + State.IntegerLiteralHexNoUnderscore => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => { + state = State.IntegerLiteralHex; + }, + else => { + result.id = Token.Id.Invalid; + }, + }, + State.IntegerLiteralHex => switch (c) { + '_' => { + state = State.IntegerLiteralHexNoUnderscore; + }, '.' => { state = State.NumberDotHex; + result.id = Token.Id.FloatLiteral; }, 'p', 'P' => { - state = State.FloatExponentUnsignedHex; + state = State.FloatExponentUnsigned; + result.id = Token.Id.FloatLiteral; }, '0'...'9', 'a'...'f', 'A'...'F' => {}, + 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => { + result.id = Token.Id.Invalid; + }, else => break, }, - State.NumberDot => switch (c) { + State.NumberDotDec => switch (c) { '.' => { self.index -= 1; state = State.Start; break; }, + 'e', 'E' => { + state = State.FloatExponentUnsigned; + }, else => { self.index -= 1; result.id = Token.Id.FloatLiteral; - state = State.FloatFraction; + state = State.FloatFractionDecNoUnderscore; }, }, State.NumberDotHex => switch (c) { @@ -1105,65 +1178,98 @@ pub const Tokenizer = struct { state = State.Start; break; }, + 'p', 'P' => { + state = State.FloatExponentUnsigned; + }, else => { self.index -= 1; result.id = Token.Id.FloatLiteral; - state = State.FloatFractionHex; + state = State.FloatFractionHexNoUnderscore; }, }, - State.FloatFraction => switch (c) { + State.FloatFractionDecNoUnderscore => switch (c) { + '0'...'9' => { + state = State.FloatFractionDec; + }, + else => { + result.id = Token.Id.Invalid; + }, + }, + State.FloatFractionDec => switch (c) { + '_' => { + state = State.FloatFractionDecNoUnderscore; + }, 'e', 'E' => { state = State.FloatExponentUnsigned; }, '0'...'9' => {}, + 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => { + result.id = Token.Id.Invalid; + }, else => break, }, + State.FloatFractionHexNoUnderscore => switch (c) { + '0'...'9', 'a'...'f', 'A'...'F' => { + state = State.FloatFractionHex; + }, + else => { + result.id = Token.Id.Invalid; + }, + }, State.FloatFractionHex => switch (c) { + '_' => { + state = State.FloatFractionHexNoUnderscore; + }, 'p', 'P' => { - state = State.FloatExponentUnsignedHex; + state = State.FloatExponentUnsigned; }, '0'...'9', 'a'...'f', 'A'...'F' => {}, + 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => { + result.id = Token.Id.Invalid; + }, else => break, }, State.FloatExponentUnsigned => switch (c) { '+', '-' => { - state = State.FloatExponentNumber; + state = State.FloatExponentNumberNoUnderscore; }, else => { // reinterpret as a normal exponent number self.index -= 1; - state = State.FloatExponentNumber; + state = State.FloatExponentNumberNoUnderscore; }, }, - State.FloatExponentUnsignedHex => switch (c) { - '+', '-' => { - state = State.FloatExponentNumberHex; + State.FloatExponentNumberNoUnderscore => switch (c) { + '0'...'9' => { + state = State.FloatExponentNumber; }, else => { - // reinterpret as a normal exponent number - self.index -= 1; - state = State.FloatExponentNumberHex; + result.id = Token.Id.Invalid; }, }, State.FloatExponentNumber => switch (c) { + '_' => { + state = State.FloatExponentNumberNoUnderscore; + }, '0'...'9' => {}, - else => break, - }, - State.FloatExponentNumberHex => switch (c) { - '0'...'9', 'a'...'f', 'A'...'F' => {}, + 'a'...'z', 'A'...'Z' => { + result.id = Token.Id.Invalid; + }, else => break, }, } } else if (self.index == self.buffer.len) { switch (state) { State.Start, - State.IntegerLiteral, - State.IntegerLiteralWithRadix, - State.IntegerLiteralWithRadixHex, - State.FloatFraction, + State.IntegerLiteralDec, + State.IntegerLiteralBin, + State.IntegerLiteralOct, + State.IntegerLiteralHex, + State.NumberDotDec, + State.NumberDotHex, + State.FloatFractionDec, State.FloatFractionHex, State.FloatExponentNumber, - State.FloatExponentNumberHex, State.StringLiteral, // find this error later State.MultilineStringLiteralLine, State.Builtin, @@ -1184,10 +1290,14 @@ pub const Tokenizer = struct { result.id = Token.Id.ContainerDocComment; }, - State.NumberDot, - State.NumberDotHex, + State.IntegerLiteralDecNoUnderscore, + State.IntegerLiteralBinNoUnderscore, + State.IntegerLiteralOctNoUnderscore, + State.IntegerLiteralHexNoUnderscore, + State.FloatFractionDecNoUnderscore, + State.FloatFractionHexNoUnderscore, + State.FloatExponentNumberNoUnderscore, State.FloatExponentUnsigned, - State.FloatExponentUnsignedHex, State.SawAtSign, State.Backslash, State.CharLiteral, @@ -1585,6 +1695,217 @@ test "correctly parse pointer assignment" { }); } +test "tokenizer - number literals decimal" { + testTokenize("1", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("2", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("3", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("4", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("5", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("6", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("7", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("8", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("9", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0a", &[_]Token.Id{ .Invalid }); + testTokenize("9b", &[_]Token.Id{ .Invalid }); + testTokenize("1z", &[_]Token.Id{ .Invalid }); + testTokenize("1z_1", &[_]Token.Id{ .Invalid }); + testTokenize("9z3", &[_]Token.Id{ .Invalid }); + + testTokenize("0_0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0001", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("01234567890", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("012_345_6789_0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0_1_2_3_4_5_6_7_8_9_0", &[_]Token.Id{ .IntegerLiteral }); + + testTokenize("00_", &[_]Token.Id{ .Invalid }); + testTokenize("0_0_", &[_]Token.Id{ .Invalid }); + testTokenize("0__0", &[_]Token.Id{ .Invalid }); + testTokenize("0_0f", &[_]Token.Id{ .Invalid }); + testTokenize("0_0_f", &[_]Token.Id{ .Invalid }); + testTokenize("1_,", &[_]Token.Id{ .Invalid }); + + testTokenize("1.", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0.0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1.0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("10.0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1e0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1e100", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1.e100", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1.0e100", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1.0e+100", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1.0e-100", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &[_]Token.Id{ .FloatLiteral }); + + testTokenize("1e", &[_]Token.Id{ .Invalid }); + testTokenize("1.0e1f0", &[_]Token.Id{ .Invalid }); + testTokenize("1.0p100", &[_]Token.Id{ .Invalid }); + testTokenize("1.0p-100", &[_]Token.Id{ .Invalid, .Minus, .IntegerLiteral }); + testTokenize("1.0p1f0", &[_]Token.Id{ .Invalid }); + testTokenize("1.0_,", &[_]Token.Id{ .Invalid }); + testTokenize("1.0e,", &[_]Token.Id{ .Invalid }); +} + + +test "tokenizer - number literals binary" { + testTokenize("0b0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b1", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b2", &[_]Token.Id{ .Invalid }); + testTokenize("0b3", &[_]Token.Id{ .Invalid }); + testTokenize("0b4", &[_]Token.Id{ .Invalid }); + testTokenize("0b5", &[_]Token.Id{ .Invalid }); + testTokenize("0b6", &[_]Token.Id{ .Invalid }); + testTokenize("0b7", &[_]Token.Id{ .Invalid }); + testTokenize("0b8", &[_]Token.Id{ .Invalid }); + testTokenize("0b9", &[_]Token.Id{ .Invalid }); + testTokenize("0ba", &[_]Token.Id{ .Invalid }); + testTokenize("0bb", &[_]Token.Id{ .Invalid }); + testTokenize("0bc", &[_]Token.Id{ .Invalid }); + testTokenize("0bd", &[_]Token.Id{ .Invalid }); + testTokenize("0be", &[_]Token.Id{ .Invalid }); + testTokenize("0bf", &[_]Token.Id{ .Invalid }); + testTokenize("0bz", &[_]Token.Id{ .Invalid }); + + testTokenize("0b0000_0000", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b1111_1111", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b10_10_10_10", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b0_1_0_1_0_1_0_1", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b1.", &[_]Token.Id{ .IntegerLiteral, .Period }); + testTokenize("0b1.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); + + testTokenize("0B0", &[_]Token.Id{ .Invalid }); + testTokenize("0b_", &[_]Token.Id{ .Invalid }); + testTokenize("0b_0", &[_]Token.Id{ .Invalid }); + testTokenize("0b1_", &[_]Token.Id{ .Invalid }); + testTokenize("0b0__1", &[_]Token.Id{ .Invalid }); + testTokenize("0b0_1_", &[_]Token.Id{ .Invalid }); + testTokenize("0b1e", &[_]Token.Id{ .Invalid }); + testTokenize("0b1p", &[_]Token.Id{ .Invalid }); + testTokenize("0b1e0", &[_]Token.Id{ .Invalid }); + testTokenize("0b1p0", &[_]Token.Id{ .Invalid }); + testTokenize("0b1_,", &[_]Token.Id{ .Invalid }); +} + +test "tokenizer - number literals octal" { + testTokenize("0o0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o1", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o2", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o3", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o4", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o5", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o6", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o7", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o8", &[_]Token.Id{ .Invalid }); + testTokenize("0o9", &[_]Token.Id{ .Invalid }); + testTokenize("0oa", &[_]Token.Id{ .Invalid }); + testTokenize("0ob", &[_]Token.Id{ .Invalid }); + testTokenize("0oc", &[_]Token.Id{ .Invalid }); + testTokenize("0od", &[_]Token.Id{ .Invalid }); + testTokenize("0oe", &[_]Token.Id{ .Invalid }); + testTokenize("0of", &[_]Token.Id{ .Invalid }); + testTokenize("0oz", &[_]Token.Id{ .Invalid }); + + testTokenize("0o01234567", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o0123_4567", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o01_23_45_67", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o0_1_2_3_4_5_6_7", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o7.", &[_]Token.Id{ .IntegerLiteral, .Period }); + testTokenize("0o7.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); + + testTokenize("0O0", &[_]Token.Id{ .Invalid }); + testTokenize("0o_", &[_]Token.Id{ .Invalid }); + testTokenize("0o_0", &[_]Token.Id{ .Invalid }); + testTokenize("0o1_", &[_]Token.Id{ .Invalid }); + testTokenize("0o0__1", &[_]Token.Id{ .Invalid }); + testTokenize("0o0_1_", &[_]Token.Id{ .Invalid }); + testTokenize("0o1e", &[_]Token.Id{ .Invalid }); + testTokenize("0o1p", &[_]Token.Id{ .Invalid }); + testTokenize("0o1e0", &[_]Token.Id{ .Invalid }); + testTokenize("0o1p0", &[_]Token.Id{ .Invalid }); + testTokenize("0o_,", &[_]Token.Id{ .Invalid }); +} + +test "tokenizer - number literals hexadeciaml" { + testTokenize("0x0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x1", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x2", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x3", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x4", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x5", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x6", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x7", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x8", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x9", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xa", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xb", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xc", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xd", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xe", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xf", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xA", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xB", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xC", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xD", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xE", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0xF", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x0z", &[_]Token.Id{ .Invalid }); + testTokenize("0xz", &[_]Token.Id{ .Invalid }); + + testTokenize("0x0123456789ABCDEF", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x0123_4567_89AB_CDEF", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x01_23_45_67_89AB_CDE_F", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &[_]Token.Id{ .IntegerLiteral }); + + testTokenize("0X0", &[_]Token.Id{ .Invalid }); + testTokenize("0x_", &[_]Token.Id{ .Invalid }); + testTokenize("0x_1", &[_]Token.Id{ .Invalid }); + testTokenize("0x1_", &[_]Token.Id{ .Invalid }); + testTokenize("0x0__1", &[_]Token.Id{ .Invalid }); + testTokenize("0x0_1_", &[_]Token.Id{ .Invalid }); + testTokenize("0x_,", &[_]Token.Id{ .Invalid }); + + testTokenize("0x1.", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x1.0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xF.", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xF.0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xF.F", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xF.Fp0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xF.FP0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x1p0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xfp0", &[_]Token.Id{ .FloatLiteral }); + + testTokenize("0x0123456.789ABCDEF", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x0_123_456.789_ABC_DEF", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x0.0p0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xff.ffp10", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xff.ffP10", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xff.p10", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xffp10", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xff_ff.ff_ffp1_0_0_0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xf_f_f_f.f_f_f_fp+1_000", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0xf_f_f_f.f_f_f_fp-1_00_0", &[_]Token.Id{ .FloatLiteral }); + + testTokenize("0x1e", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x1e0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x1p", &[_]Token.Id{ .Invalid }); + testTokenize("0xfp0z1", &[_]Token.Id{ .Invalid }); + testTokenize("0xff.ffpff", &[_]Token.Id{ .Invalid }); + testTokenize("0x0_.0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0._0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0_", &[_]Token.Id{ .Invalid }); + testTokenize("0x0_p0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0_.p0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0._p0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0_p0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0._0p0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0_p0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0p_0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0p+_0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0p-_0", &[_]Token.Id{ .Invalid }); + testTokenize("0x0.0p0_", &[_]Token.Id{ .Invalid }); +} + + fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { var tokenizer = Tokenizer.init(source); for (expected_tokens) |expected_token_id| { From dc79f181a56cad17f429bbb7fd176e49bf3d66da Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 21 Mar 2020 18:33:54 +0100 Subject: [PATCH 69/79] ir: Disallow comparison between enum literal and untagged enum Closes #4770 --- src/ir.cpp | 9 +++++++++ test/compile_errors.zig | 11 +++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/ir.cpp b/src/ir.cpp index 531c1b2432..590b81d3be 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -16286,6 +16286,15 @@ static IrInstGen *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstSrcBinOp *bin_op_i IrInstGen *union_val = op1->value->type->id == ZigTypeIdUnion ? op1 : op2; IrInstGen *enum_val = op1->value->type->id == ZigTypeIdUnion ? op2 : op1; + if (!is_tagged_union(union_val->value->type)) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("comparison of union and enum literal is only valid for tagged union types")); + add_error_note(ira->codegen, msg, union_val->value->type->data.unionation.decl_node, + buf_sprintf("type %s is not a tagged union", + buf_ptr(&union_val->value->type->name))); + return ira->codegen->invalid_inst_gen; + } + ZigType *tag_type = union_val->value->type->data.unionation.tag_type; assert(tag_type != nullptr); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d2e298032f..f19ff11471 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -14,6 +14,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:15: error: unused variable: 'a'", }); + cases.addTest("comparison of non-tagged union and enum literal", + \\export fn entry() void { + \\ const U = union { A: u32, B: u64 }; + \\ var u = U{ .A = 42 }; + \\ var ok = u == .A; + \\} + , &[_][]const u8{ + "tmp.zig:4:16: error: comparison of union and enum literal is only valid for tagged union types", + "tmp.zig:2:15: note: type U is not a tagged union", + }); + cases.addTest("shift on type with non-power-of-two size", \\export fn entry() void { \\ const S = struct { From 2b65dc10328cc437b21114e3c87fac2ef6ef9adc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 21 Mar 2020 22:30:46 -0400 Subject: [PATCH 70/79] zig cc: detect optimization and debug flags --- src-self-hosted/clang_options.zig | 10 ++--- src-self-hosted/clang_options_data.zig | 54 +++++++++++++++++++------ src-self-hosted/stage2.zig | 18 ++++++--- src/codegen.cpp | 1 + src/main.cpp | 41 +++++++++++++++++++ src/stage2.h | 3 ++ tools/update_clang_options.zig | 56 ++++++++++++++++++++++++++ 7 files changed, 159 insertions(+), 24 deletions(-) diff --git a/src-self-hosted/clang_options.zig b/src-self-hosted/clang_options.zig index 538f281706..70525655de 100644 --- a/src-self-hosted/clang_options.zig +++ b/src-self-hosted/clang_options.zig @@ -46,23 +46,23 @@ pub const CliArg = struct { multi_arg: u8, }; - pub fn matchEql(self: CliArg, arg: []const u8) bool { + pub fn matchEql(self: CliArg, arg: []const u8) u2 { if (self.pd1 and arg.len >= self.name.len + 1 and mem.startsWith(u8, arg, "-") and mem.eql(u8, arg[1..], self.name)) { - return true; + return 1; } if (self.pd2 and arg.len >= self.name.len + 2 and mem.startsWith(u8, arg, "--") and mem.eql(u8, arg[2..], self.name)) { - return true; + return 2; } if (self.psl and arg.len >= self.name.len + 1 and mem.startsWith(u8, arg, "/") and mem.eql(u8, arg[1..], self.name)) { - return true; + return 1; } - return false; + return 0; } pub fn matchStartsWith(self: CliArg, arg: []const u8) usize { diff --git a/src-self-hosted/clang_options_data.zig b/src-self-hosted/clang_options_data.zig index b1796dce75..1e472f80a5 100644 --- a/src-self-hosted/clang_options_data.zig +++ b/src-self-hosted/clang_options_data.zig @@ -35,7 +35,14 @@ flagpd1("MV"), flagpd1("Mach"), flagpd1("O0"), flagpd1("O4"), -flagpd1("O"), +.{ + .name = "O", + .syntax = .flag, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, flagpd1("ObjC"), flagpd1("ObjC++"), flagpd1("P"), @@ -1485,7 +1492,7 @@ flagpd1("###"), .{ .name = "debug", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .debug, .pd1 = false, .pd2 = true, .psl = false, @@ -1701,7 +1708,7 @@ flagpd1("###"), .{ .name = "optimize", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .optimize, .pd1 = false, .pd2 = true, .psl = false, @@ -2034,7 +2041,7 @@ flagpd1("fno-semantic-interposition"), .{ .name = "O1", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .optimize, .pd1 = true, .pd2 = false, .psl = true, @@ -2042,7 +2049,7 @@ flagpd1("fno-semantic-interposition"), .{ .name = "O2", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .optimize, .pd1 = true, .pd2 = false, .psl = true, @@ -2083,7 +2090,7 @@ flagpd1("fno-ident"), .{ .name = "Og", .syntax = .flag, - .zig_equivalent = .other, + .zig_equivalent = .optimize, .pd1 = true, .pd2 = false, .psl = true, @@ -3088,7 +3095,14 @@ flagpd1("g0"), flagpd1("g1"), flagpd1("g2"), flagpd1("g3"), -flagpd1("g"), +.{ + .name = "g", + .syntax = .flag, + .zig_equivalent = .debug, + .pd1 = true, + .pd2 = false, + .psl = false, +}, sepd1("gcc-toolchain"), flagpd1("gcodeview"), flagpd1("gcodeview-ghash"), @@ -4954,7 +4968,7 @@ joinpd1("flto-jobs="), .{ .name = "fsanitize=", .syntax = .comma_joined, - .zig_equivalent = .other, + .zig_equivalent = .sanitize, .pd1 = true, .pd2 = false, .psl = false, @@ -4997,7 +5011,7 @@ joinpd1("segs_read_"), .{ .name = "optimize=", .syntax = .joined, - .zig_equivalent = .other, + .zig_equivalent = .optimize, .pd1 = false, .pd2 = true, .psl = false, @@ -5187,7 +5201,7 @@ joinpd1("Rpass="), .{ .name = "debug=", .syntax = .joined, - .zig_equivalent = .other, + .zig_equivalent = .debug, .pd1 = false, .pd2 = true, .psl = false, @@ -5231,7 +5245,14 @@ joinpd1("mtune="), .psl = false, }, joinpd1("weak-l"), -joinpd1("Ofast"), +.{ + .name = "Ofast", + .syntax = .joined, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, jspd1("Tdata"), jspd1("Ttext"), .{ @@ -5584,7 +5605,14 @@ jspd1("G"), jspd1("I"), jspd1("J"), jspd1("L"), -joinpd1("O"), +.{ + .name = "O", + .syntax = .joined, + .zig_equivalent = .optimize, + .pd1 = true, + .pd2 = false, + .psl = false, +}, joinpd1("R"), jspd1("T"), jspd1("U"), @@ -5619,7 +5647,7 @@ joinpd1("Z"), .{ .name = "O", .syntax = .joined, - .zig_equivalent = .other, + .zig_equivalent = .optimize, .pd1 = true, .pd2 = false, .psl = true, diff --git a/src-self-hosted/stage2.zig b/src-self-hosted/stage2.zig index 030e9694e8..f67200097c 100644 --- a/src-self-hosted/stage2.zig +++ b/src-self-hosted/stage2.zig @@ -1248,6 +1248,9 @@ pub const ClangArgIterator = extern struct { rdynamic, wl, preprocess, + optimize, + debug, + sanitize, }; fn init(argv: []const [*:0]const u8) ClangArgIterator { @@ -1284,11 +1287,14 @@ pub const ClangArgIterator = extern struct { } find_clang_arg: for (clang_args) |clang_arg| switch (clang_arg.syntax) { - .flag => if (clang_arg.matchEql(arg)) { - self.zig_equivalent = clang_arg.zig_equivalent; - self.only_arg = arg.ptr; + .flag => { + const prefix_len = clang_arg.matchEql(arg); + if (prefix_len > 0) { + self.zig_equivalent = clang_arg.zig_equivalent; + self.only_arg = arg.ptr + prefix_len; - break :find_clang_arg; + break :find_clang_arg; + } }, .joined, .comma_joined => { // joined example: --target=foo @@ -1338,7 +1344,7 @@ pub const ClangArgIterator = extern struct { break :find_clang_arg; } }, - .separate => if (clang_arg.matchEql(arg)) { + .separate => if (clang_arg.matchEql(arg) > 0) { if (self.next_index >= self.argv_len) { std.debug.warn("Expected parameter after '{}'\n", .{arg}); process.exit(1); @@ -1355,7 +1361,7 @@ pub const ClangArgIterator = extern struct { @panic("TODO"); } }, - .multi_arg => if (clang_arg.matchEql(arg)) { + .multi_arg => if (clang_arg.matchEql(arg) > 0) { @panic("TODO"); }, } diff --git a/src/codegen.cpp b/src/codegen.cpp index 7b481f7c21..a0fd984740 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9269,6 +9269,7 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa case BuildModeDebug: // windows c runtime requires -D_DEBUG if using debug libraries args.append("-D_DEBUG"); + args.append("-Og"); if (g->libc_link_lib != nullptr) { args.append("-fstack-protector-strong"); diff --git a/src/main.cpp b/src/main.cpp index 071b365d2f..b47e532d9b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -580,6 +580,7 @@ static int main0(int argc, char **argv) { return stage2_fmt(argc, argv); } else if (argc >= 2 && strcmp(argv[1], "cc") == 0) { emit_h = false; + strip = true; bool c_arg = false; Stage2ClangArgIterator it; @@ -664,6 +665,42 @@ static int main0(int argc, char **argv) { case Stage2ClangArgPreprocess: only_preprocess = true; break; + case Stage2ClangArgOptimize: + // alright what release mode do they want? + if (strcmp(it.only_arg, "Os") == 0) { + build_mode = BuildModeSmallRelease; + } else if (strcmp(it.only_arg, "O2") == 0 || + strcmp(it.only_arg, "O3") == 0 || + strcmp(it.only_arg, "O4") == 0) + { + build_mode = BuildModeFastRelease; + } else if (strcmp(it.only_arg, "Og") == 0) { + build_mode = BuildModeDebug; + } else { + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + } + break; + case Stage2ClangArgDebug: + strip = false; + if (strcmp(it.only_arg, "-g") == 0) { + // we handled with strip = false above + } else { + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + } + break; + case Stage2ClangArgSanitize: + if (strcmp(it.only_arg, "undefined") == 0) { + want_sanitize_c = WantCSanitizeEnabled; + } else { + for (size_t i = 0; i < it.other_args_len; i += 1) { + clang_argv.append(it.other_args_ptr[i]); + } + } + break; } } // Parse linker args @@ -715,6 +752,10 @@ static int main0(int argc, char **argv) { } } + if (want_sanitize_c == WantCSanitizeEnabled && build_mode == BuildModeFastRelease) { + build_mode = BuildModeSafeRelease; + } + if (!nostdlib && !have_libc) { have_libc = true; link_libs.append("c"); diff --git a/src/stage2.h b/src/stage2.h index 15c4c604cd..a66163eceb 100644 --- a/src/stage2.h +++ b/src/stage2.h @@ -334,6 +334,9 @@ enum Stage2ClangArg { Stage2ClangArgRDynamic, Stage2ClangArgWL, Stage2ClangArgPreprocess, + Stage2ClangArgOptimize, + Stage2ClangArgDebug, + Stage2ClangArgSanitize, }; // ABI warning diff --git a/tools/update_clang_options.zig b/tools/update_clang_options.zig index ccd4443130..f65c89c258 100644 --- a/tools/update_clang_options.zig +++ b/tools/update_clang_options.zig @@ -90,6 +90,62 @@ const known_options = [_]KnownOpt{ .name = "assemble", .ident = "driver_punt", }, + .{ + .name = "O1", + .ident = "optimize", + }, + .{ + .name = "O2", + .ident = "optimize", + }, + .{ + .name = "Og", + .ident = "optimize", + }, + .{ + .name = "O", + .ident = "optimize", + }, + .{ + .name = "Ofast", + .ident = "optimize", + }, + .{ + .name = "optimize", + .ident = "optimize", + }, + .{ + .name = "g", + .ident = "debug", + }, + .{ + .name = "debug", + .ident = "debug", + }, + .{ + .name = "g-dwarf", + .ident = "debug", + }, + .{ + .name = "g-dwarf-2", + .ident = "debug", + }, + .{ + .name = "g-dwarf-3", + .ident = "debug", + }, + .{ + .name = "g-dwarf-4", + .ident = "debug", + }, + .{ + .name = "g-dwarf-5", + .ident = "debug", + }, + .{ + .name = "fsanitize", + .ident = "sanitize", + }, }; const blacklisted_options = [_][]const u8{}; From 29324e6f393011ee010b80f2c88d946f082bef22 Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 22 Mar 2020 12:41:11 +1000 Subject: [PATCH 71/79] fix formatting in tokenizer tests --- lib/std/zig/tokenizer.zig | 361 +++++++++++++++++++------------------- 1 file changed, 180 insertions(+), 181 deletions(-) diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 8c9b39d34f..6beaba0fe5 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -1696,216 +1696,215 @@ test "correctly parse pointer assignment" { } test "tokenizer - number literals decimal" { - testTokenize("1", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("2", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("3", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("4", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("5", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("6", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("7", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("8", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("9", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0a", &[_]Token.Id{ .Invalid }); - testTokenize("9b", &[_]Token.Id{ .Invalid }); - testTokenize("1z", &[_]Token.Id{ .Invalid }); - testTokenize("1z_1", &[_]Token.Id{ .Invalid }); - testTokenize("9z3", &[_]Token.Id{ .Invalid }); + testTokenize("0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("2", &[_]Token.Id{.IntegerLiteral}); + testTokenize("3", &[_]Token.Id{.IntegerLiteral}); + testTokenize("4", &[_]Token.Id{.IntegerLiteral}); + testTokenize("5", &[_]Token.Id{.IntegerLiteral}); + testTokenize("6", &[_]Token.Id{.IntegerLiteral}); + testTokenize("7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("8", &[_]Token.Id{.IntegerLiteral}); + testTokenize("9", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0a", &[_]Token.Id{.Invalid}); + testTokenize("9b", &[_]Token.Id{.Invalid}); + testTokenize("1z", &[_]Token.Id{.Invalid}); + testTokenize("1z_1", &[_]Token.Id{.Invalid}); + testTokenize("9z3", &[_]Token.Id{.Invalid}); - testTokenize("0_0", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0001", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("01234567890", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("012_345_6789_0", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0_1_2_3_4_5_6_7_8_9_0", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0_0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0001", &[_]Token.Id{.IntegerLiteral}); + testTokenize("01234567890", &[_]Token.Id{.IntegerLiteral}); + testTokenize("012_345_6789_0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0_1_2_3_4_5_6_7_8_9_0", &[_]Token.Id{.IntegerLiteral}); - testTokenize("00_", &[_]Token.Id{ .Invalid }); - testTokenize("0_0_", &[_]Token.Id{ .Invalid }); - testTokenize("0__0", &[_]Token.Id{ .Invalid }); - testTokenize("0_0f", &[_]Token.Id{ .Invalid }); - testTokenize("0_0_f", &[_]Token.Id{ .Invalid }); - testTokenize("1_,", &[_]Token.Id{ .Invalid }); + testTokenize("00_", &[_]Token.Id{.Invalid}); + testTokenize("0_0_", &[_]Token.Id{.Invalid}); + testTokenize("0__0", &[_]Token.Id{.Invalid}); + testTokenize("0_0f", &[_]Token.Id{.Invalid}); + testTokenize("0_0_f", &[_]Token.Id{.Invalid}); + testTokenize("1_,", &[_]Token.Id{.Invalid}); - testTokenize("1.", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0.0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1.0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("10.0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1e0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1e100", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1.e100", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1.0e100", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1.0e+100", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1.0e-100", &[_]Token.Id{ .FloatLiteral }); - testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("1.", &[_]Token.Id{.FloatLiteral}); + testTokenize("0.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("10.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1e0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1e100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.e100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0e100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0e+100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.0e-100", &[_]Token.Id{.FloatLiteral}); + testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &[_]Token.Id{.FloatLiteral}); - testTokenize("1e", &[_]Token.Id{ .Invalid }); - testTokenize("1.0e1f0", &[_]Token.Id{ .Invalid }); - testTokenize("1.0p100", &[_]Token.Id{ .Invalid }); + testTokenize("1e", &[_]Token.Id{.Invalid}); + testTokenize("1.0e1f0", &[_]Token.Id{.Invalid}); + testTokenize("1.0p100", &[_]Token.Id{.Invalid}); testTokenize("1.0p-100", &[_]Token.Id{ .Invalid, .Minus, .IntegerLiteral }); - testTokenize("1.0p1f0", &[_]Token.Id{ .Invalid }); - testTokenize("1.0_,", &[_]Token.Id{ .Invalid }); - testTokenize("1.0e,", &[_]Token.Id{ .Invalid }); + testTokenize("1.0p1f0", &[_]Token.Id{.Invalid}); + testTokenize("1.0_,", &[_]Token.Id{.Invalid}); + testTokenize("1.0e,", &[_]Token.Id{.Invalid}); } - test "tokenizer - number literals binary" { - testTokenize("0b0", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0b1", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0b2", &[_]Token.Id{ .Invalid }); - testTokenize("0b3", &[_]Token.Id{ .Invalid }); - testTokenize("0b4", &[_]Token.Id{ .Invalid }); - testTokenize("0b5", &[_]Token.Id{ .Invalid }); - testTokenize("0b6", &[_]Token.Id{ .Invalid }); - testTokenize("0b7", &[_]Token.Id{ .Invalid }); - testTokenize("0b8", &[_]Token.Id{ .Invalid }); - testTokenize("0b9", &[_]Token.Id{ .Invalid }); - testTokenize("0ba", &[_]Token.Id{ .Invalid }); - testTokenize("0bb", &[_]Token.Id{ .Invalid }); - testTokenize("0bc", &[_]Token.Id{ .Invalid }); - testTokenize("0bd", &[_]Token.Id{ .Invalid }); - testTokenize("0be", &[_]Token.Id{ .Invalid }); - testTokenize("0bf", &[_]Token.Id{ .Invalid }); - testTokenize("0bz", &[_]Token.Id{ .Invalid }); + testTokenize("0b0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b2", &[_]Token.Id{.Invalid}); + testTokenize("0b3", &[_]Token.Id{.Invalid}); + testTokenize("0b4", &[_]Token.Id{.Invalid}); + testTokenize("0b5", &[_]Token.Id{.Invalid}); + testTokenize("0b6", &[_]Token.Id{.Invalid}); + testTokenize("0b7", &[_]Token.Id{.Invalid}); + testTokenize("0b8", &[_]Token.Id{.Invalid}); + testTokenize("0b9", &[_]Token.Id{.Invalid}); + testTokenize("0ba", &[_]Token.Id{.Invalid}); + testTokenize("0bb", &[_]Token.Id{.Invalid}); + testTokenize("0bc", &[_]Token.Id{.Invalid}); + testTokenize("0bd", &[_]Token.Id{.Invalid}); + testTokenize("0be", &[_]Token.Id{.Invalid}); + testTokenize("0bf", &[_]Token.Id{.Invalid}); + testTokenize("0bz", &[_]Token.Id{.Invalid}); - testTokenize("0b0000_0000", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0b1111_1111", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0b10_10_10_10", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0b0_1_0_1_0_1_0_1", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0b0000_0000", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b1111_1111", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b10_10_10_10", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0b0_1_0_1_0_1_0_1", &[_]Token.Id{.IntegerLiteral}); testTokenize("0b1.", &[_]Token.Id{ .IntegerLiteral, .Period }); testTokenize("0b1.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); - testTokenize("0B0", &[_]Token.Id{ .Invalid }); - testTokenize("0b_", &[_]Token.Id{ .Invalid }); - testTokenize("0b_0", &[_]Token.Id{ .Invalid }); - testTokenize("0b1_", &[_]Token.Id{ .Invalid }); - testTokenize("0b0__1", &[_]Token.Id{ .Invalid }); - testTokenize("0b0_1_", &[_]Token.Id{ .Invalid }); - testTokenize("0b1e", &[_]Token.Id{ .Invalid }); - testTokenize("0b1p", &[_]Token.Id{ .Invalid }); - testTokenize("0b1e0", &[_]Token.Id{ .Invalid }); - testTokenize("0b1p0", &[_]Token.Id{ .Invalid }); - testTokenize("0b1_,", &[_]Token.Id{ .Invalid }); + testTokenize("0B0", &[_]Token.Id{.Invalid}); + testTokenize("0b_", &[_]Token.Id{.Invalid}); + testTokenize("0b_0", &[_]Token.Id{.Invalid}); + testTokenize("0b1_", &[_]Token.Id{.Invalid}); + testTokenize("0b0__1", &[_]Token.Id{.Invalid}); + testTokenize("0b0_1_", &[_]Token.Id{.Invalid}); + testTokenize("0b1e", &[_]Token.Id{.Invalid}); + testTokenize("0b1p", &[_]Token.Id{.Invalid}); + testTokenize("0b1e0", &[_]Token.Id{.Invalid}); + testTokenize("0b1p0", &[_]Token.Id{.Invalid}); + testTokenize("0b1_,", &[_]Token.Id{.Invalid}); } test "tokenizer - number literals octal" { - testTokenize("0o0", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o1", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o2", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o3", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o4", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o5", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o6", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o7", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o8", &[_]Token.Id{ .Invalid }); - testTokenize("0o9", &[_]Token.Id{ .Invalid }); - testTokenize("0oa", &[_]Token.Id{ .Invalid }); - testTokenize("0ob", &[_]Token.Id{ .Invalid }); - testTokenize("0oc", &[_]Token.Id{ .Invalid }); - testTokenize("0od", &[_]Token.Id{ .Invalid }); - testTokenize("0oe", &[_]Token.Id{ .Invalid }); - testTokenize("0of", &[_]Token.Id{ .Invalid }); - testTokenize("0oz", &[_]Token.Id{ .Invalid }); + testTokenize("0o0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o2", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o3", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o4", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o5", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o6", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o8", &[_]Token.Id{.Invalid}); + testTokenize("0o9", &[_]Token.Id{.Invalid}); + testTokenize("0oa", &[_]Token.Id{.Invalid}); + testTokenize("0ob", &[_]Token.Id{.Invalid}); + testTokenize("0oc", &[_]Token.Id{.Invalid}); + testTokenize("0od", &[_]Token.Id{.Invalid}); + testTokenize("0oe", &[_]Token.Id{.Invalid}); + testTokenize("0of", &[_]Token.Id{.Invalid}); + testTokenize("0oz", &[_]Token.Id{.Invalid}); - testTokenize("0o01234567", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o0123_4567", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o01_23_45_67", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0o0_1_2_3_4_5_6_7", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0o01234567", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o0123_4567", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o01_23_45_67", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0o0_1_2_3_4_5_6_7", &[_]Token.Id{.IntegerLiteral}); testTokenize("0o7.", &[_]Token.Id{ .IntegerLiteral, .Period }); testTokenize("0o7.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); - testTokenize("0O0", &[_]Token.Id{ .Invalid }); - testTokenize("0o_", &[_]Token.Id{ .Invalid }); - testTokenize("0o_0", &[_]Token.Id{ .Invalid }); - testTokenize("0o1_", &[_]Token.Id{ .Invalid }); - testTokenize("0o0__1", &[_]Token.Id{ .Invalid }); - testTokenize("0o0_1_", &[_]Token.Id{ .Invalid }); - testTokenize("0o1e", &[_]Token.Id{ .Invalid }); - testTokenize("0o1p", &[_]Token.Id{ .Invalid }); - testTokenize("0o1e0", &[_]Token.Id{ .Invalid }); - testTokenize("0o1p0", &[_]Token.Id{ .Invalid }); - testTokenize("0o_,", &[_]Token.Id{ .Invalid }); + testTokenize("0O0", &[_]Token.Id{.Invalid}); + testTokenize("0o_", &[_]Token.Id{.Invalid}); + testTokenize("0o_0", &[_]Token.Id{.Invalid}); + testTokenize("0o1_", &[_]Token.Id{.Invalid}); + testTokenize("0o0__1", &[_]Token.Id{.Invalid}); + testTokenize("0o0_1_", &[_]Token.Id{.Invalid}); + testTokenize("0o1e", &[_]Token.Id{.Invalid}); + testTokenize("0o1p", &[_]Token.Id{.Invalid}); + testTokenize("0o1e0", &[_]Token.Id{.Invalid}); + testTokenize("0o1p0", &[_]Token.Id{.Invalid}); + testTokenize("0o_,", &[_]Token.Id{.Invalid}); } test "tokenizer - number literals hexadeciaml" { - testTokenize("0x0", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x1", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x2", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x3", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x4", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x5", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x6", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x7", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x8", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x9", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xa", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xb", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xc", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xd", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xe", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xf", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xA", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xB", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xC", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xD", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xE", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0xF", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x0z", &[_]Token.Id{ .Invalid }); - testTokenize("0xz", &[_]Token.Id{ .Invalid }); + testTokenize("0x0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x1", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x2", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x3", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x4", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x5", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x6", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x7", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x8", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x9", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xa", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xb", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xc", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xd", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xe", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xf", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xA", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xB", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xC", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xD", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xE", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0xF", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x0z", &[_]Token.Id{.Invalid}); + testTokenize("0xz", &[_]Token.Id{.Invalid}); - testTokenize("0x0123456789ABCDEF", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x0123_4567_89AB_CDEF", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x01_23_45_67_89AB_CDE_F", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &[_]Token.Id{ .IntegerLiteral }); + testTokenize("0x0123456789ABCDEF", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x0123_4567_89AB_CDEF", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x01_23_45_67_89AB_CDE_F", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &[_]Token.Id{.IntegerLiteral}); - testTokenize("0X0", &[_]Token.Id{ .Invalid }); - testTokenize("0x_", &[_]Token.Id{ .Invalid }); - testTokenize("0x_1", &[_]Token.Id{ .Invalid }); - testTokenize("0x1_", &[_]Token.Id{ .Invalid }); - testTokenize("0x0__1", &[_]Token.Id{ .Invalid }); - testTokenize("0x0_1_", &[_]Token.Id{ .Invalid }); - testTokenize("0x_,", &[_]Token.Id{ .Invalid }); + testTokenize("0X0", &[_]Token.Id{.Invalid}); + testTokenize("0x_", &[_]Token.Id{.Invalid}); + testTokenize("0x_1", &[_]Token.Id{.Invalid}); + testTokenize("0x1_", &[_]Token.Id{.Invalid}); + testTokenize("0x0__1", &[_]Token.Id{.Invalid}); + testTokenize("0x0_1_", &[_]Token.Id{.Invalid}); + testTokenize("0x_,", &[_]Token.Id{.Invalid}); - testTokenize("0x1.", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0x1.0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xF.", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xF.0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xF.F", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xF.Fp0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xF.FP0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0x1p0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xfp0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x1.", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x1.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.F", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.Fp0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xF.FP0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x1p0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xfp0", &[_]Token.Id{.FloatLiteral}); - testTokenize("0x0123456.789ABCDEF", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0x0_123_456.789_ABC_DEF", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0x0.0p0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xff.ffp10", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xff.ffP10", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xff.p10", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xffp10", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xff_ff.ff_ffp1_0_0_0", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xf_f_f_f.f_f_f_fp+1_000", &[_]Token.Id{ .FloatLiteral }); - testTokenize("0xf_f_f_f.f_f_f_fp-1_00_0", &[_]Token.Id{ .FloatLiteral }); + testTokenize("0x0123456.789ABCDEF", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0_123_456.789_ABC_DEF", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0.0p0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff.ffp10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff.ffP10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff.p10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xffp10", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xff_ff.ff_ffp1_0_0_0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xf_f_f_f.f_f_f_fp+1_000", &[_]Token.Id{.FloatLiteral}); + testTokenize("0xf_f_f_f.f_f_f_fp-1_00_0", &[_]Token.Id{.FloatLiteral}); - testTokenize("0x1e", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x1e0", &[_]Token.Id{ .IntegerLiteral }); - testTokenize("0x1p", &[_]Token.Id{ .Invalid }); - testTokenize("0xfp0z1", &[_]Token.Id{ .Invalid }); - testTokenize("0xff.ffpff", &[_]Token.Id{ .Invalid }); - testTokenize("0x0_.0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0._0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0_", &[_]Token.Id{ .Invalid }); - testTokenize("0x0_p0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0_.p0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0._p0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0_p0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0._0p0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0_p0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0p_0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0p+_0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0p-_0", &[_]Token.Id{ .Invalid }); - testTokenize("0x0.0p0_", &[_]Token.Id{ .Invalid }); + testTokenize("0x1e", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x1e0", &[_]Token.Id{.IntegerLiteral}); + testTokenize("0x1p", &[_]Token.Id{.Invalid}); + testTokenize("0xfp0z1", &[_]Token.Id{.Invalid}); + testTokenize("0xff.ffpff", &[_]Token.Id{.Invalid}); + testTokenize("0x0_.0", &[_]Token.Id{.Invalid}); + testTokenize("0x0._0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0_", &[_]Token.Id{.Invalid}); + testTokenize("0x0_p0", &[_]Token.Id{.Invalid}); + testTokenize("0x0_.p0", &[_]Token.Id{.Invalid}); + testTokenize("0x0._p0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0_p0", &[_]Token.Id{.Invalid}); + testTokenize("0x0._0p0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0_p0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0p_0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0p+_0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0p-_0", &[_]Token.Id{.Invalid}); + testTokenize("0x0.0p0_", &[_]Token.Id{.Invalid}); } - fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { var tokenizer = Tokenizer.init(source); for (expected_tokens) |expected_token_id| { From a8fa1ecd89eebd444736d73da4ebf24af74daea8 Mon Sep 17 00:00:00 2001 From: dbandstra Date: Sat, 21 Mar 2020 19:53:05 -0700 Subject: [PATCH 72/79] fix build.zig addBuildOption function for stream refactor --- lib/std/build.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/build.zig b/lib/std/build.zig index ac411d6cf6..c603fd861b 100644 --- a/lib/std/build.zig +++ b/lib/std/build.zig @@ -1679,7 +1679,7 @@ pub const LibExeObjStep = struct { } pub fn addBuildOption(self: *LibExeObjStep, comptime T: type, name: []const u8, value: T) void { - const out = &std.io.BufferOutStream.init(&self.build_options_contents).stream; + const out = self.build_options_contents.outStream(); out.print("pub const {} = {};\n", .{ name, value }) catch unreachable; } From 8de45e51438d7f593825ae2134ab7dfc46f3bab2 Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Sun, 22 Mar 2020 13:45:31 +1000 Subject: [PATCH 73/79] update parsing of int literals in self-hosted * update std.math.big.Int.setString() to ignore underscores and make it case insensitive * fix issue in ir.zig with leading zeroes in integer literals --- lib/std/math/big/int.zig | 25 +++++++++++++++++++++++-- src-self-hosted/ir.zig | 7 +++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 95d0764f68..3557a40798 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -373,6 +373,7 @@ pub const Int = struct { const d = switch (ch) { '0'...'9' => ch - '0', 'a'...'f' => (ch - 'a') + 0xa, + 'A'...'F' => (ch - 'A') + 0xa, else => return error.InvalidCharForDigit, }; @@ -393,8 +394,9 @@ pub const Int = struct { /// Set self from the string representation `value`. /// - /// value must contain only digits <= `base`. Base prefixes are not allowed (e.g. 0x43 should - /// simply be 43). + /// `value` must contain only digits <= `base` and is case insensitive. Base prefixes are + /// not allowed (e.g. 0x43 should simply be 43). Underscores in the input string are + /// ignored and can be used as digit separators. /// /// Returns an error if memory could not be allocated or `value` has invalid digits for the /// requested base. @@ -415,6 +417,9 @@ pub const Int = struct { try self.set(0); for (value[i..]) |ch| { + if (ch == '_') { + continue; + } const d = try charToDigit(ch, base); const ap_d = Int.initFixed(([_]Limb{d})[0..]); @@ -1582,6 +1587,22 @@ test "big.int string negative" { testing.expect((try a.to(i32)) == -1023); } +test "big.int string set number with underscores" { + var a = try Int.init(testing.allocator); + defer a.deinit(); + + try a.setString(10, "__1_2_0_3_1_7_2_4_1_2_0_____9_1__2__4_7_8_1_2_4_1_2_9_0_8_4_7_1_2_4___"); + testing.expect((try a.to(u128)) == 120317241209124781241290847124); +} + +test "big.int string set case insensitive number" { + var a = try Int.init(testing.allocator); + defer a.deinit(); + + try a.setString(16, "aB_cD_eF"); + testing.expect((try a.to(u32)) == 0xabcdef); +} + test "big.int string set bad char error" { var a = try Int.init(testing.allocator); defer a.deinit(); diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 2e65962d41..e3d13b43db 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -1311,13 +1311,16 @@ pub const Builder = struct { var base: u8 = undefined; var rest: []const u8 = undefined; if (int_token.len >= 3 and int_token[0] == '0') { + rest = int_token[2..]; base = switch (int_token[1]) { 'b' => 2, 'o' => 8, 'x' => 16, - else => unreachable, + else => { + base = 10; + rest = int_token; + }, }; - rest = int_token[2..]; } else { base = 10; rest = int_token; From 6a89751025abc074d31bbbab5b01a7e701f1abce Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 21 Mar 2020 18:00:19 +0100 Subject: [PATCH 74/79] ir: Implement cast from anon struct to union --- src/ir.cpp | 74 ++++++++++++++++++++++++++++++++-- test/stage1/behavior/union.zig | 28 +++++++++++++ 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 590b81d3be..b64128bef9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -276,6 +276,11 @@ static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime); static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime); +static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instruction, + AstNode *field_source_node, ZigType *union_type, Buf *field_name, IrInstGen *field_result_loc, + IrInstGen *result_loc); +static IrInstGen *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst* source_instr, + IrInstGen *struct_operand, TypeStructField *field); static void destroy_instruction_src(IrInstSrc *inst) { switch (inst->id) { @@ -14445,10 +14450,71 @@ static IrInstGen *ir_analyze_struct_literal_to_struct(IrAnalyze *ira, IrInst* so } static IrInstGen *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInst* source_instr, - IrInstGen *value, ZigType *wanted_type) + IrInstGen *value, ZigType *union_type) { - ir_add_error(ira, source_instr, buf_sprintf("TODO: type coercion of anon struct literal to union")); - return ira->codegen->invalid_inst_gen; + Error err; + ZigType *struct_type = value->value->type; + + assert(struct_type->id == ZigTypeIdStruct); + assert(union_type->id == ZigTypeIdUnion); + assert(struct_type->data.structure.src_field_count == 1); + + TypeStructField *only_field = struct_type->data.structure.fields[0]; + + if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_inst_gen; + + TypeUnionField *union_field = find_union_type_field(union_type, only_field->name); + if (union_field == nullptr) { + ir_add_error_node(ira, only_field->decl_node, + buf_sprintf("no member named '%s' in union '%s'", + buf_ptr(only_field->name), buf_ptr(&union_type->name))); + return ira->codegen->invalid_inst_gen; + } + + ZigType *payload_type = resolve_union_field_type(ira->codegen, union_field); + if (payload_type == nullptr) + return ira->codegen->invalid_inst_gen; + + IrInstGen *field_value = ir_analyze_struct_value_field_value(ira, source_instr, value, only_field); + if (type_is_invalid(field_value->value->type)) + return ira->codegen->invalid_inst_gen; + + IrInstGen *casted_value = ir_implicit_cast(ira, field_value, payload_type); + if (type_is_invalid(casted_value->value->type)) + return ira->codegen->invalid_inst_gen; + + if (instr_is_comptime(casted_value)) { + ZigValue *val = ir_resolve_const(ira, casted_value, UndefBad); + if (val == nullptr) + return ira->codegen->invalid_inst_gen; + + IrInstGen *result = ir_const(ira, source_instr, union_type); + bigint_init_bigint(&result->value->data.x_union.tag, &union_field->enum_field->value); + result->value->data.x_union.payload = val; + + val->parent.id = ConstParentIdUnion; + val->parent.data.p_union.union_val = result->value; + + return result; + } + + IrInstGen *result_loc_inst = ir_resolve_result(ira, source_instr, no_result_loc(), + union_type, nullptr, true, true); + if (type_is_invalid(result_loc_inst->value->type) || result_loc_inst->value->type->id == ZigTypeIdUnreachable) { + return ira->codegen->invalid_inst_gen; + } + + IrInstGen *payload_ptr = ir_analyze_container_field_ptr(ira, only_field->name, source_instr, + result_loc_inst, source_instr, union_type, true); + if (type_is_invalid(payload_ptr->value->type)) + return ira->codegen->invalid_inst_gen; + + IrInstGen *store_ptr_inst = ir_analyze_store_ptr(ira, source_instr, payload_ptr, casted_value, false); + if (type_is_invalid(store_ptr_inst->value->type)) + return ira->codegen->invalid_inst_gen; + + return ir_get_deref(ira, source_instr, result_loc_inst, nullptr); } // Add a compile error and return ErrorSemanticAnalyzeFail if the pointer alignment does not work, @@ -23050,7 +23116,7 @@ static IrInstGen *ir_analyze_union_init(IrAnalyze *ira, IrInst* source_instructi Error err; assert(union_type->id == ZigTypeIdUnion); - if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown))) + if ((err = type_resolve(ira->codegen, union_type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_inst_gen; TypeUnionField *type_field = find_union_type_field(union_type, field_name); diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 7f49049f58..be7a84c5b4 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -1,5 +1,6 @@ const std = @import("std"); const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; const Value = union(enum) { Int: u64, @@ -638,3 +639,30 @@ test "runtime tag name with single field" { var v = U{ .A = 42 }; expect(std.mem.eql(u8, @tagName(v), "A")); } + +test "cast from anonymous struct to union" { + const S = struct { + const U = union(enum) { + A: u32, + B: []const u8, + C: void, + }; + fn doTheTest() void { + var y: u32 = 42; + const t0 = .{ .A = 123 }; + const t1 = .{ .B = "foo" }; + const t2 = .{ .C = {} }; + const t3 = .{ .A = y }; + const x0: U = t0; + var x1: U = t1; + const x2: U = t2; + var x3: U = t3; + expect(x0.A == 123); + expect(std.mem.eql(u8, x1.B, "foo")); + expect(x2 == .C); + expect(x3.A == y); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} From 9d19d9008eb70d069b799dd65a68bb410a5dff8e Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 22 Mar 2020 22:47:28 +0100 Subject: [PATCH 75/79] debug: Correct version check in debug_line parser Version 3 is similar to version 2 plus more opcodes. --- lib/std/dwarf.zig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index 769f349e33..d198886b11 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -717,8 +717,7 @@ pub const DwarfInfo = struct { const next_offset = unit_length + (if (is_64) @as(usize, 12) else @as(usize, 4)); const version = try in.readInt(u16, di.endian); - // TODO support 3 and 5 - if (version != 2 and version != 4) return error.InvalidDebugInfo; + if (version < 2 or version > 4) return error.InvalidDebugInfo; const prologue_length = if (is_64) try in.readInt(u64, di.endian) else try in.readInt(u32, di.endian); const prog_start_offset = (try seekable.getPos()) + prologue_length; From 2d18178c27060ff9b9b4a5b56941617dc47868d0 Mon Sep 17 00:00:00 2001 From: momumi <57862114+momumi@users.noreply.github.com> Date: Mon, 23 Mar 2020 09:21:34 +1000 Subject: [PATCH 76/79] minor fixes and more tests for _ separators * Make the tokenizer spit out an Invalid token on the first invalid character found in the number literal. * More parsing and tokenizer tests for number literals * fix invalid switch statement in ir.zig --- lib/std/zig/parser_test.zig | 69 +++++++++ lib/std/zig/tokenizer.zig | 275 ++++++++++++++++++++++-------------- src-self-hosted/ir.zig | 10 +- 3 files changed, 242 insertions(+), 112 deletions(-) diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index d00568e49f..00f6b33673 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -2800,6 +2800,75 @@ test "zig fmt: extern without container keyword returns error" { ); } +test "zig fmt: integer literals with underscore separators" { + try testTransform( + \\const + \\ x = + \\ 1_234_567 + \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0; + , + \\const x = 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0; + \\ + ); +} + +test "zig fmt: hex literals with underscore separators" { + try testTransform( + \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { + \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; + \\ for (c [ 0_0 .. ]) |_, i| { + \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; + \\ } + \\ return c; + \\} + \\ + \\ + , + \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { + \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; + \\ for (c[0_0..]) |_, i| { + \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; + \\ } + \\ return c; + \\} + \\ + ); +} + +test "zig fmt: decimal float literals with underscore separators" { + try testTransform( + \\pub fn main() void { + \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; + \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + , + \\pub fn main() void { + \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; + \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + \\ + ); +} + +test "zig fmt: hexadeciaml float literals with underscore separators" { + try testTransform( + \\pub fn main() void { + \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; + \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + , + \\pub fn main() void { + \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; + \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; + \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); + \\} + \\ + ); +} + const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 6beaba0fe5..6cb66595a7 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -418,6 +418,10 @@ pub const Tokenizer = struct { SawAtSign, }; + fn isIdentifierChar(char: u8) bool { + return std.ascii.isAlNum(char) or char == '_'; + } + pub fn next(self: *Tokenizer) Token { if (self.pending_invalid_token) |token| { self.pending_invalid_token = null; @@ -1063,11 +1067,17 @@ pub const Tokenizer = struct { 'x' => { state = State.IntegerLiteralHexNoUnderscore; }, - else => { - // reinterpret as a normal number + '0'...'9', '_', '.', 'e', 'E' => { + // reinterpret as a decimal number self.index -= 1; state = State.IntegerLiteralDec; }, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; + }, }, State.IntegerLiteralBinNoUnderscore => switch (c) { '0'...'1' => { @@ -1075,6 +1085,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.IntegerLiteralBin => switch (c) { @@ -1082,10 +1093,12 @@ pub const Tokenizer = struct { state = State.IntegerLiteralBinNoUnderscore; }, '0'...'1' => {}, - '2'...'9', 'a'...'z', 'A'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, State.IntegerLiteralOctNoUnderscore => switch (c) { '0'...'7' => { @@ -1093,6 +1106,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.IntegerLiteralOct => switch (c) { @@ -1100,10 +1114,12 @@ pub const Tokenizer = struct { state = State.IntegerLiteralOctNoUnderscore; }, '0'...'7' => {}, - '8'...'9', 'a'...'z', 'A'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, State.IntegerLiteralDecNoUnderscore => switch (c) { '0'...'9' => { @@ -1111,6 +1127,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.IntegerLiteralDec => switch (c) { @@ -1126,10 +1143,12 @@ pub const Tokenizer = struct { result.id = Token.Id.FloatLiteral; }, '0'...'9' => {}, - 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, State.IntegerLiteralHexNoUnderscore => switch (c) { '0'...'9', 'a'...'f', 'A'...'F' => { @@ -1137,6 +1156,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.IntegerLiteralHex => switch (c) { @@ -1152,10 +1172,12 @@ pub const Tokenizer = struct { result.id = Token.Id.FloatLiteral; }, '0'...'9', 'a'...'f', 'A'...'F' => {}, - 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, State.NumberDotDec => switch (c) { '.' => { @@ -1166,10 +1188,15 @@ pub const Tokenizer = struct { 'e', 'E' => { state = State.FloatExponentUnsigned; }, - else => { - self.index -= 1; + '0'...'9' => { result.id = Token.Id.FloatLiteral; - state = State.FloatFractionDecNoUnderscore; + state = State.FloatFractionDec; + }, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, }, State.NumberDotHex => switch (c) { @@ -1181,10 +1208,15 @@ pub const Tokenizer = struct { 'p', 'P' => { state = State.FloatExponentUnsigned; }, - else => { - self.index -= 1; + '0'...'9', 'a'...'f', 'A'...'F' => { result.id = Token.Id.FloatLiteral; - state = State.FloatFractionHexNoUnderscore; + state = State.FloatFractionHex; + }, + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, }, State.FloatFractionDecNoUnderscore => switch (c) { @@ -1193,6 +1225,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.FloatFractionDec => switch (c) { @@ -1203,10 +1236,12 @@ pub const Tokenizer = struct { state = State.FloatExponentUnsigned; }, '0'...'9' => {}, - 'a'...'d', 'f'...'z', 'A'...'D', 'F'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, State.FloatFractionHexNoUnderscore => switch (c) { '0'...'9', 'a'...'f', 'A'...'F' => { @@ -1214,6 +1249,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.FloatFractionHex => switch (c) { @@ -1224,10 +1260,12 @@ pub const Tokenizer = struct { state = State.FloatExponentUnsigned; }, '0'...'9', 'a'...'f', 'A'...'F' => {}, - 'g'...'o', 'q'...'z', 'G'...'O', 'Q'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, State.FloatExponentUnsigned => switch (c) { '+', '-' => { @@ -1245,6 +1283,7 @@ pub const Tokenizer = struct { }, else => { result.id = Token.Id.Invalid; + break; }, }, State.FloatExponentNumber => switch (c) { @@ -1252,10 +1291,12 @@ pub const Tokenizer = struct { state = State.FloatExponentNumberNoUnderscore; }, '0'...'9' => {}, - 'a'...'z', 'A'...'Z' => { - result.id = Token.Id.Invalid; + else => { + if (isIdentifierChar(c)) { + result.id = Token.Id.Invalid; + } + break; }, - else => break, }, } } else if (self.index == self.buffer.len) { @@ -1706,11 +1747,11 @@ test "tokenizer - number literals decimal" { testTokenize("7", &[_]Token.Id{.IntegerLiteral}); testTokenize("8", &[_]Token.Id{.IntegerLiteral}); testTokenize("9", &[_]Token.Id{.IntegerLiteral}); - testTokenize("0a", &[_]Token.Id{.Invalid}); - testTokenize("9b", &[_]Token.Id{.Invalid}); - testTokenize("1z", &[_]Token.Id{.Invalid}); - testTokenize("1z_1", &[_]Token.Id{.Invalid}); - testTokenize("9z3", &[_]Token.Id{.Invalid}); + testTokenize("0a", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("9b", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1z_1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("9z3", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0_0", &[_]Token.Id{.IntegerLiteral}); testTokenize("0001", &[_]Token.Id{.IntegerLiteral}); @@ -1720,15 +1761,17 @@ test "tokenizer - number literals decimal" { testTokenize("00_", &[_]Token.Id{.Invalid}); testTokenize("0_0_", &[_]Token.Id{.Invalid}); - testTokenize("0__0", &[_]Token.Id{.Invalid}); - testTokenize("0_0f", &[_]Token.Id{.Invalid}); - testTokenize("0_0_f", &[_]Token.Id{.Invalid}); - testTokenize("1_,", &[_]Token.Id{.Invalid}); + testTokenize("0__0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0_0f", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0_0_f", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0_0_f_00", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1_,", &[_]Token.Id{ .Invalid, .Comma }); testTokenize("1.", &[_]Token.Id{.FloatLiteral}); testTokenize("0.0", &[_]Token.Id{.FloatLiteral}); testTokenize("1.0", &[_]Token.Id{.FloatLiteral}); testTokenize("10.0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0e0", &[_]Token.Id{.FloatLiteral}); testTokenize("1e0", &[_]Token.Id{.FloatLiteral}); testTokenize("1e100", &[_]Token.Id{.FloatLiteral}); testTokenize("1.e100", &[_]Token.Id{.FloatLiteral}); @@ -1736,34 +1779,47 @@ test "tokenizer - number literals decimal" { testTokenize("1.0e+100", &[_]Token.Id{.FloatLiteral}); testTokenize("1.0e-100", &[_]Token.Id{.FloatLiteral}); testTokenize("1_0_0_0.0_0_0_0_0_1e1_0_0_0", &[_]Token.Id{.FloatLiteral}); + testTokenize("1.+", &[_]Token.Id{ .FloatLiteral, .Plus }); testTokenize("1e", &[_]Token.Id{.Invalid}); - testTokenize("1.0e1f0", &[_]Token.Id{.Invalid}); - testTokenize("1.0p100", &[_]Token.Id{.Invalid}); - testTokenize("1.0p-100", &[_]Token.Id{ .Invalid, .Minus, .IntegerLiteral }); - testTokenize("1.0p1f0", &[_]Token.Id{.Invalid}); - testTokenize("1.0_,", &[_]Token.Id{.Invalid}); - testTokenize("1.0e,", &[_]Token.Id{.Invalid}); + testTokenize("1.0e1f0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0p100", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0p-100", &[_]Token.Id{ .Invalid, .Identifier, .Minus, .IntegerLiteral }); + testTokenize("1.0p1f0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0_,", &[_]Token.Id{ .Invalid, .Comma }); + testTokenize("1_.0", &[_]Token.Id{ .Invalid, .Period, .IntegerLiteral }); + testTokenize("1._", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.a", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1._0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1._+", &[_]Token.Id{ .Invalid, .Identifier, .Plus }); + testTokenize("1._e", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e", &[_]Token.Id{.Invalid}); + testTokenize("1.0e,", &[_]Token.Id{ .Invalid, .Comma }); + testTokenize("1.0e_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e+_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e-_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("1.0e0_+", &[_]Token.Id{ .Invalid, .Plus }); } test "tokenizer - number literals binary" { testTokenize("0b0", &[_]Token.Id{.IntegerLiteral}); testTokenize("0b1", &[_]Token.Id{.IntegerLiteral}); - testTokenize("0b2", &[_]Token.Id{.Invalid}); - testTokenize("0b3", &[_]Token.Id{.Invalid}); - testTokenize("0b4", &[_]Token.Id{.Invalid}); - testTokenize("0b5", &[_]Token.Id{.Invalid}); - testTokenize("0b6", &[_]Token.Id{.Invalid}); - testTokenize("0b7", &[_]Token.Id{.Invalid}); - testTokenize("0b8", &[_]Token.Id{.Invalid}); - testTokenize("0b9", &[_]Token.Id{.Invalid}); - testTokenize("0ba", &[_]Token.Id{.Invalid}); - testTokenize("0bb", &[_]Token.Id{.Invalid}); - testTokenize("0bc", &[_]Token.Id{.Invalid}); - testTokenize("0bd", &[_]Token.Id{.Invalid}); - testTokenize("0be", &[_]Token.Id{.Invalid}); - testTokenize("0bf", &[_]Token.Id{.Invalid}); - testTokenize("0bz", &[_]Token.Id{.Invalid}); + testTokenize("0b2", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b3", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b4", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b5", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b6", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b7", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b8", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0b9", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0ba", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bb", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bc", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bd", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0be", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bf", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0bz", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0b0000_0000", &[_]Token.Id{.IntegerLiteral}); testTokenize("0b1111_1111", &[_]Token.Id{.IntegerLiteral}); @@ -1772,17 +1828,17 @@ test "tokenizer - number literals binary" { testTokenize("0b1.", &[_]Token.Id{ .IntegerLiteral, .Period }); testTokenize("0b1.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); - testTokenize("0B0", &[_]Token.Id{.Invalid}); - testTokenize("0b_", &[_]Token.Id{.Invalid}); - testTokenize("0b_0", &[_]Token.Id{.Invalid}); + testTokenize("0B0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b_0", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0b1_", &[_]Token.Id{.Invalid}); - testTokenize("0b0__1", &[_]Token.Id{.Invalid}); + testTokenize("0b0__1", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0b0_1_", &[_]Token.Id{.Invalid}); - testTokenize("0b1e", &[_]Token.Id{.Invalid}); - testTokenize("0b1p", &[_]Token.Id{.Invalid}); - testTokenize("0b1e0", &[_]Token.Id{.Invalid}); - testTokenize("0b1p0", &[_]Token.Id{.Invalid}); - testTokenize("0b1_,", &[_]Token.Id{.Invalid}); + testTokenize("0b1e", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1p", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1e0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0b1_,", &[_]Token.Id{ .Invalid, .Comma }); } test "tokenizer - number literals octal" { @@ -1794,15 +1850,15 @@ test "tokenizer - number literals octal" { testTokenize("0o5", &[_]Token.Id{.IntegerLiteral}); testTokenize("0o6", &[_]Token.Id{.IntegerLiteral}); testTokenize("0o7", &[_]Token.Id{.IntegerLiteral}); - testTokenize("0o8", &[_]Token.Id{.Invalid}); - testTokenize("0o9", &[_]Token.Id{.Invalid}); - testTokenize("0oa", &[_]Token.Id{.Invalid}); - testTokenize("0ob", &[_]Token.Id{.Invalid}); - testTokenize("0oc", &[_]Token.Id{.Invalid}); - testTokenize("0od", &[_]Token.Id{.Invalid}); - testTokenize("0oe", &[_]Token.Id{.Invalid}); - testTokenize("0of", &[_]Token.Id{.Invalid}); - testTokenize("0oz", &[_]Token.Id{.Invalid}); + testTokenize("0o8", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0o9", &[_]Token.Id{ .Invalid, .IntegerLiteral }); + testTokenize("0oa", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0ob", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0oc", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0od", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0oe", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0of", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0oz", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0o01234567", &[_]Token.Id{.IntegerLiteral}); testTokenize("0o0123_4567", &[_]Token.Id{.IntegerLiteral}); @@ -1811,17 +1867,17 @@ test "tokenizer - number literals octal" { testTokenize("0o7.", &[_]Token.Id{ .IntegerLiteral, .Period }); testTokenize("0o7.0", &[_]Token.Id{ .IntegerLiteral, .Period, .IntegerLiteral }); - testTokenize("0O0", &[_]Token.Id{.Invalid}); - testTokenize("0o_", &[_]Token.Id{.Invalid}); - testTokenize("0o_0", &[_]Token.Id{.Invalid}); + testTokenize("0O0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o_0", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0o1_", &[_]Token.Id{.Invalid}); - testTokenize("0o0__1", &[_]Token.Id{.Invalid}); + testTokenize("0o0__1", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0o0_1_", &[_]Token.Id{.Invalid}); - testTokenize("0o1e", &[_]Token.Id{.Invalid}); - testTokenize("0o1p", &[_]Token.Id{.Invalid}); - testTokenize("0o1e0", &[_]Token.Id{.Invalid}); - testTokenize("0o1p0", &[_]Token.Id{.Invalid}); - testTokenize("0o_,", &[_]Token.Id{.Invalid}); + testTokenize("0o1e", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1p", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1e0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o1p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0o_,", &[_]Token.Id{ .Invalid, .Identifier, .Comma }); } test "tokenizer - number literals hexadeciaml" { @@ -1847,21 +1903,21 @@ test "tokenizer - number literals hexadeciaml" { testTokenize("0xD", &[_]Token.Id{.IntegerLiteral}); testTokenize("0xE", &[_]Token.Id{.IntegerLiteral}); testTokenize("0xF", &[_]Token.Id{.IntegerLiteral}); - testTokenize("0x0z", &[_]Token.Id{.Invalid}); - testTokenize("0xz", &[_]Token.Id{.Invalid}); + testTokenize("0x0z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0xz", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0x0123456789ABCDEF", &[_]Token.Id{.IntegerLiteral}); testTokenize("0x0123_4567_89AB_CDEF", &[_]Token.Id{.IntegerLiteral}); testTokenize("0x01_23_45_67_89AB_CDE_F", &[_]Token.Id{.IntegerLiteral}); testTokenize("0x0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F", &[_]Token.Id{.IntegerLiteral}); - testTokenize("0X0", &[_]Token.Id{.Invalid}); - testTokenize("0x_", &[_]Token.Id{.Invalid}); - testTokenize("0x_1", &[_]Token.Id{.Invalid}); + testTokenize("0X0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x_", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x_1", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0x1_", &[_]Token.Id{.Invalid}); - testTokenize("0x0__1", &[_]Token.Id{.Invalid}); + testTokenize("0x0__1", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0x0_1_", &[_]Token.Id{.Invalid}); - testTokenize("0x_,", &[_]Token.Id{.Invalid}); + testTokenize("0x_,", &[_]Token.Id{ .Invalid, .Identifier, .Comma }); testTokenize("0x1.", &[_]Token.Id{.FloatLiteral}); testTokenize("0x1.0", &[_]Token.Id{.FloatLiteral}); @@ -1872,10 +1928,12 @@ test "tokenizer - number literals hexadeciaml" { testTokenize("0xF.FP0", &[_]Token.Id{.FloatLiteral}); testTokenize("0x1p0", &[_]Token.Id{.FloatLiteral}); testTokenize("0xfp0", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x1.+0xF.", &[_]Token.Id{ .FloatLiteral, .Plus, .FloatLiteral }); testTokenize("0x0123456.789ABCDEF", &[_]Token.Id{.FloatLiteral}); testTokenize("0x0_123_456.789_ABC_DEF", &[_]Token.Id{.FloatLiteral}); testTokenize("0x0_1_2_3_4_5_6.7_8_9_A_B_C_D_E_F", &[_]Token.Id{.FloatLiteral}); + testTokenize("0x0p0", &[_]Token.Id{.FloatLiteral}); testTokenize("0x0.0p0", &[_]Token.Id{.FloatLiteral}); testTokenize("0xff.ffp10", &[_]Token.Id{.FloatLiteral}); testTokenize("0xff.ffP10", &[_]Token.Id{.FloatLiteral}); @@ -1888,21 +1946,24 @@ test "tokenizer - number literals hexadeciaml" { testTokenize("0x1e", &[_]Token.Id{.IntegerLiteral}); testTokenize("0x1e0", &[_]Token.Id{.IntegerLiteral}); testTokenize("0x1p", &[_]Token.Id{.Invalid}); - testTokenize("0xfp0z1", &[_]Token.Id{.Invalid}); - testTokenize("0xff.ffpff", &[_]Token.Id{.Invalid}); - testTokenize("0x0_.0", &[_]Token.Id{.Invalid}); - testTokenize("0x0._0", &[_]Token.Id{.Invalid}); + testTokenize("0xfp0z1", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0xff.ffpff", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.p", &[_]Token.Id{.Invalid}); + testTokenize("0x0.z", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0._", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0_.0", &[_]Token.Id{ .Invalid, .Period, .IntegerLiteral }); + testTokenize("0x0_.0.0", &[_]Token.Id{ .Invalid, .Period, .FloatLiteral }); + testTokenize("0x0._0", &[_]Token.Id{ .Invalid, .Identifier }); testTokenize("0x0.0_", &[_]Token.Id{.Invalid}); - testTokenize("0x0_p0", &[_]Token.Id{.Invalid}); - testTokenize("0x0_.p0", &[_]Token.Id{.Invalid}); - testTokenize("0x0._p0", &[_]Token.Id{.Invalid}); - testTokenize("0x0.0_p0", &[_]Token.Id{.Invalid}); - testTokenize("0x0._0p0", &[_]Token.Id{.Invalid}); - testTokenize("0x0.0_p0", &[_]Token.Id{.Invalid}); - testTokenize("0x0.0p_0", &[_]Token.Id{.Invalid}); - testTokenize("0x0.0p+_0", &[_]Token.Id{.Invalid}); - testTokenize("0x0.0p-_0", &[_]Token.Id{.Invalid}); - testTokenize("0x0.0p0_", &[_]Token.Id{.Invalid}); + testTokenize("0x0_p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0_.p0", &[_]Token.Id{ .Invalid, .Period, .Identifier }); + testTokenize("0x0._p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0_p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0._0p0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p+_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p-_0", &[_]Token.Id{ .Invalid, .Identifier }); + testTokenize("0x0.0p0_", &[_]Token.Id{ .Invalid, .Eof }); } fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) void { diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index e3d13b43db..63dc67a6fb 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -1312,15 +1312,15 @@ pub const Builder = struct { var rest: []const u8 = undefined; if (int_token.len >= 3 and int_token[0] == '0') { rest = int_token[2..]; - base = switch (int_token[1]) { - 'b' => 2, - 'o' => 8, - 'x' => 16, + switch (int_token[1]) { + 'b' => base = 2, + 'o' => base = 8, + 'x' => base = 16, else => { base = 10; rest = int_token; }, - }; + } } else { base = 10; rest = int_token; From 0cd953d40ea0f6934a0900f7ad8593e5deaf6efd Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 10:00:46 +0100 Subject: [PATCH 77/79] ir: Prevent crash when slicing hardcoded pointer Closes #4780 --- src/ir.cpp | 2 +- test/stage1/behavior/slice.zig | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/ir.cpp b/src/ir.cpp index b64128bef9..f0f0930762 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12819,7 +12819,7 @@ static IrInstGen *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInst* sourc result->value->type = wanted_type; return result; } - } else { + } else if (array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { ZigValue *pointee = const_ptr_pointee(ira, ira->codegen, array_ptr_val, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_inst_gen; diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index f7d6037a1f..e357ad2f0f 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -285,3 +285,17 @@ test "slice syntax resulting in pointer-to-array" { S.doTheTest(); comptime S.doTheTest(); } + +test "slice of hardcoded address to pointer" { + const S = struct { + fn doTheTest() void { + const pointer = @intToPtr([*]u8, 0x04)[0..2]; + comptime expect(@TypeOf(pointer) == *[2]u8); + const slice: []const u8 = pointer; + expect(@ptrToInt(slice.ptr) == 4); + expect(slice.len == 2); + } + }; + + S.doTheTest(); +} From e643b414e4aa8bcd02dfa0a9415a87cbfa77666d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 23 Mar 2020 11:33:48 -0400 Subject: [PATCH 78/79] zig cc: recognize .S and .C as source file extensions --- src/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index b47e532d9b..1dcaa34a95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -612,10 +612,12 @@ static int main0(int argc, char **argv) { case Stage2ClangArgPositional: { Buf *arg_buf = buf_create_from_str(it.only_arg); if (buf_ends_with_str(arg_buf, ".c") || + buf_ends_with_str(arg_buf, ".C") || buf_ends_with_str(arg_buf, ".cc") || buf_ends_with_str(arg_buf, ".cpp") || buf_ends_with_str(arg_buf, ".cxx") || - buf_ends_with_str(arg_buf, ".s")) + buf_ends_with_str(arg_buf, ".s") || + buf_ends_with_str(arg_buf, ".S")) { CFile *c_file = heap::c_allocator.create(); c_file->source_path = it.only_arg; From dc44fe053c609f389e375f6857f96b6bb3794897 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 23 Mar 2020 12:39:18 -0400 Subject: [PATCH 79/79] zig cc: detect dynamic linker argument --- src/main.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 1dcaa34a95..33ba54c7f3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -749,6 +749,16 @@ static int main0(int argc, char **argv) { } Buf *rpath = linker_args.at(i); rpath_list.append(buf_ptr(rpath)); + } else if (buf_eql_str(arg, "-I") || + buf_eql_str(arg, "--dynamic-linker") || + buf_eql_str(arg, "-dynamic-linker")) + { + i += 1; + if (i >= linker_args.length) { + fprintf(stderr, "expected linker arg after '%s'\n", buf_ptr(arg)); + return EXIT_FAILURE; + } + dynamic_linker = buf_ptr(linker_args.at(i)); } else { fprintf(stderr, "warning: unsupported linker arg: %s\n", buf_ptr(arg)); }