diff --git a/doc/langref.html.in b/doc/langref.html.in
index 50807377cd..dee95cf773 100644
--- a/doc/langref.html.in
+++ b/doc/langref.html.in
@@ -1422,7 +1422,8 @@ fn foo() i32 {
{#header_open|Thread Local Variables#}
A variable may be specified to be a thread-local variable using the
- {#syntax#}threadlocal{#endsyntax#} keyword:
+ {#syntax#}threadlocal{#endsyntax#} keyword,
+ which makes each thread work with a separate instance of the variable:
{#code_begin|test|test_thread_local_variables#}
const std = @import("std");
const assert = std.debug.assert;
@@ -4278,7 +4279,7 @@ const expectError = std.testing.expectError;
fn isFieldOptional(comptime T: type, field_index: usize) !bool {
const fields = @typeInfo(T).Struct.fields;
return switch (field_index) {
- // This prong is analyzed `fields.len - 1` times with `idx` being an
+ // This prong is analyzed `fields.len - 1` times with `idx` being a
// unique comptime-known value each time.
inline 0...fields.len - 1 => |idx| @typeInfo(fields[idx].type) == .Optional,
else => return error.IndexOutOfBounds,
@@ -4667,6 +4668,29 @@ test "for basics" {
sum2 += @intCast(i32, i);
}
try expect(sum2 == 10);
+
+ // To iterate over consecutive integers, use the range syntax.
+ // Unbounded range is always a compile error.
+ var sum3 : usize = 0;
+ for (0..5) |i| {
+ sum3 += i;
+ }
+ try expect(sum3 == 10);
+}
+
+test "multi object for" {
+ const items = [_]usize{ 1, 2, 3 };
+ const items2 = [_]usize{ 4, 5, 6 };
+ var count: usize = 0;
+
+ // Iterate over multiple objects.
+ // All lengths must be equal at the start of the loop, otherwise detectable
+ // illegal behavior occurs.
+ for (items, items2) |i, j| {
+ count += i + j;
+ }
+
+ try expect(count == 21);
}
test "for reference" {
@@ -4710,8 +4734,8 @@ const expect = std.testing.expect;
test "nested break" {
var count: usize = 0;
- outer: for ([_]i32{ 1, 2, 3, 4, 5 }) |_| {
- for ([_]i32{ 1, 2, 3, 4, 5 }) |_| {
+ outer: for (1..6) |_| {
+ for (1..6) |_| {
count += 1;
break :outer;
}
@@ -4721,8 +4745,8 @@ test "nested break" {
test "nested continue" {
var count: usize = 0;
- outer: for ([_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }) |_| {
- for ([_]i32{ 1, 2, 3, 4, 5 }) |_| {
+ outer: for (1..9) |_| {
+ for (1..6) |_| {
count += 1;
continue :outer;
}
@@ -8017,7 +8041,7 @@ pub const CallModifier = enum {
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.
{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.
- This function counts the number of most-significant (leading in a big-Endian sense) zeroes in an integer.
+ Counts the number of most-significant (leading in a big-endian sense) zeroes in an integer - "count leading zeroes".
If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer,
@@ -8167,7 +8191,7 @@ test "main" {
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type or an integer vector type.
{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.
- This function counts the number of least-significant (trailing in a big-Endian sense) zeroes in an integer.
+ Counts the number of least-significant (trailing in a big-endian sense) zeroes in an integer - "count trailing zeroes".
If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer,
@@ -8553,16 +8577,27 @@ test "@hasDecl" {
- {#syntax#}@import("std"){#endsyntax#} - Zig Standard Library
- - {#syntax#}@import("builtin"){#endsyntax#} - Target-specific information.
+
- {#syntax#}@import("builtin"){#endsyntax#} - Target-specific information
The command
zig build-exe --show-builtin outputs the source to stdout for reference.
- - {#syntax#}@import("root"){#endsyntax#} - Points to the root source file.
- This is usually
src/main.zig but it depends on what file is chosen to be built.
+ - {#syntax#}@import("root"){#endsyntax#} - Root source file
+ This is usually
src/main.zig but depends on what file is built.
{#see_also|Compile Variables|@embedFile#}
{#header_close#}
+ {#header_open|@inComptime#}
+ {#syntax#}@inComptime() bool{#endsyntax#}
+
+ Returns whether the builtin was run in a {#syntax#}comptime{#endsyntax#} context. The result is a compile-time constant.
+
+
+ This can be used to provide alternative, comptime-friendly implementations of functions. It should not be used, for instance, to exclude certain functions from being evaluated at comptime.
+
+ {#see_also|comptime#}
+ {#header_close#}
+
{#header_open|@intCast#}
{#syntax#}@intCast(comptime DestType: type, int: anytype) DestType{#endsyntax#}
@@ -8780,7 +8815,9 @@ test "@wasmMemoryGrow" {
{#syntax#}@popCount(operand: anytype) anytype{#endsyntax#}
{#syntax#}@TypeOf(operand){#endsyntax#} must be an integer type.
{#syntax#}operand{#endsyntax#} may be an {#link|integer|Integers#} or {#link|vector|Vectors#}.
- Counts the number of bits set in an integer.
+
+ Counts the number of bits set in an integer - "population count".
+
If {#syntax#}operand{#endsyntax#} is a {#link|comptime#}-known integer,
the return type is {#syntax#}comptime_int{#endsyntax#}.
@@ -8812,6 +8849,8 @@ test "@wasmMemoryGrow" {
pub const PrefetchOptions = struct {
/// Whether the prefetch should prepare for a read or a write.
rw: Rw = .read,
+ /// The data's locality in an inclusive range from 0 to 3.
+ ///
/// 0 means no temporal locality. That is, the data can be immediately
/// dropped from the cache after it is accessed.
///
@@ -8821,12 +8860,12 @@ pub const PrefetchOptions = struct {
/// The cache that the prefetch should be preformed on.
cache: Cache = .data,
- pub const Rw = enum {
+ pub const Rw = enum(u1) {
read,
write,
};
- pub const Cache = enum {
+ pub const Cache = enum(u1) {
instruction,
data,
};
@@ -10948,7 +10987,7 @@ pub const MAKELOCAL = @compileError("unable to translate C expr: unexpected toke
{#syntax#}[*c]T{#endsyntax#} - C pointer.
- - Supports all the syntax of the other two pointer types.
+ - Supports all the syntax of the other two pointer types ({#syntax#}*T{#endsyntax#}) and ({#syntax#}[*]T{#endsyntax#}).
- Coerces to other pointer types, as well as {#link|Optional Pointers#}.
When a C pointer is coerced to a non-optional pointer, safety-checked
{#link|Undefined Behavior#} occurs if the address is 0.
@@ -11966,6 +12005,17 @@ fn readU32Be() u32 {}
+
+
+ {#syntax#}noinline{#endsyntax#}
+ |
+
+ {#syntax#}noinline{#endsyntax#} disallows function to be inlined in all call sites.
+
+ - See also {#link|Functions#}
+
+ |
+
{#syntax#}nosuspend{#endsyntax#}
diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig
index 3b67f4b24c..cae779a306 100644
--- a/lib/std/Build/Cache.zig
+++ b/lib/std/Build/Cache.zig
@@ -184,7 +184,7 @@ pub const File = struct {
pub const HashHelper = struct {
hasher: Hasher = hasher_init,
- /// Record a slice of bytes as an dependency of the process being cached
+ /// Record a slice of bytes as a dependency of the process being cached.
pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
hh.hasher.update(mem.asBytes(&bytes.len));
hh.hasher.update(bytes);
diff --git a/lib/std/RingBuffer.zig b/lib/std/RingBuffer.zig
index 857775b5a0..080e6f54d3 100644
--- a/lib/std/RingBuffer.zig
+++ b/lib/std/RingBuffer.zig
@@ -1,7 +1,7 @@
//! This ring buffer stores read and write indices while being able to utilise
//! the full backing slice by incrementing the indices modulo twice the slice's
//! length and reducing indices modulo the slice's length on slice access. This
-//! means that whether the ring buffer if full or empty can be distinguished by
+//! means that whether the ring buffer is full or empty can be distinguished by
//! looking at the difference between the read and write indices without adding
//! an extra boolean flag or having to reserve a slot in the buffer.
//!
diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig
index b010ce8662..b0bb3047cb 100644
--- a/lib/std/Uri.zig
+++ b/lib/std/Uri.zig
@@ -1,4 +1,4 @@
-//! Implements URI parsing roughly adhering to .
+//! Uniform Resource Identifier (URI) parsing roughly adhering to .
//! Does not do perfect grammar and character class checking, but should be robust against URIs in the wild.
const Uri = @This();
diff --git a/lib/std/array_list.zig b/lib/std/array_list.zig
index 205649ae4d..1695e2bd87 100644
--- a/lib/std/array_list.zig
+++ b/lib/std/array_list.zig
@@ -221,6 +221,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
/// Asserts the array has at least one item.
/// Invalidates pointers to end of list.
/// This operation is O(N).
+ /// This preserves item order. Use `swapRemove` if order preservation is not important.
pub fn orderedRemove(self: *Self, i: usize) T {
const newlen = self.items.len - 1;
if (newlen == i) return self.pop();
@@ -235,6 +236,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
/// Removes the element at the specified index and returns it.
/// The empty slot is filled from the end of the list.
/// This operation is O(1).
+ /// This may not preserve item order. Use `orderedRemove` if you need to preserve order.
pub fn swapRemove(self: *Self, i: usize) T {
if (self.items.len - 1 == i) return self.pop();
diff --git a/lib/std/bit_set.zig b/lib/std/bit_set.zig
index d8f9b7f90e..292d099303 100644
--- a/lib/std/bit_set.zig
+++ b/lib/std/bit_set.zig
@@ -35,9 +35,10 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
/// Returns the optimal static bit set type for the specified number
-/// of elements. The returned type will perform no allocations,
+/// of elements: either `IntegerBitSet` or `ArrayBitSet`,
+/// both of which fulfill the same interface.
+/// The returned type will perform no allocations,
/// can be copied by value, and does not require deinitialization.
-/// Both possible implementations fulfill the same interface.
pub fn StaticBitSet(comptime size: usize) type {
if (size <= @bitSizeOf(usize)) {
return IntegerBitSet(size);
diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig
index 1d28e69d61..cfe22099cb 100644
--- a/lib/std/builtin.zig
+++ b/lib/std/builtin.zig
@@ -144,22 +144,47 @@ pub const Mode = OptimizeMode;
/// This data structure is used by the Zig language code generation and
/// therefore must be kept in sync with the compiler implementation.
pub const CallingConvention = enum {
+ /// This is the default Zig calling convention used when not using `export` on `fn`
+ /// and no other calling convention is specified.
Unspecified,
+ /// Matches the C ABI for the target.
+ /// This is the default calling convention when using `export` on `fn`
+ /// and no other calling convention is specified.
C,
+ /// This makes a function not have any function prologue or epilogue,
+ /// making the function itself uncallable in regular Zig code.
+ /// This can be useful when integrating with assembly.
Naked,
+ /// Functions with this calling convention are called asynchronously,
+ /// as if called as `async function()`.
Async,
+ /// Functions with this calling convention are inlined at all call sites.
Inline,
+ /// x86-only.
Interrupt,
Signal,
+ /// x86-only.
Stdcall,
+ /// x86-only.
Fastcall,
+ /// x86-only.
Vectorcall,
+ /// x86-only.
Thiscall,
+ /// ARM Procedure Call Standard (obsolete)
+ /// ARM-only.
APCS,
+ /// ARM Architecture Procedure Call Standard (current standard)
+ /// ARM-only.
AAPCS,
+ /// ARM Architecture Procedure Call Standard Vector Floating-Point
+ /// ARM-only.
AAPCSVFP,
+ /// x86-64-only.
SysV,
+ /// x86-64-only.
Win64,
+ /// AMD GPU, NVPTX, or SPIR-V kernel
Kernel,
};
@@ -716,6 +741,8 @@ pub const VaList = switch (builtin.cpu.arch) {
pub const PrefetchOptions = struct {
/// Whether the prefetch should prepare for a read or a write.
rw: Rw = .read,
+ /// The data's locality in an inclusive range from 0 to 3.
+ ///
/// 0 means no temporal locality. That is, the data can be immediately
/// dropped from the cache after it is accessed.
///
diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig
index a46337b721..19baee92d3 100644
--- a/lib/std/c/darwin.zig
+++ b/lib/std/c/darwin.zig
@@ -3846,3 +3846,11 @@ pub extern "c" fn os_signpost_interval_begin(log: os_log_t, signpos: os_signpost
pub extern "c" fn os_signpost_interval_end(log: os_log_t, signpos: os_signpost_id_t, func: [*]const u8, ...) void;
pub extern "c" fn os_signpost_id_make_with_pointer(log: os_log_t, ptr: ?*anyopaque) os_signpost_id_t;
pub extern "c" fn os_signpost_enabled(log: os_log_t) bool;
+
+pub extern "c" fn proc_listpids(tpe: u32, tinfo: u32, buffer: ?*anyopaque, buffersize: c_int) c_int;
+pub extern "c" fn proc_listallpids(buffer: ?*anyopaque, buffersize: c_int) c_int;
+pub extern "c" fn proc_listpgrppids(pgrpid: pid_t, buffer: ?*anyopaque, buffersize: c_int) c_int;
+pub extern "c" fn proc_listchildpids(ppid: pid_t, buffer: ?*anyopaque, buffersize: c_int) c_int;
+pub extern "c" fn proc_pidinfo(pid: c_int, flavor: c_int, arg: u64, buffer: ?*anyopaque, buffersize: c_int) c_int;
+pub extern "c" fn proc_name(pid: c_int, buffer: ?*anyopaque, buffersize: u32) c_int;
+pub extern "c" fn proc_pidpath(pid: c_int, buffer: ?*anyopaque, buffersize: u32) c_int;
diff --git a/lib/std/c/dragonfly.zig b/lib/std/c/dragonfly.zig
index 900e1165f0..c7561d558d 100644
--- a/lib/std/c/dragonfly.zig
+++ b/lib/std/c/dragonfly.zig
@@ -1143,3 +1143,20 @@ pub const POLL = struct {
pub const HUP = 0x0010;
pub const NVAL = 0x0020;
};
+
+pub const SIGEV = struct {
+ pub const NONE = 0;
+ pub const SIGNAL = 1;
+ pub const THREAD = 2;
+};
+
+pub const sigevent = extern struct {
+ sigev_notify: c_int,
+ __sigev_u: extern union {
+ __sigev_signo: c_int,
+ __sigev_notify_kqueue: c_int,
+ __sigev_notify_attributes: ?*pthread_attr_t,
+ },
+ sigev_value: sigval,
+ sigev_notify_function: ?*const fn (sigval) callconv(.C) void,
+};
diff --git a/lib/std/c/freebsd.zig b/lib/std/c/freebsd.zig
index 534b6bc592..d3fa8f51c7 100644
--- a/lib/std/c/freebsd.zig
+++ b/lib/std/c/freebsd.zig
@@ -29,6 +29,8 @@ pub const CPU_WHICH_TIDPID: cpuwhich_t = 8;
extern "c" fn __error() *c_int;
pub const _errno = __error;
+pub extern "c" var malloc_options: [*:0]const u8;
+
pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize;
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int;
pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
@@ -42,6 +44,7 @@ pub extern "c" fn arc4random_buf(buf: [*]u8, len: usize) void;
pub extern "c" fn posix_memalign(memptr: *?*anyopaque, alignment: usize, size: usize) c_int;
pub extern "c" fn malloc_usable_size(?*const anyopaque) usize;
+pub extern "c" fn reallocf(?*anyopaque, usize) ?*anyopaque;
pub extern "c" fn getpid() pid_t;
@@ -50,6 +53,9 @@ pub extern "c" fn kinfo_getvmmap(pid: pid_t, cntp: *c_int) ?[*]kinfo_vmentry;
pub extern "c" fn cpuset_getaffinity(level: cpulevel_t, which: cpuwhich_t, id: id_t, setsize: usize, mask: *cpuset_t) c_int;
pub extern "c" fn cpuset_setaffinity(level: cpulevel_t, which: cpuwhich_t, id: id_t, setsize: usize, mask: *const cpuset_t) c_int;
+pub extern "c" fn sched_getaffinity(pid: pid_t, cpusetsz: usize, cpuset: *cpuset_t) c_int;
+pub extern "c" fn sched_setaffinity(pid: pid_t, cpusetsz: usize, cpuset: *const cpuset_t) c_int;
+pub extern "c" fn sched_getcpu() c_int;
pub const sf_hdtr = extern struct {
headers: [*]const iovec_const,
@@ -1102,6 +1108,11 @@ pub const DT = struct {
pub const WHT = 14;
};
+pub const accept_filter = extern struct {
+ af_name: [16]u8,
+ af_args: [240]u8,
+};
+
/// add event to kq (implies enable)
pub const EV_ADD = 0x0001;
@@ -1383,15 +1394,47 @@ pub const mcontext_t = switch (builtin.cpu.arch) {
rflags: u64,
rsp: u64,
ss: u64,
- len: u64,
- fpformat: u64,
- ownedfp: u64,
- fpstate: [64]u64 align(16),
+ len: c_long,
+ fpformat: c_long,
+ ownedfp: c_long,
+ fpstate: [64]c_long align(16),
fsbase: u64,
gsbase: u64,
xfpustate: u64,
xfpustate_len: u64,
- spare: [4]u64,
+ spare: [4]c_long,
+ },
+ .x86 => extern struct {
+ onstack: u32,
+ gs: u32,
+ fs: u32,
+ es: u32,
+ ds: u32,
+ edi: u32,
+ esi: u32,
+ ebp: u32,
+ isp: u32,
+ ebx: u32,
+ edx: u32,
+ ecx: u32,
+ eax: u32,
+ trapno: u32,
+ err: u32,
+ eip: u32,
+ cs: u32,
+ eflags: u32,
+ esp: u32,
+ ss: u32,
+ len: c_int,
+ fpformat: c_int,
+ ownedfp: c_int,
+ flags: u32,
+ fpstate: [128]c_int align(16),
+ fsbase: u32,
+ gsbase: u32,
+ xpustate: u32,
+ xpustate_len: u32,
+ spare2: [4]c_int,
},
.aarch64 => extern struct {
gpregs: extern struct {
@@ -2205,3 +2248,46 @@ pub const shm_largeconf = extern struct {
pub extern "c" fn shm_create_largepage(path: [*:0]const u8, flags: c_int, psind: c_int, alloc_policy: c_int, mode: mode_t) c_int;
pub extern "c" fn elf_aux_info(aux: c_int, buf: ?*anyopaque, buflen: c_int) c_int;
+
+pub const lwpid = i32;
+
+pub const SIGEV = struct {
+ pub const NONE = 0;
+ pub const SIGNAL = 1;
+ pub const THREAD = 2;
+ pub const KEVENT = 3;
+ pub const THREAD_ID = 4;
+};
+
+pub const sigevent = extern struct {
+ sigev_notify: c_int,
+ sigev_signo: c_int,
+ sigev_value: sigval,
+ _sigev_un: extern union {
+ _threadid: lwpid,
+ _sigev_thread: extern struct {
+ _function: ?*const fn (sigval) callconv(.C) void,
+ _attribute: ?**pthread_attr_t,
+ },
+ _kevent_flags: c_ushort,
+ __spare__: [8]c_long,
+ },
+};
+
+pub const MIN = struct {
+ pub const INCORE = 0x1;
+ pub const REFERENCED = 0x2;
+ pub const MODIFIED = 0x4;
+ pub const REFERENCED_OTHER = 0x8;
+ pub const MODIFIED_OTHER = 0x10;
+ pub const SUPER = 0x60;
+ pub fn PSIND(i: u32) u32 {
+ return (i << 5) & SUPER;
+ }
+};
+
+pub extern "c" fn mincore(
+ addr: *align(std.mem.page_size) const anyopaque,
+ length: usize,
+ vec: [*]u8,
+) c_int;
diff --git a/lib/std/c/haiku.zig b/lib/std/c/haiku.zig
index 9c4f8460de..9b693a59c2 100644
--- a/lib/std/c/haiku.zig
+++ b/lib/std/c/haiku.zig
@@ -5,11 +5,15 @@ const maxInt = std.math.maxInt;
const iovec = std.os.iovec;
const iovec_const = std.os.iovec_const;
+const status_t = i32;
+
extern "c" fn _errnop() *c_int;
pub const _errno = _errnop;
-pub extern "c" fn find_directory(which: c_int, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) u64;
+pub extern "c" fn find_directory(which: c_int, volume: i32, createIt: bool, path_ptr: [*]u8, length: i32) status_t;
+
+pub extern "c" fn find_path(codePointer: *const u8, baseDirectory: c_int, subPath: [*:0]const u8, pathBuffer: [*:0]u8, bufferSize: usize) status_t;
pub extern "c" fn find_thread(thread_name: ?*anyopaque) i32;
@@ -1038,3 +1042,22 @@ pub const termios = extern struct {
};
pub const MSG_NOSIGNAL = 0x0800;
+
+pub const SIGEV = struct {
+ pub const NONE = 0;
+ pub const SIGNAL = 1;
+ pub const THREAD = 2;
+};
+
+pub const sigval = extern union {
+ int: c_int,
+ ptr: ?*anyopaque,
+};
+
+pub const sigevent = extern struct {
+ sigev_notify: c_int,
+ sigev_signo: c_int,
+ sigev_value: sigval,
+ sigev_notify_function: ?*const fn (sigval) callconv(.C) void,
+ sigev_notify_attributes: ?*pthread_attr_t,
+};
diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig
index 41524885f7..f70549775c 100644
--- a/lib/std/c/netbsd.zig
+++ b/lib/std/c/netbsd.zig
@@ -1633,3 +1633,22 @@ pub const POLL = struct {
pub const HUP = 0x0010;
pub const NVAL = 0x0020;
};
+
+pub const SIGEV = struct {
+ pub const NONE = 0;
+ pub const SIGNAL = 1;
+ pub const THREAD = 2;
+};
+
+pub const sigval = extern union {
+ int: c_int,
+ ptr: ?*anyopaque,
+};
+
+pub const sigevent = extern struct {
+ sigev_notify: c_int,
+ sigev_signo: c_int,
+ sigev_value: sigval,
+ sigev_notify_function: ?*const fn (sigval) callconv(.C) void,
+ sigev_notify_attributes: ?*pthread_attr_t,
+};
diff --git a/lib/std/c/solaris.zig b/lib/std/c/solaris.zig
index b1b789c77b..c2c38f46ce 100644
--- a/lib/std/c/solaris.zig
+++ b/lib/std/c/solaris.zig
@@ -1927,3 +1927,22 @@ pub fn IOW(io_type: u8, nr: u8, comptime IOT: type) i32 {
pub fn IOWR(io_type: u8, nr: u8, comptime IOT: type) i32 {
return ioImpl(.read_write, io_type, nr, IOT);
}
+
+pub const SIGEV = struct {
+ pub const NONE = 0;
+ pub const SIGNAL = 1;
+ pub const THREAD = 2;
+};
+
+pub const sigval = extern union {
+ int: c_int,
+ ptr: ?*anyopaque,
+};
+
+pub const sigevent = extern struct {
+ sigev_notify: c_int,
+ sigev_signo: c_int,
+ sigev_value: sigval,
+ sigev_notify_function: ?*const fn (sigval) callconv(.C) void,
+ sigev_notify_attributes: ?*pthread_attr_t,
+};
diff --git a/lib/std/compress/zstandard.zig b/lib/std/compress/zstandard.zig
index f59de87e6b..1e8a0fc86f 100644
--- a/lib/std/compress/zstandard.zig
+++ b/lib/std/compress/zstandard.zig
@@ -10,7 +10,7 @@ pub const decompress = @import("zstandard/decompress.zig");
pub const DecompressStreamOptions = struct {
verify_checksum: bool = true,
- window_size_max: usize = 1 << 23, // 8MiB default maximum window size,
+ window_size_max: usize = 1 << 23, // 8MiB default maximum window size
};
pub fn DecompressStream(
diff --git a/lib/std/compress/zstandard/decode/fse.zig b/lib/std/compress/zstandard/decode/fse.zig
index 41a34d0fc1..741fd81ccc 100644
--- a/lib/std/compress/zstandard/decode/fse.zig
+++ b/lib/std/compress/zstandard/decode/fse.zig
@@ -21,7 +21,7 @@ pub fn decodeFseTable(
var accumulated_probability: u16 = 0;
while (accumulated_probability < total_probability) {
- // WARNING: The RFC in poorly worded, and would suggest std.math.log2_int_ceil is correct here,
+ // WARNING: The RFC is poorly worded, and would suggest std.math.log2_int_ceil is correct here,
// but power of two (remaining probabilities + 1) need max bits set to 1 more.
const max_bits = std.math.log2_int(u16, total_probability - accumulated_probability + 1) + 1;
const small = try bit_reader.readBitsNoEof(u16, max_bits - 1);
diff --git a/lib/std/crypto/sha2.zig b/lib/std/crypto/sha2.zig
index 07bda89585..ad99079852 100644
--- a/lib/std/crypto/sha2.zig
+++ b/lib/std/crypto/sha2.zig
@@ -71,12 +71,6 @@ const Sha256Params = Sha2Params32{
const v4u32 = @Vector(4, u32);
-// TODO: Remove once https://github.com/ziglang/zig/issues/868 is resolved.
-fn isComptime() bool {
- var a: u8 = 0;
- return @typeInfo(@TypeOf(.{a})).Struct.fields[0].is_comptime;
-}
-
/// SHA-224
pub const Sha224 = Sha2x32(Sha224Params);
@@ -203,7 +197,7 @@ fn Sha2x32(comptime params: Sha2Params32) type {
s[i] = mem.readIntBig(u32, mem.asBytes(elem));
}
- if (!isComptime()) {
+ if (!@inComptime()) {
switch (builtin.cpu.arch) {
.aarch64 => if (builtin.zig_backend != .stage2_c and comptime std.Target.aarch64.featureSetHas(builtin.cpu.features, .sha2)) {
var x: v4u32 = d.s[0..4].*;
diff --git a/lib/std/debug.zig b/lib/std/debug.zig
index e093fa5dc8..c965dd6436 100644
--- a/lib/std/debug.zig
+++ b/lib/std/debug.zig
@@ -651,6 +651,8 @@ pub fn writeCurrentStackTraceWindows(
}
}
+/// Provides simple functionality for manipulating the terminal in some way,
+/// for debugging purposes, such as coloring text, etc.
pub const TTY = struct {
pub const Color = enum {
Red,
diff --git a/lib/std/elf.zig b/lib/std/elf.zig
index 2eb89e810a..e2cad5640e 100644
--- a/lib/std/elf.zig
+++ b/lib/std/elf.zig
@@ -221,75 +221,138 @@ pub const DT_IA_64_NUM = 1;
pub const DT_NIOS2_GP = 0x70000002;
+/// Program header table entry unused
pub const PT_NULL = 0;
+/// Loadable program segment
pub const PT_LOAD = 1;
+/// Dynamic linking information
pub const PT_DYNAMIC = 2;
+/// Program interpreter
pub const PT_INTERP = 3;
+/// Auxiliary information
pub const PT_NOTE = 4;
+/// Reserved
pub const PT_SHLIB = 5;
+/// Entry for header table itself
pub const PT_PHDR = 6;
+/// Thread-local storage segment
pub const PT_TLS = 7;
+/// Number of defined types
pub const PT_NUM = 8;
+/// Start of OS-specific
pub const PT_LOOS = 0x60000000;
+/// GCC .eh_frame_hdr segment
pub const PT_GNU_EH_FRAME = 0x6474e550;
+/// Indicates stack executability
pub const PT_GNU_STACK = 0x6474e551;
+/// Read-only after relocation
pub const PT_GNU_RELRO = 0x6474e552;
pub const PT_LOSUNW = 0x6ffffffa;
+/// Sun specific segment
pub const PT_SUNWBSS = 0x6ffffffa;
+/// Stack segment
pub const PT_SUNWSTACK = 0x6ffffffb;
pub const PT_HISUNW = 0x6fffffff;
+/// End of OS-specific
pub const PT_HIOS = 0x6fffffff;
+/// Start of processor-specific
pub const PT_LOPROC = 0x70000000;
+/// End of processor-specific
pub const PT_HIPROC = 0x7fffffff;
+/// Section header table entry unused
pub const SHT_NULL = 0;
+/// Program data
pub const SHT_PROGBITS = 1;
+/// Symbol table
pub const SHT_SYMTAB = 2;
+/// String table
pub const SHT_STRTAB = 3;
+/// Relocation entries with addends
pub const SHT_RELA = 4;
+/// Symbol hash table
pub const SHT_HASH = 5;
+/// Dynamic linking information
pub const SHT_DYNAMIC = 6;
+/// Notes
pub const SHT_NOTE = 7;
+/// Program space with no data (bss)
pub const SHT_NOBITS = 8;
+/// Relocation entries, no addends
pub const SHT_REL = 9;
+/// Reserved
pub const SHT_SHLIB = 10;
+/// Dynamic linker symbol table
pub const SHT_DYNSYM = 11;
+/// Array of constructors
pub const SHT_INIT_ARRAY = 14;
+/// Array of destructors
pub const SHT_FINI_ARRAY = 15;
+/// Array of pre-constructors
pub const SHT_PREINIT_ARRAY = 16;
+/// Section group
pub const SHT_GROUP = 17;
+/// Extended section indices
pub const SHT_SYMTAB_SHNDX = 18;
+/// Start of OS-specific
pub const SHT_LOOS = 0x60000000;
+/// End of OS-specific
pub const SHT_HIOS = 0x6fffffff;
+/// Start of processor-specific
pub const SHT_LOPROC = 0x70000000;
+/// End of processor-specific
pub const SHT_HIPROC = 0x7fffffff;
+/// Start of application-specific
pub const SHT_LOUSER = 0x80000000;
+/// End of application-specific
pub const SHT_HIUSER = 0xffffffff;
+/// Local symbol
pub const STB_LOCAL = 0;
+/// Global symbol
pub const STB_GLOBAL = 1;
+/// Weak symbol
pub const STB_WEAK = 2;
+/// Number of defined types
pub const STB_NUM = 3;
+/// Start of OS-specific
pub const STB_LOOS = 10;
+/// Unique symbol
pub const STB_GNU_UNIQUE = 10;
+/// End of OS-specific
pub const STB_HIOS = 12;
+/// Start of processor-specific
pub const STB_LOPROC = 13;
+/// End of processor-specific
pub const STB_HIPROC = 15;
pub const STB_MIPS_SPLIT_COMMON = 13;
+/// Symbol type is unspecified
pub const STT_NOTYPE = 0;
+/// Symbol is a data object
pub const STT_OBJECT = 1;
+/// Symbol is a code object
pub const STT_FUNC = 2;
+/// Symbol associated with a section
pub const STT_SECTION = 3;
+/// Symbol's name is file name
pub const STT_FILE = 4;
+/// Symbol is a common data object
pub const STT_COMMON = 5;
+/// Symbol is thread-local data object
pub const STT_TLS = 6;
+/// Number of defined types
pub const STT_NUM = 7;
+/// Start of OS-specific
pub const STT_LOOS = 10;
+/// Symbol is indirect code object
pub const STT_GNU_IFUNC = 10;
+/// End of OS-specific
pub const STT_HIOS = 12;
+/// Start of processor-specific
pub const STT_LOPROC = 13;
+/// End of processor-specific
pub const STT_HIPROC = 15;
pub const STT_SPARC_REGISTER = 13;
@@ -656,6 +719,13 @@ pub const Elf32_Sym = extern struct {
st_info: u8,
st_other: u8,
st_shndx: Elf32_Section,
+
+ pub inline fn st_type(self: @This()) u4 {
+ return @truncate(u4, self.st_info);
+ }
+ pub inline fn st_bind(self: @This()) u4 {
+ return @truncate(u4, self.st_info >> 4);
+ }
};
pub const Elf64_Sym = extern struct {
st_name: Elf64_Word,
@@ -664,6 +734,13 @@ pub const Elf64_Sym = extern struct {
st_shndx: Elf64_Section,
st_value: Elf64_Addr,
st_size: Elf64_Xword,
+
+ pub inline fn st_type(self: @This()) u4 {
+ return @truncate(u4, self.st_info);
+ }
+ pub inline fn st_bind(self: @This()) u4 {
+ return @truncate(u4, self.st_info >> 4);
+ }
};
pub const Elf32_Syminfo = extern struct {
si_boundto: Elf32_Half,
@@ -681,7 +758,7 @@ pub const Elf32_Rel = extern struct {
return @truncate(u24, self.r_info >> 8);
}
pub inline fn r_type(self: @This()) u8 {
- return @truncate(u8, self.r_info & 0xff);
+ return @truncate(u8, self.r_info);
}
};
pub const Elf64_Rel = extern struct {
@@ -692,7 +769,7 @@ pub const Elf64_Rel = extern struct {
return @truncate(u32, self.r_info >> 32);
}
pub inline fn r_type(self: @This()) u32 {
- return @truncate(u32, self.r_info & 0xffffffff);
+ return @truncate(u32, self.r_info);
}
};
pub const Elf32_Rela = extern struct {
@@ -704,7 +781,7 @@ pub const Elf32_Rela = extern struct {
return @truncate(u24, self.r_info >> 8);
}
pub inline fn r_type(self: @This()) u8 {
- return @truncate(u8, self.r_info & 0xff);
+ return @truncate(u8, self.r_info);
}
};
pub const Elf64_Rela = extern struct {
@@ -716,7 +793,7 @@ pub const Elf64_Rela = extern struct {
return @truncate(u32, self.r_info >> 32);
}
pub inline fn r_type(self: @This()) u32 {
- return @truncate(u32, self.r_info & 0xffffffff);
+ return @truncate(u32, self.r_info);
}
};
pub const Elf32_Dyn = extern struct {
@@ -1630,14 +1707,20 @@ pub const PF_MASKOS = 0x0ff00000;
/// Bits for processor-specific semantics.
pub const PF_MASKPROC = 0xf0000000;
-// Special section indexes used in Elf{32,64}_Sym.
+/// Undefined section
pub const SHN_UNDEF = 0;
+/// Start of reserved indices
pub const SHN_LORESERVE = 0xff00;
+/// Start of processor-specific
pub const SHN_LOPROC = 0xff00;
+/// End of processor-specific
pub const SHN_HIPROC = 0xff1f;
pub const SHN_LIVEPATCH = 0xff20;
+/// Associated symbol is absolute
pub const SHN_ABS = 0xfff1;
+/// Associated symbol is common
pub const SHN_COMMON = 0xfff2;
+/// End of reserved indices
pub const SHN_HIRESERVE = 0xffff;
/// AMD x86-64 relocations.
diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig
index 3f697f8117..cf791df1a6 100644
--- a/lib/std/fmt.zig
+++ b/lib/std/fmt.zig
@@ -41,7 +41,7 @@ pub const FormatOptions = struct {
/// brackets, e.g. {[score]...} as opposed to the numeric index form which can be written e.g. {2...}
/// - *specifier* is a type-dependent formatting option that determines how a type should formatted (see below)
/// - *fill* is a single character which is used to pad the formatted text
-/// - *alignment* is one of the three characters `<`, `^` or `>`. they define if the text is *left*, *center*, or *right* aligned
+/// - *alignment* is one of the three characters `<`, `^`, or `>` to make the text left-, center-, or right-aligned, respectively
/// - *width* is the total width of the field in characters
/// - *precision* specifies how many decimals a formatted number should have
///
@@ -1428,8 +1428,7 @@ pub fn formatInt(
var a: MinInt = abs_value;
var index: usize = buf.len;
- // TODO isComptime here because of https://github.com/ziglang/zig/issues/13335.
- if (base == 10 and !isComptime()) {
+ if (base == 10) {
while (a >= 100) : (a = @divTrunc(a, 100)) {
index -= 2;
buf[index..][0..2].* = digits2(@intCast(usize, a % 100));
@@ -1469,12 +1468,6 @@ pub fn formatInt(
return formatBuf(buf[index..], options, writer);
}
-// TODO: Remove once https://github.com/ziglang/zig/issues/868 is resolved.
-fn isComptime() bool {
- var a: u8 = 0;
- return @typeInfo(@TypeOf(.{a})).Struct.fields[0].is_comptime;
-}
-
pub fn formatIntBuf(out_buf: []u8, value: anytype, base: u8, case: Case, options: FormatOptions) usize {
var fbs = std.io.fixedBufferStream(out_buf);
formatInt(value, base, case, options, fbs.writer()) catch unreachable;
diff --git a/lib/std/fs.zig b/lib/std/fs.zig
index b5e2d7ad63..290eb151f7 100644
--- a/lib/std/fs.zig
+++ b/lib/std/fs.zig
@@ -1236,6 +1236,7 @@ pub const Dir = struct {
.capable_io_mode = std.io.default_mode,
.intended_io_mode = flags.intended_io_mode,
};
+ errdefer file.close();
var io: w.IO_STATUS_BLOCK = undefined;
const range_off: w.LARGE_INTEGER = 0;
const range_len: w.LARGE_INTEGER = 1;
@@ -1396,6 +1397,7 @@ pub const Dir = struct {
.capable_io_mode = std.io.default_mode,
.intended_io_mode = flags.intended_io_mode,
};
+ errdefer file.close();
var io: w.IO_STATUS_BLOCK = undefined;
const range_off: w.LARGE_INTEGER = 0;
const range_len: w.LARGE_INTEGER = 1;
@@ -2210,7 +2212,7 @@ pub const Dir = struct {
var need_to_retry: bool = false;
parent_dir.deleteDir(name) catch |err| switch (err) {
error.FileNotFound => {},
- error.DirNotEmpty => need_to_retry = false,
+ error.DirNotEmpty => need_to_retry = true,
else => |e| return e,
};
@@ -2913,6 +2915,7 @@ pub const OpenSelfExeError = error{
/// On Windows, file paths cannot contain these characters:
/// '/', '*', '?', '"', '<', '>', '|'
BadPathName,
+ Overflow,
Unexpected,
} || os.OpenError || SelfExePathError || os.FlockError;
@@ -2991,7 +2994,15 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
// TODO could this slice from 0 to out_len instead?
return mem.sliceTo(out_buffer, 0);
},
- .openbsd, .haiku => {
+ .haiku => {
+ // The only possible issue when looking for the self image path is
+ // when the buffer is too short.
+ // TODO replace with proper constants
+ if (os.find_path(null, 1000, null, out_buffer.ptr, out_buffer.len) != 0)
+ return error.Overflow;
+ return mem.sliceTo(out_buffer, 0);
+ },
+ .openbsd => {
// OpenBSD doesn't support getting the path of a running process, so try to guess it
if (os.argv.len == 0)
return error.FileNotFound;
diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig
index 4d780b2ead..beb386f92c 100644
--- a/lib/std/fs/path.zig
+++ b/lib/std/fs/path.zig
@@ -1214,10 +1214,9 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons
try testing.expectEqualStrings(expected_output, result);
}
-/// Returns the extension of the file name (if any).
-/// This function will search for the file extension (separated by a `.`) and will return the text after the `.`.
-/// Files that end with `.`, or that start with `.` and have no other `.` in their name,
-/// are considered to have no extension.
+/// Searches for a file extension separated by a `.` and returns the string after that `.`.
+/// Files that end or start with `.` and have no other `.` in their name
+/// are considered to have no extension, in which case this returns "".
/// Examples:
/// - `"main.zig"` ⇒ `".zig"`
/// - `"src/main.zig"` ⇒ `".zig"`
diff --git a/lib/std/http.zig b/lib/std/http.zig
index 364cc4eeda..2f0a20de8d 100644
--- a/lib/std/http.zig
+++ b/lib/std/http.zig
@@ -275,4 +275,5 @@ test {
_ = Client;
_ = Method;
_ = Status;
+ _ = @import("http/test.zig");
}
diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig
index 4ff29a215a..cc01a181f0 100644
--- a/lib/std/http/Client.zig
+++ b/lib/std/http/Client.zig
@@ -645,7 +645,6 @@ pub const Request = struct {
if (req.response.parser.state.isContent()) break;
}
- req.response.headers = http.Headers{ .allocator = req.client.allocator, .owned = false };
try req.response.parse(req.response.parser.header_bytes.items);
if (req.response.status == .switching_protocols) {
@@ -765,7 +764,7 @@ pub const Request = struct {
}
if (has_trail) {
- req.response.headers = http.Headers{ .allocator = req.client.allocator, .owned = false };
+ req.response.headers.clearRetainingCapacity();
// The response headers before the trailers are already guaranteed to be valid, so they will always be parsed again and cannot return an error.
// This will *only* fail for a malformed trailer.
@@ -797,18 +796,18 @@ pub const Request = struct {
/// Write `bytes` to the server. The `transfer_encoding` request header determines how data will be sent.
pub fn write(req: *Request, bytes: []const u8) WriteError!usize {
- switch (req.headers.transfer_encoding) {
+ switch (req.transfer_encoding) {
.chunked => {
- try req.connection.data.conn.writer().print("{x}\r\n", .{bytes.len});
- try req.connection.data.conn.writeAll(bytes);
- try req.connection.data.conn.writeAll("\r\n");
+ try req.connection.data.buffered.writer().print("{x}\r\n", .{bytes.len});
+ try req.connection.data.buffered.writeAll(bytes);
+ try req.connection.data.buffered.writeAll("\r\n");
return bytes.len;
},
.content_length => |*len| {
if (len.* < bytes.len) return error.MessageTooLong;
- const amt = try req.connection.data.conn.write(bytes);
+ const amt = try req.connection.data.buffered.write(bytes);
len.* -= amt;
return amt;
},
@@ -828,7 +827,7 @@ pub const Request = struct {
/// Finish the body of a request. This notifies the server that you have no more data to send.
pub fn finish(req: *Request) FinishError!void {
switch (req.transfer_encoding) {
- .chunked => try req.connection.data.conn.writeAll("0\r\n\r\n"),
+ .chunked => try req.connection.data.buffered.writeAll("0\r\n\r\n"),
.content_length => |len| if (len != 0) return error.MessageNotCompleted,
.none => {},
}
@@ -1019,7 +1018,7 @@ pub fn request(client: *Client, method: http.Method, uri: Uri, headers: http.Hea
.status = undefined,
.reason = undefined,
.version = undefined,
- .headers = undefined,
+ .headers = http.Headers{ .allocator = client.allocator, .owned = false },
.parser = switch (options.header_strategy) {
.dynamic => |max| proto.HeadersParser.initDynamic(max),
.static => |buf| proto.HeadersParser.initStatic(buf),
diff --git a/lib/std/http/Headers.zig b/lib/std/http/Headers.zig
index e84a890862..0322c32481 100644
--- a/lib/std/http/Headers.zig
+++ b/lib/std/http/Headers.zig
@@ -68,17 +68,7 @@ pub const Headers = struct {
}
pub fn deinit(headers: *Headers) void {
- var it = headers.index.iterator();
- while (it.next()) |entry| {
- entry.value_ptr.deinit(headers.allocator);
-
- if (headers.owned) headers.allocator.free(entry.key_ptr.*);
- }
-
- for (headers.list.items) |entry| {
- if (headers.owned) headers.allocator.free(entry.value);
- }
-
+ headers.deallocateIndexListsAndFields();
headers.index.deinit(headers.allocator);
headers.list.deinit(headers.allocator);
@@ -255,6 +245,39 @@ pub const Headers = struct {
try out_stream.writeAll("\r\n");
}
+
+ /// Frees all `HeaderIndexList`s within `index`
+ /// Frees names and values of all fields if they are owned.
+ fn deallocateIndexListsAndFields(headers: *Headers) void {
+ var it = headers.index.iterator();
+ while (it.next()) |entry| {
+ entry.value_ptr.deinit(headers.allocator);
+
+ if (headers.owned) headers.allocator.free(entry.key_ptr.*);
+ }
+
+ if (headers.owned) {
+ for (headers.list.items) |entry| {
+ headers.allocator.free(entry.value);
+ }
+ }
+ }
+
+ /// Clears and frees the underlying data structures.
+ /// Frees names and values if they are owned.
+ pub fn clearAndFree(headers: *Headers) void {
+ headers.deallocateIndexListsAndFields();
+ headers.index.clearAndFree(headers.allocator);
+ headers.list.clearAndFree(headers.allocator);
+ }
+
+ /// Clears the underlying data structures while retaining their capacities.
+ /// Frees names and values if they are owned.
+ pub fn clearRetainingCapacity(headers: *Headers) void {
+ headers.deallocateIndexListsAndFields();
+ headers.index.clearRetainingCapacity();
+ headers.list.clearRetainingCapacity();
+ }
};
test "Headers.append" {
@@ -384,3 +407,42 @@ test "Headers consistency" {
try h.formatCommaSeparated("foo", writer);
try testing.expectEqualStrings("foo: bar, baz\r\n", fbs.getWritten());
}
+
+test "Headers.clearRetainingCapacity and clearAndFree" {
+ var h = Headers.init(std.testing.allocator);
+ defer h.deinit();
+
+ h.clearRetainingCapacity();
+
+ try h.append("foo", "bar");
+ try h.append("bar", "world");
+ try h.append("foo", "baz");
+ try h.append("baz", "hello");
+ try testing.expectEqual(@as(usize, 4), h.list.items.len);
+ try testing.expectEqual(@as(usize, 3), h.index.count());
+ const list_capacity = h.list.capacity;
+ const index_capacity = h.index.capacity();
+
+ h.clearRetainingCapacity();
+ try testing.expectEqual(@as(usize, 0), h.list.items.len);
+ try testing.expectEqual(@as(usize, 0), h.index.count());
+ try testing.expectEqual(list_capacity, h.list.capacity);
+ try testing.expectEqual(index_capacity, h.index.capacity());
+
+ try h.append("foo", "bar");
+ try h.append("bar", "world");
+ try h.append("foo", "baz");
+ try h.append("baz", "hello");
+ try testing.expectEqual(@as(usize, 4), h.list.items.len);
+ try testing.expectEqual(@as(usize, 3), h.index.count());
+ // Capacity should still be the same since we shouldn't have needed to grow
+ // when adding back the same fields
+ try testing.expectEqual(list_capacity, h.list.capacity);
+ try testing.expectEqual(index_capacity, h.index.capacity());
+
+ h.clearAndFree();
+ try testing.expectEqual(@as(usize, 0), h.list.items.len);
+ try testing.expectEqual(@as(usize, 0), h.index.count());
+ try testing.expectEqual(@as(usize, 0), h.list.capacity);
+ try testing.expectEqual(@as(usize, 0), h.index.capacity());
+}
diff --git a/lib/std/http/Server.zig b/lib/std/http/Server.zig
index 445a10bf48..66adb1bb96 100644
--- a/lib/std/http/Server.zig
+++ b/lib/std/http/Server.zig
@@ -336,8 +336,15 @@ pub const Response = struct {
headers: http.Headers,
request: Request,
+ pub fn deinit(res: *Response) void {
+ res.server.allocator.destroy(res);
+ }
+
/// Reset this response to its initial state. This must be called before handling a second request on the same connection.
pub fn reset(res: *Response) void {
+ res.request.headers.deinit();
+ res.headers.deinit();
+
switch (res.request.compression) {
.none => {},
.deflate => |*deflate| deflate.deinit(),
@@ -356,8 +363,6 @@ pub const Response = struct {
if (res.request.parser.header_bytes_owned) {
res.request.parser.header_bytes.deinit(res.server.allocator);
}
-
- res.* = undefined;
} else {
res.request.parser.reset();
}
@@ -656,3 +661,74 @@ pub fn accept(server: *Server, options: HeaderStrategy) AcceptError!*Response {
return res;
}
+
+test "HTTP server handles a chunked transfer coding request" {
+ const builtin = @import("builtin");
+
+ // This test requires spawning threads.
+ if (builtin.single_threaded) {
+ return error.SkipZigTest;
+ }
+
+ const native_endian = comptime builtin.cpu.arch.endian();
+ if (builtin.zig_backend == .stage2_llvm and native_endian == .Big) {
+ // https://github.com/ziglang/zig/issues/13782
+ return error.SkipZigTest;
+ }
+
+ if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+ const allocator = std.testing.allocator;
+ const expect = std.testing.expect;
+
+ const max_header_size = 8192;
+ var server = std.http.Server.init(allocator, .{ .reuse_address = true });
+ defer server.deinit();
+
+ const address = try std.net.Address.parseIp("127.0.0.1", 0);
+ try server.listen(address);
+ const server_port = server.socket.listen_address.in.getPort();
+
+ const server_thread = try std.Thread.spawn(.{}, (struct {
+ fn apply(s: *std.http.Server) !void {
+ const res = try s.accept(.{ .dynamic = max_header_size });
+ defer res.deinit();
+ defer res.reset();
+ try res.wait();
+
+ try expect(res.request.transfer_encoding.? == .chunked);
+
+ const server_body: []const u8 = "message from server!\n";
+ res.transfer_encoding = .{ .content_length = server_body.len };
+ try res.headers.append("content-type", "text/plain");
+ try res.headers.append("connection", "close");
+ try res.do();
+
+ var buf: [128]u8 = undefined;
+ const n = try res.readAll(&buf);
+ try expect(std.mem.eql(u8, buf[0..n], "ABCD"));
+ _ = try res.writer().writeAll(server_body);
+ try res.finish();
+ }
+ }).apply, .{&server});
+
+ const request_bytes =
+ "POST / HTTP/1.1\r\n" ++
+ "Content-Type: text/plain\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n" ++
+ "1\r\n" ++
+ "A\r\n" ++
+ "1\r\n" ++
+ "B\r\n" ++
+ "2\r\n" ++
+ "CD\r\n" ++
+ "0\r\n" ++
+ "\r\n";
+
+ const stream = try std.net.tcpConnectToHost(allocator, "127.0.0.1", server_port);
+ defer stream.close();
+ _ = try stream.writeAll(request_bytes[0..]);
+
+ server_thread.join();
+}
diff --git a/lib/std/http/protocol.zig b/lib/std/http/protocol.zig
index 0d661bb31f..962376ce82 100644
--- a/lib/std/http/protocol.zig
+++ b/lib/std/http/protocol.zig
@@ -556,8 +556,12 @@ pub const HeadersParser = struct {
switch (r.state) {
.invalid => return error.HttpChunkInvalid,
.chunk_data => if (r.next_chunk_length == 0) {
- // The trailer section is formatted identically to the header section.
- r.state = .seen_rn;
+ if (std.mem.eql(u8, bconn.peek(), "\r\n")) {
+ r.state = .finished;
+ } else {
+ // The trailer section is formatted identically to the header section.
+ r.state = .seen_rn;
+ }
r.done = true;
return out_index;
diff --git a/lib/std/http/test.zig b/lib/std/http/test.zig
new file mode 100644
index 0000000000..ce55c21392
--- /dev/null
+++ b/lib/std/http/test.zig
@@ -0,0 +1,72 @@
+const std = @import("std");
+const expect = std.testing.expect;
+
+test "client requests server" {
+ const builtin = @import("builtin");
+
+ // This test requires spawning threads.
+ if (builtin.single_threaded) {
+ return error.SkipZigTest;
+ }
+
+ const native_endian = comptime builtin.cpu.arch.endian();
+ if (builtin.zig_backend == .stage2_llvm and native_endian == .Big) {
+ // https://github.com/ziglang/zig/issues/13782
+ return error.SkipZigTest;
+ }
+
+ if (builtin.os.tag == .wasi) return error.SkipZigTest;
+
+ const allocator = std.testing.allocator;
+
+ const max_header_size = 8192;
+ var server = std.http.Server.init(allocator, .{ .reuse_address = true });
+ defer server.deinit();
+
+ const address = try std.net.Address.parseIp("127.0.0.1", 0);
+ try server.listen(address);
+ const server_port = server.socket.listen_address.in.getPort();
+
+ const server_thread = try std.Thread.spawn(.{}, (struct {
+ fn apply(s: *std.http.Server) !void {
+ const res = try s.accept(.{ .dynamic = max_header_size });
+ defer res.deinit();
+ defer res.reset();
+ try res.wait();
+
+ const server_body: []const u8 = "message from server!\n";
+ res.transfer_encoding = .{ .content_length = server_body.len };
+ try res.headers.append("content-type", "text/plain");
+ try res.headers.append("connection", "close");
+ try res.do();
+
+ var buf: [128]u8 = undefined;
+ const n = try res.readAll(&buf);
+ try expect(std.mem.eql(u8, buf[0..n], "Hello, World!\n"));
+ _ = try res.writer().writeAll(server_body);
+ try res.finish();
+ }
+ }).apply, .{&server});
+
+ var uri_buf: [22]u8 = undefined;
+ const uri = try std.Uri.parse(try std.fmt.bufPrint(&uri_buf, "http://127.0.0.1:{d}", .{server_port}));
+ var client = std.http.Client{ .allocator = allocator };
+ defer client.deinit();
+ var client_headers = std.http.Headers{ .allocator = allocator };
+ defer client_headers.deinit();
+ var client_req = try client.request(.POST, uri, client_headers, .{});
+ defer client_req.deinit();
+
+ client_req.transfer_encoding = .{ .content_length = 14 }; // this will be checked to ensure you sent exactly 14 bytes
+ try client_req.start(); // this sends the request
+ try client_req.writeAll("Hello, ");
+ try client_req.writeAll("World!\n");
+ try client_req.finish();
+ try client_req.do(); // this waits for a response
+
+ const body = try client_req.reader().readAllAlloc(allocator, 8192 * 1024);
+ defer allocator.free(body);
+ try expect(std.mem.eql(u8, body, "message from server!\n"));
+
+ server_thread.join();
+}
diff --git a/lib/std/macho.zig b/lib/std/macho.zig
index ff12e718f6..a25ffca4fa 100644
--- a/lib/std/macho.zig
+++ b/lib/std/macho.zig
@@ -540,13 +540,13 @@ pub const dylib_command = extern struct {
dylib: dylib,
};
-/// Dynamicaly linked shared libraries are identified by two things. The
+/// Dynamically linked shared libraries are identified by two things. The
/// pathname (the name of the library as found for execution), and the
/// compatibility version number. The pathname must match and the compatibility
/// number in the user of the library must be greater than or equal to the
/// library being used. The time stamp is used to record the time a library was
/// built and copied into user so it can be use to determined if the library used
-/// at runtime is exactly the same as used to built the program.
+/// at runtime is exactly the same as used to build the program.
pub const dylib = extern struct {
/// library's pathname (offset pointing at the end of dylib_command)
name: u32,
diff --git a/lib/std/math.zig b/lib/std/math.zig
index 14c71a796f..02b737610c 100644
--- a/lib/std/math.zig
+++ b/lib/std/math.zig
@@ -782,7 +782,8 @@ fn testOverflow() !void {
}
/// Returns the absolute value of x, where x is a value of a signed integer type.
-/// See also: `absCast`
+/// Does not convert and returns a value of a signed integer type.
+/// Use `absCast` if you want to convert the result and get an unsigned type.
pub fn absInt(x: anytype) !@TypeOf(x) {
const T = @TypeOf(x);
return switch (@typeInfo(T)) {
@@ -1015,8 +1016,8 @@ pub inline fn fabs(value: anytype) @TypeOf(value) {
}
/// Returns the absolute value of the integer parameter.
-/// Result is an unsigned integer.
-/// See also: `absInt`
+/// Converts result type to unsigned if needed and returns a value of an unsigned integer type.
+/// Use `absInt` if you want to keep your integer type signed.
pub fn absCast(x: anytype) switch (@typeInfo(@TypeOf(x))) {
.ComptimeInt => comptime_int,
.Int => |int_info| std.meta.Int(.unsigned, int_info.bits),
diff --git a/lib/std/mem.zig b/lib/std/mem.zig
index 940882e930..4b796c851a 100644
--- a/lib/std/mem.zig
+++ b/lib/std/mem.zig
@@ -227,7 +227,7 @@ pub fn set(comptime T: type, dest: []T, value: T) void {
/// interfacing with a C API where this practice is more common and relied upon. If you are performing code review and see this
/// function used, examine closely - it may be a code smell.
/// Zero initializes the type.
-/// This can be used to zero initialize a any type for which it makes sense. Structs will be initialized recursively.
+/// This can be used to zero-initialize any type for which it makes sense. Structs will be initialized recursively.
pub fn zeroes(comptime T: type) T {
switch (@typeInfo(T)) {
.ComptimeInt, .Int, .ComptimeFloat, .Float => {
diff --git a/lib/std/net.zig b/lib/std/net.zig
index 8800bbe6be..205fbf4842 100644
--- a/lib/std/net.zig
+++ b/lib/std/net.zig
@@ -1867,6 +1867,7 @@ pub const StreamServer = struct {
/// Copied from `Options` on `init`.
kernel_backlog: u31,
reuse_address: bool,
+ reuse_port: bool,
/// `undefined` until `listen` returns successfully.
listen_address: Address,
@@ -1881,6 +1882,9 @@ pub const StreamServer = struct {
/// Enable SO.REUSEADDR on the socket.
reuse_address: bool = false,
+
+ /// Enable SO.REUSEPORT on the socket.
+ reuse_port: bool = false,
};
/// After this call succeeds, resources have been acquired and must
@@ -1890,6 +1894,7 @@ pub const StreamServer = struct {
.sockfd = null,
.kernel_backlog = options.kernel_backlog,
.reuse_address = options.reuse_address,
+ .reuse_port = options.reuse_port,
.listen_address = undefined,
};
}
@@ -1920,6 +1925,14 @@ pub const StreamServer = struct {
&mem.toBytes(@as(c_int, 1)),
);
}
+ if (@hasDecl(os.SO, "REUSEPORT") and self.reuse_port) {
+ try os.setsockopt(
+ sockfd,
+ os.SOL.SOCKET,
+ os.SO.REUSEPORT,
+ &mem.toBytes(@as(c_int, 1)),
+ );
+ }
var socklen = address.getOsSockLen();
try os.bind(sockfd, &address.any, socklen);
diff --git a/lib/std/net/test.zig b/lib/std/net/test.zig
index c4afc0e4e3..f59d73d621 100644
--- a/lib/std/net/test.zig
+++ b/lib/std/net/test.zig
@@ -230,6 +230,27 @@ test "listen on ipv4 try connect on ipv6 then ipv4" {
try await client_frame;
}
+test "listen on an in use port" {
+ if (builtin.os.tag != .linux and comptime !builtin.os.tag.isDarwin()) {
+ // TODO build abstractions for other operating systems
+ return error.SkipZigTest;
+ }
+
+ const localhost = try net.Address.parseIp("127.0.0.1", 0);
+
+ var server1 = net.StreamServer.init(net.StreamServer.Options{
+ .reuse_port = true,
+ });
+ defer server1.deinit();
+ try server1.listen(localhost);
+
+ var server2 = net.StreamServer.init(net.StreamServer.Options{
+ .reuse_port = true,
+ });
+ defer server2.deinit();
+ try server2.listen(server1.listen_address);
+}
+
fn testClientToHost(allocator: mem.Allocator, name: []const u8, port: u16) anyerror!void {
if (builtin.os.tag == .wasi) return error.SkipZigTest;
diff --git a/lib/std/os.zig b/lib/std/os.zig
index 13b0c62455..5b5189ea60 100644
--- a/lib/std/os.zig
+++ b/lib/std/os.zig
@@ -4722,11 +4722,8 @@ pub fn sysctl(
newp: ?*anyopaque,
newlen: usize,
) SysCtlError!void {
- if (builtin.os.tag == .wasi) {
- @panic("unsupported"); // TODO should be compile error, not panic
- }
- if (builtin.os.tag == .haiku) {
- @panic("unsupported"); // TODO should be compile error, not panic
+ if (builtin.os.tag == .wasi or builtin.os.tag == .haiku) {
+ @compileError("unsupported OS");
}
const name_len = math.cast(c_uint, name.len) orelse return error.NameTooLong;
@@ -4747,11 +4744,8 @@ pub fn sysctlbynameZ(
newp: ?*anyopaque,
newlen: usize,
) SysCtlError!void {
- if (builtin.os.tag == .wasi) {
- @panic("unsupported"); // TODO should be compile error, not panic
- }
- if (builtin.os.tag == .haiku) {
- @panic("unsupported"); // TODO should be compile error, not panic
+ if (builtin.os.tag == .wasi or builtin.os.tag == .haiku) {
+ @compileError("unsupported OS");
}
switch (errno(system.sysctlbyname(name, oldp, oldlenp, newp, newlen))) {
diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig
index b6ec05997f..6646cb1d32 100644
--- a/lib/std/os/linux.zig
+++ b/lib/std/os/linux.zig
@@ -3464,7 +3464,10 @@ pub const CAP = struct {
pub const WAKE_ALARM = 35;
pub const BLOCK_SUSPEND = 36;
pub const AUDIT_READ = 37;
- pub const LAST_CAP = AUDIT_READ;
+ pub const PERFMON = 38;
+ pub const BPF = 39;
+ pub const CHECKPOINT_RESTORE = 40;
+ pub const LAST_CAP = CHECKPOINT_RESTORE;
pub fn valid(x: u8) bool {
return x >= 0 and x <= LAST_CAP;
diff --git a/lib/std/os/linux/seccomp.zig b/lib/std/os/linux/seccomp.zig
index b659c3d0e8..23dbb6ee38 100644
--- a/lib/std/os/linux/seccomp.zig
+++ b/lib/std/os/linux/seccomp.zig
@@ -20,7 +20,7 @@
//!
//! 1. Each CPU architecture supported by Linux has its own unique ABI and
//! syscall API. It is not guaranteed that the syscall numbers and arguments
-//! are the same across architectures, or that they're even implemted. Thus,
+//! are the same across architectures, or that they're even implemented. Thus,
//! filters cannot be assumed to be portable without consulting documentation
//! like syscalls(2) and testing on target hardware. This also requires
//! checking the value of `data.arch` to make sure that a filter was compiled
diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig
index 5174090712..682bd4f6f8 100644
--- a/lib/std/os/test.zig
+++ b/lib/std/os/test.zig
@@ -1101,6 +1101,8 @@ test "isatty" {
defer tmp.cleanup();
var file = try tmp.dir.createFile("foo", .{});
+ defer file.close();
+
try expectEqual(os.isatty(file.handle), false);
}
diff --git a/lib/std/process.zig b/lib/std/process.zig
index 578efa62c4..56e3708f3b 100644
--- a/lib/std/process.zig
+++ b/lib/std/process.zig
@@ -818,7 +818,8 @@ pub const ArgIterator = struct {
}
};
-/// Use argsWithAllocator() for cross-platform code
+/// Holds the command-line arguments, with the program name as the first entry.
+/// Use argsWithAllocator() for cross-platform code.
pub fn args() ArgIterator {
return ArgIterator.init();
}
@@ -1162,12 +1163,17 @@ pub fn totalSystemMemory() TotalSystemMemoryError!usize {
.linux => {
return totalSystemMemoryLinux() catch return error.UnknownTotalSystemMemory;
},
- .freebsd => {
+ .freebsd, .netbsd, .openbsd, .dragonfly, .macos => {
var physmem: c_ulong = undefined;
var len: usize = @sizeOf(c_ulong);
- os.sysctlbynameZ("hw.physmem", &physmem, &len, null, 0) catch |err| switch (err) {
+ const name = switch (builtin.os.tag) {
+ .macos => "hw.memsize",
+ .netbsd => "hw.physmem64",
+ else => "hw.physmem",
+ };
+ os.sysctlbynameZ(name, &physmem, &len, null, 0) catch |err| switch (err) {
error.NameTooLong, error.UnknownName => unreachable,
- else => |e| return e,
+ else => return error.UnknownTotalSystemMemory,
};
return @intCast(usize, physmem);
},
diff --git a/lib/std/rand.zig b/lib/std/rand.zig
index 4f9cb0db56..204409c10e 100644
--- a/lib/std/rand.zig
+++ b/lib/std/rand.zig
@@ -389,6 +389,8 @@ pub const Random = struct {
/// Randomly selects an index into `proportions`, where the likelihood of each
/// index is weighted by that proportion.
+ /// It is more likely for the index of the last proportion to be returned
+ /// than the index of the first proportion in the slice, and vice versa.
///
/// This is useful for selecting an item from a slice where weights are not equal.
/// `T` must be a numeric type capable of holding the sum of `proportions`.
diff --git a/lib/std/tar.zig b/lib/std/tar.zig
index 91772d7319..ec668d5f93 100644
--- a/lib/std/tar.zig
+++ b/lib/std/tar.zig
@@ -35,7 +35,7 @@ pub const Header = struct {
pub fn fileSize(header: Header) !u64 {
const raw = header.bytes[124..][0..12];
const ltrimmed = std.mem.trimLeft(u8, raw, "0");
- const rtrimmed = std.mem.trimRight(u8, ltrimmed, "\x00");
+ const rtrimmed = std.mem.trimRight(u8, ltrimmed, " \x00");
if (rtrimmed.len == 0) return 0;
return std.fmt.parseInt(u64, rtrimmed, 8);
}
@@ -122,13 +122,16 @@ pub fn pipeToFileSystem(dir: std.fs.Dir, reader: anytype, options: Options) !voi
.directory => {
const file_name = try stripComponents(unstripped_file_name, options.strip_components);
if (file_name.len != 0) {
- try dir.makeDir(file_name);
+ try dir.makePath(file_name);
}
},
.normal => {
if (file_size == 0 and unstripped_file_name.len == 0) return;
const file_name = try stripComponents(unstripped_file_name, options.strip_components);
+ if (std.fs.path.dirname(file_name)) |dir_name| {
+ try dir.makePath(dir_name);
+ }
var file = try dir.createFile(file_name, .{});
defer file.close();
diff --git a/src/Air.zig b/src/Air.zig
index 19ba576a5f..33a8d0515b 100644
--- a/src/Air.zig
+++ b/src/Air.zig
@@ -681,7 +681,7 @@ pub const Inst = struct {
/// Uses the `un_op` field.
tag_name,
- /// Given an error value, return the error name. Result type is always `[:0] const u8`.
+ /// Given an error value, return the error name. Result type is always `[:0]const u8`.
/// Uses the `un_op` field.
error_name,
diff --git a/src/AstGen.zig b/src/AstGen.zig
index 4419f5e803..d802e9dcc8 100644
--- a/src/AstGen.zig
+++ b/src/AstGen.zig
@@ -839,12 +839,9 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
.slice_open => {
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
-
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, node_datas[node].rhs);
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
const result = try gz.addPlNode(.slice_start, node, Zir.Inst.SliceStart{
.lhs = lhs,
.start = start,
@@ -854,14 +851,11 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
.slice => {
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
-
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice);
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start);
const end = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end);
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{
.lhs = lhs,
.start = start,
@@ -872,15 +866,12 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
.slice_sentinel => {
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
-
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel);
const start = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.start);
const end = if (extra.end != 0) try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, extra.end) else .none;
const sentinel = try expr(gz, scope, .{ .rl = .none }, extra.sentinel);
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
const result = try gz.addPlNode(.slice_sentinel, node, Zir.Inst.SliceSentinel{
.lhs = lhs,
.start = start,
@@ -914,20 +905,16 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
.ref => {
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
- try emitDbgStmt(gz, line, column);
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
+ try emitDbgStmt(gz, cursor);
return gz.addUnNode(.optional_payload_safe_ptr, lhs, node);
},
else => {
const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
- try emitDbgStmt(gz, line, column);
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
+ try emitDbgStmt(gz, cursor);
return rvalue(gz, ri, try gz.addUnNode(.optional_payload_safe, lhs, node), node);
},
@@ -3330,23 +3317,17 @@ fn assignOp(
const lhs_ptr = try lvalExpr(gz, scope, node_datas[infix_node].lhs);
- var line: u32 = undefined;
- var column: u32 = undefined;
- switch (op_inst_tag) {
- .add, .sub, .mul, .div, .mod_rem => {
- maybeAdvanceSourceCursorToMainToken(gz, infix_node);
- line = gz.astgen.source_line - gz.decl_line;
- column = gz.astgen.source_column;
- },
- else => {},
- }
+ const cursor = switch (op_inst_tag) {
+ .add, .sub, .mul, .div, .mod_rem => maybeAdvanceSourceCursorToMainToken(gz, infix_node),
+ else => undefined,
+ };
const lhs = try gz.addUnNode(.load, lhs_ptr, infix_node);
const lhs_type = try gz.addUnNode(.typeof, lhs, infix_node);
const rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = lhs_type } }, node_datas[infix_node].rhs);
switch (op_inst_tag) {
.add, .sub, .mul, .div, .mod_rem => {
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
},
else => {},
}
@@ -5360,8 +5341,7 @@ fn tryExpr(
if (!parent_gz.is_comptime) {
try emitDbgNode(parent_gz, node);
}
- const try_line = astgen.source_line - parent_gz.decl_line;
- const try_column = astgen.source_column;
+ const try_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
const operand_ri: ResultInfo = switch (ri.rl) {
.ref => .{ .rl = .ref, .ctx = .error_handling_expr },
@@ -5382,7 +5362,7 @@ fn tryExpr(
};
const err_code = try else_scope.addUnNode(err_tag, operand, node);
try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
- try emitDbgStmt(&else_scope, try_line, try_column);
+ try emitDbgStmt(&else_scope, try_lc);
_ = try else_scope.addUnNode(.ret_node, err_code, node);
try else_scope.setTryBody(try_inst, operand);
@@ -5607,10 +5587,8 @@ fn addFieldAccess(
const str_index = try astgen.identAsString(field_ident);
const lhs = try expr(gz, scope, lhs_ri, object_node);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
- try emitDbgStmt(gz, line, column);
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
+ try emitDbgStmt(gz, cursor);
return gz.addPlNode(tag, node, Zir.Inst.Field{
.lhs = lhs,
@@ -5630,24 +5608,20 @@ fn arrayAccess(
.ref => {
const lhs = try expr(gz, scope, .{ .rl = .ref }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
const rhs = try expr(gz, scope, .{ .rl = .{ .ty = .usize_type } }, node_datas[node].rhs);
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs });
},
else => {
const lhs = try expr(gz, scope, .{ .rl = .none }, node_datas[node].lhs);
- maybeAdvanceSourceCursorToMainToken(gz, node);
- const line = gz.astgen.source_line - gz.decl_line;
- const column = gz.astgen.source_column;
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
const rhs = try expr(gz, scope, .{ .rl = .{ .ty = .usize_type } }, node_datas[node].rhs);
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
return rvalue(gz, ri, try gz.addPlNode(.elem_val_node, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs }), node);
},
@@ -5674,21 +5648,15 @@ fn simpleBinOp(
}
const lhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].lhs, node);
- var line: u32 = undefined;
- var column: u32 = undefined;
- switch (op_inst_tag) {
- .add, .sub, .mul, .div, .mod_rem => {
- maybeAdvanceSourceCursorToMainToken(gz, node);
- line = gz.astgen.source_line - gz.decl_line;
- column = gz.astgen.source_column;
- },
- else => {},
- }
+ const cursor = switch (op_inst_tag) {
+ .add, .sub, .mul, .div, .mod_rem => maybeAdvanceSourceCursorToMainToken(gz, node),
+ else => undefined,
+ };
const rhs = try reachableExpr(gz, scope, .{ .rl = .none }, node_datas[node].rhs, node);
switch (op_inst_tag) {
.add, .sub, .mul, .div, .mod_rem => {
- try emitDbgStmt(gz, line, column);
+ try emitDbgStmt(gz, cursor);
},
else => {},
}
@@ -6787,14 +6755,15 @@ fn switchExpr(
}
const operand_ri: ResultInfo = .{ .rl = if (any_payload_is_ref) .ref else .none };
+
astgen.advanceSourceCursorToNode(operand_node);
- const operand_line = astgen.source_line - parent_gz.decl_line;
- const operand_column = astgen.source_column;
+ const operand_lc = LineColumn{ astgen.source_line - parent_gz.decl_line, astgen.source_column };
+
const raw_operand = try expr(parent_gz, scope, operand_ri, operand_node);
const cond_tag: Zir.Inst.Tag = if (any_payload_is_ref) .switch_cond_ref else .switch_cond;
const cond = try parent_gz.addUnNode(cond_tag, raw_operand, operand_node);
// Sema expects a dbg_stmt immediately after switch_cond(_ref)
- try emitDbgStmt(parent_gz, operand_line, operand_column);
+ try emitDbgStmt(parent_gz, operand_lc);
// We need the type of the operand to use as the result location for all the prong items.
const cond_ty_inst = try parent_gz.addUnNode(.typeof, cond, operand_node);
const item_ri: ResultInfo = .{ .rl = .{ .ty = cond_ty_inst } };
@@ -7154,8 +7123,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
if (!gz.is_comptime) {
try emitDbgNode(gz, node);
}
- const ret_line = astgen.source_line - gz.decl_line;
- const ret_column = astgen.source_column;
+ const ret_lc = LineColumn{ astgen.source_line - gz.decl_line, astgen.source_column };
const defer_outer = &astgen.fn_block.?.base;
@@ -7179,13 +7147,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
const defer_counts = countDefers(defer_outer, scope);
if (!defer_counts.need_err_code) {
try genDefers(gz, defer_outer, scope, .both_sans_err);
- try emitDbgStmt(gz, ret_line, ret_column);
+ try emitDbgStmt(gz, ret_lc);
_ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
return Zir.Inst.Ref.unreachable_value;
}
const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
try genDefers(gz, defer_outer, scope, .{ .both = err_code });
- try emitDbgStmt(gz, ret_line, ret_column);
+ try emitDbgStmt(gz, ret_lc);
_ = try gz.addUnNode(.ret_node, err_code, node);
return Zir.Inst.Ref.unreachable_value;
}
@@ -7210,7 +7178,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
// As our last action before the return, "pop" the error trace if needed
_ = try gz.addRestoreErrRetIndex(.ret, .always);
- try emitDbgStmt(gz, ret_line, ret_column);
+ try emitDbgStmt(gz, ret_lc);
try gz.addRet(ri, operand, node);
return Zir.Inst.Ref.unreachable_value;
},
@@ -7218,7 +7186,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
// Value is always an error. Emit both error defers and regular defers.
const err_code = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand;
try genDefers(gz, defer_outer, scope, .{ .both = err_code });
- try emitDbgStmt(gz, ret_line, ret_column);
+ try emitDbgStmt(gz, ret_lc);
try gz.addRet(ri, operand, node);
return Zir.Inst.Ref.unreachable_value;
},
@@ -7227,7 +7195,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
if (!defer_counts.have_err) {
// Only regular defers; no branch needed.
try genDefers(gz, defer_outer, scope, .normal_only);
- try emitDbgStmt(gz, ret_line, ret_column);
+ try emitDbgStmt(gz, ret_lc);
// As our last action before the return, "pop" the error trace if needed
const result = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand;
@@ -7250,7 +7218,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
// As our last action before the return, "pop" the error trace if needed
_ = try then_scope.addRestoreErrRetIndex(.ret, .always);
- try emitDbgStmt(&then_scope, ret_line, ret_column);
+ try emitDbgStmt(&then_scope, ret_lc);
try then_scope.addRet(ri, operand, node);
var else_scope = gz.makeSubBlock(scope);
@@ -7260,7 +7228,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
.both = try else_scope.addUnNode(.err_union_code, result, node),
};
try genDefers(&else_scope, defer_outer, scope, which_ones);
- try emitDbgStmt(&else_scope, ret_line, ret_column);
+ try emitDbgStmt(&else_scope, ret_lc);
try else_scope.addRet(ri, operand, node);
try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
@@ -8174,6 +8142,7 @@ fn builtinCall(
.frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node),
.frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node),
.breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
+ .in_comptime => return rvalue(gz, ri, try gz.addNodeExtended(.in_comptime, node), node),
.type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info),
.size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of),
@@ -8649,11 +8618,14 @@ fn typeCast(
rhs_node: Ast.Node.Index,
tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
- try emitDbgNode(gz, node);
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
+ const result_type = try typeExpr(gz, scope, lhs_node);
+ const operand = try expr(gz, scope, .{ .rl = .none }, rhs_node);
+ try emitDbgStmt(gz, cursor);
const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
- .lhs = try typeExpr(gz, scope, lhs_node),
- .rhs = try expr(gz, scope, .{ .rl = .none }, rhs_node),
+ .lhs = result_type,
+ .rhs = operand,
});
return rvalue(gz, ri, result, node);
}
@@ -8680,14 +8652,15 @@ fn simpleUnOp(
operand_node: Ast.Node.Index,
tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
- switch (tag) {
- .tag_name, .error_name, .ptr_to_int => try emitDbgNode(gz, node),
- else => {},
- }
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
const operand = if (tag == .compile_error)
try comptimeExpr(gz, scope, operand_ri, operand_node)
else
try expr(gz, scope, operand_ri, operand_node);
+ switch (tag) {
+ .tag_name, .error_name, .ptr_to_int => try emitDbgStmt(gz, cursor),
+ else => {},
+ }
const result = try gz.addUnNode(tag, operand, node);
return rvalue(gz, ri, result, node);
}
@@ -8759,12 +8732,12 @@ fn divBuiltin(
rhs_node: Ast.Node.Index,
tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
- try emitDbgNode(gz, node);
+ const cursor = maybeAdvanceSourceCursorToMainToken(gz, node);
+ const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node);
+ const rhs = try expr(gz, scope, .{ .rl = .none }, rhs_node);
- const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
- .lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node),
- .rhs = try expr(gz, scope, .{ .rl = .none }, rhs_node),
- });
+ try emitDbgStmt(gz, cursor);
+ const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ .lhs = lhs, .rhs = rhs });
return rvalue(gz, ri, result, node);
}
@@ -8813,23 +8786,21 @@ fn shiftOp(
rhs_node: Ast.Node.Index,
tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
- var line = gz.astgen.source_line - gz.decl_line;
- var column = gz.astgen.source_column;
const lhs = try expr(gz, scope, .{ .rl = .none }, lhs_node);
- switch (gz.astgen.tree.nodes.items(.tag)[node]) {
- .shl, .shr => {
- maybeAdvanceSourceCursorToMainToken(gz, node);
- line = gz.astgen.source_line - gz.decl_line;
- column = gz.astgen.source_column;
- },
- else => {},
- }
+ const cursor = switch (gz.astgen.tree.nodes.items(.tag)[node]) {
+ .shl, .shr => maybeAdvanceSourceCursorToMainToken(gz, node),
+ else => undefined,
+ };
const log2_int_type = try gz.addUnNode(.typeof_log2_int_type, lhs, lhs_node);
const rhs = try expr(gz, scope, .{ .rl = .{ .ty = log2_int_type }, .ctx = .shift_op }, rhs_node);
- try emitDbgStmt(gz, line, column);
+ switch (gz.astgen.tree.nodes.items(.tag)[node]) {
+ .shl, .shr => try emitDbgStmt(gz, cursor),
+ else => undefined,
+ }
+
const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{
.lhs = lhs,
.rhs = rhs,
@@ -12593,16 +12564,20 @@ fn detectLocalShadowing(
};
}
+const LineColumn = struct { u32, u32 };
+
/// Advances the source cursor to the main token of `node` if not in comptime scope.
/// Usually paired with `emitDbgStmt`.
-fn maybeAdvanceSourceCursorToMainToken(gz: *GenZir, node: Ast.Node.Index) void {
- if (gz.is_comptime) return;
+fn maybeAdvanceSourceCursorToMainToken(gz: *GenZir, node: Ast.Node.Index) LineColumn {
+ if (gz.is_comptime) return .{ gz.astgen.source_line - gz.decl_line, gz.astgen.source_column };
const tree = gz.astgen.tree;
const token_starts = tree.tokens.items(.start);
const main_tokens = tree.nodes.items(.main_token);
const node_start = token_starts[main_tokens[node]];
gz.astgen.advanceSourceCursor(node_start);
+
+ return .{ gz.astgen.source_line - gz.decl_line, gz.astgen.source_column };
}
/// Advances the source cursor to the beginning of `node`.
@@ -12806,13 +12781,13 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
return @intCast(u32, count);
}
-fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {
+fn emitDbgStmt(gz: *GenZir, lc: LineColumn) !void {
if (gz.is_comptime) return;
_ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
.dbg_stmt = .{
- .line = line,
- .column = column,
+ .line = lc[0],
+ .column = lc[1],
},
} });
}
diff --git a/src/Autodoc.zig b/src/Autodoc.zig
index 67cb6b7325..3c1beda74a 100644
--- a/src/Autodoc.zig
+++ b/src/Autodoc.zig
@@ -4076,7 +4076,7 @@ fn analyzeFancyFunction(
else => null,
};
- // if we're analyzing a funcion signature (ie without body), we
+ // if we're analyzing a function signature (ie without body), we
// actually don't have an ast_node reserved for us, but since
// we don't have a name, we don't need it.
const src = if (fn_info.body.len == 0) 0 else self_ast_node_index;
@@ -4229,7 +4229,7 @@ fn analyzeFunction(
} else break :blk ret_type_ref;
};
- // if we're analyzing a funcion signature (ie without body), we
+ // if we're analyzing a function signature (ie without body), we
// actually don't have an ast_node reserved for us, but since
// we don't have a name, we don't need it.
const src = if (fn_info.body.len == 0) 0 else self_ast_node_index;
diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig
index 4a98a5a615..ee11aecbf4 100644
--- a/src/BuiltinFn.zig
+++ b/src/BuiltinFn.zig
@@ -58,6 +58,7 @@ pub const Tag = enum {
has_decl,
has_field,
import,
+ in_comptime,
int_cast,
int_to_enum,
int_to_error,
@@ -560,6 +561,13 @@ pub const list = list: {
.param_count = 1,
},
},
+ .{
+ "@inComptime",
+ .{
+ .tag = .in_comptime,
+ .param_count = 0,
+ },
+ },
.{
"@intCast",
.{
diff --git a/src/Module.zig b/src/Module.zig
index fa91e8c1ed..27f7b24e7a 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -6626,7 +6626,7 @@ pub fn backendSupportsFeature(mod: Module, feature: Feature) bool {
.safety_check_formatted => mod.comp.bin_file.options.use_llvm,
.error_return_trace => mod.comp.bin_file.options.use_llvm,
.is_named_enum_value => mod.comp.bin_file.options.use_llvm,
- .error_set_has_value => mod.comp.bin_file.options.use_llvm,
+ .error_set_has_value => mod.comp.bin_file.options.use_llvm or mod.comp.bin_file.options.target.isWasm(),
.field_reordering => mod.comp.bin_file.options.use_llvm,
};
}
diff --git a/src/Sema.zig b/src/Sema.zig
index 5c19d37431..ed36417876 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -1166,6 +1166,7 @@ fn analyzeBodyInner(
.work_item_id => try sema.zirWorkItem( block, extended, extended.opcode),
.work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),
.work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
+ .in_comptime => try sema.zirInComptime( block),
// zig fmt: on
.fence => {
@@ -4155,7 +4156,7 @@ fn validateUnionInit(
const msg = try sema.errMsg(
block,
init_src,
- "cannot initialize multiple union fields at once, unions can only have one active field",
+ "cannot initialize multiple union fields at once; unions can only have one active field",
.{},
);
errdefer msg.destroy(sema.gpa);
@@ -9646,7 +9647,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.Union => "union",
else => unreachable,
};
- return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}', {s} does not have a guaranteed in-memory layout", .{
+ return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{
dest_ty.fmt(sema.mod), container,
});
},
@@ -9709,7 +9710,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.Union => "union",
else => unreachable,
};
- return sema.fail(block, operand_src, "cannot @bitCast from '{}', {s} does not have a guaranteed in-memory layout", .{
+ return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{
operand_ty.fmt(sema.mod), container,
});
},
@@ -19626,7 +19627,7 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
try sema.requireRuntimeBlock(block, src, operand_src);
- if (block.wantSafety() and try sema.typeHasRuntimeBits(elem_ty)) {
+ if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag() == .Fn)) {
if (!ptr_ty.isAllowzeroPtr()) {
const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
@@ -19852,7 +19853,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
try sema.requireRuntimeBlock(block, src, null);
if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and
- try sema.typeHasRuntimeBits(dest_ty.elemType2()))
+ (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn))
{
const ptr_int = try block.addUnOp(.ptrtoint, ptr);
const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
@@ -22466,6 +22467,18 @@ fn zirWorkItem(
});
}
+fn zirInComptime(
+ sema: *Sema,
+ block: *Block,
+) CompileError!Air.Inst.Ref {
+ _ = sema;
+ if (block.is_comptime) {
+ return Air.Inst.Ref.bool_true;
+ } else {
+ return Air.Inst.Ref.bool_false;
+ }
+}
+
fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
if (block.is_comptime) {
const msg = msg: {
@@ -23738,7 +23751,6 @@ fn fieldCallBind(
{
const first_param_type = decl_type.fnParamType(0);
const first_param_tag = first_param_type.tag();
- var opt_buf: Type.Payload.ElemType = undefined;
// zig fmt: off
if (first_param_tag == .var_args_param or
first_param_tag == .generic_poison or (
@@ -23764,17 +23776,29 @@ fn fieldCallBind(
.arg0_inst = deref,
});
return sema.addConstant(ty, value);
- } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .Optional and
- first_param_type.optionalChild(&opt_buf).eql(concrete_ty, sema.mod))
- {
- const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
- .func_inst = decl_val,
- .arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
- } else if (first_param_tag != .generic_poison and first_param_type.zigTypeTag() == .ErrorUnion and
+ } else if (first_param_type.zigTypeTag() == .Optional) {
+ var opt_buf: Type.Payload.ElemType = undefined;
+ const child = first_param_type.optionalChild(&opt_buf);
+ if (child.eql(concrete_ty, sema.mod)) {
+ const deref = try sema.analyzeLoad(block, src, object_ptr, src);
+ const ty = Type.Tag.bound_fn.init();
+ const value = try Value.Tag.bound_fn.create(arena, .{
+ .func_inst = decl_val,
+ .arg0_inst = deref,
+ });
+ return sema.addConstant(ty, value);
+ } else if (child.zigTypeTag() == .Pointer and
+ child.ptrSize() == .One and
+ child.childType().eql(concrete_ty, sema.mod))
+ {
+ const ty = Type.Tag.bound_fn.init();
+ const value = try Value.Tag.bound_fn.create(arena, .{
+ .func_inst = decl_val,
+ .arg0_inst = object_ptr,
+ });
+ return sema.addConstant(ty, value);
+ }
+ } else if (first_param_type.zigTypeTag() == .ErrorUnion and
first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
{
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
@@ -26434,7 +26458,7 @@ fn coerceVarArgParam(
.ComptimeInt, .ComptimeFloat => return sema.fail(
block,
inst_src,
- "integer and float literals passed variadic function must be casted to a fixed-size number type",
+ "integer and float literals passed to variadic function must be casted to a fixed-size number type",
.{},
),
.Fn => blk: {
@@ -27718,7 +27742,7 @@ fn coerceCompatiblePtrs(
try sema.requireRuntimeBlock(block, inst_src, null);
const inst_allows_zero = inst_ty.zigTypeTag() != .Pointer or inst_ty.ptrAllowsZero();
if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and
- try sema.typeHasRuntimeBits(dest_ty.elemType2()))
+ (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn))
{
const actual_ptr = if (inst_ty.isSlice())
try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
@@ -27891,7 +27915,7 @@ fn coerceAnonStructToUnion(
const msg = if (field_count > 1) try sema.errMsg(
block,
inst_src,
- "cannot initialize multiple union fields at once, unions can only have one active field",
+ "cannot initialize multiple union fields at once; unions can only have one active field",
.{},
) else try sema.errMsg(
block,
diff --git a/src/Zir.zig b/src/Zir.zig
index 904e02c755..a58b4b4070 100644
--- a/src/Zir.zig
+++ b/src/Zir.zig
@@ -1994,10 +1994,10 @@ pub const Inst = struct {
/// Implement builtin `@cVaArg`.
/// `operand` is payload index to `BinNode`.
c_va_arg,
- /// Implement builtin `@cVaStart`.
+ /// Implement builtin `@cVaCopy`.
/// `operand` is payload index to `UnNode`.
c_va_copy,
- /// Implement builtin `@cVaStart`.
+ /// Implement builtin `@cVaEnd`.
/// `operand` is payload index to `UnNode`.
c_va_end,
/// Implement builtin `@cVaStart`.
@@ -2018,6 +2018,9 @@ pub const Inst = struct {
/// Implements the `@workGroupId` builtin.
/// `operand` is payload index to `UnNode`.
work_group_id,
+ /// Implements the `@inComptime` builtin.
+ /// `operand` is `src_node: i32`.
+ in_comptime,
pub const InstData = struct {
opcode: Extended,
diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig
index b94d3993f9..9bf39b73f1 100644
--- a/src/arch/wasm/CodeGen.zig
+++ b/src/arch/wasm/CodeGen.zig
@@ -1946,6 +1946,8 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.ret_addr => func.airRetAddr(inst),
.tag_name => func.airTagName(inst),
+ .error_set_has_value => func.airErrorSetHasValue(inst),
+
.mul_sat,
.mod,
.assembly,
@@ -1967,7 +1969,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
.set_err_return_trace,
.save_err_return_trace_index,
.is_named_enum_value,
- .error_set_has_value,
.addrspace_cast,
.vector_store_elem,
.c_va_arg,
@@ -3338,9 +3339,14 @@ fn airCmpVector(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
fn airCmpLtErrorsLen(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
const un_op = func.air.instructions.items(.data)[inst].un_op;
const operand = try func.resolveInst(un_op);
+ const sym_index = try func.bin_file.getGlobalSymbol("__zig_errors_len", null);
+ const errors_len = WValue{ .memory = sym_index };
- _ = operand;
- return func.fail("TODO implement airCmpLtErrorsLen for wasm", .{});
+ try func.emitWValue(operand);
+ const errors_len_val = try func.load(errors_len, Type.err_int, 0);
+ const result = try func.cmp(.stack, errors_len_val, Type.err_int, .lt);
+
+ return func.finishAir(inst, try result.toLocal(func, Type.bool), &.{un_op});
}
fn airBr(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
@@ -6510,3 +6516,84 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
const func_type = try genFunctype(arena, .Unspecified, &.{int_tag_ty}, slice_ty, func.target);
return func.bin_file.createFunction(func_name, func_type, &body_list, &relocs);
}
+
+fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
+ const ty_op = func.air.instructions.items(.data)[inst].ty_op;
+
+ const operand = try func.resolveInst(ty_op.operand);
+ const error_set_ty = func.air.getRefType(ty_op.ty);
+ const result = try func.allocLocal(Type.bool);
+
+ const names = error_set_ty.errorSetNames();
+ var values = try std.ArrayList(u32).initCapacity(func.gpa, names.len);
+ defer values.deinit();
+
+ const module = func.bin_file.base.options.module.?;
+ var lowest: ?u32 = null;
+ var highest: ?u32 = null;
+ for (names) |name| {
+ const err_int = module.global_error_set.get(name).?;
+ if (lowest) |*l| {
+ if (err_int < l.*) {
+ l.* = err_int;
+ }
+ } else {
+ lowest = err_int;
+ }
+ if (highest) |*h| {
+ if (err_int > h.*) {
+ highest = err_int;
+ }
+ } else {
+ highest = err_int;
+ }
+
+ values.appendAssumeCapacity(err_int);
+ }
+
+ // start block for 'true' branch
+ try func.startBlock(.block, wasm.block_empty);
+ // start block for 'false' branch
+ try func.startBlock(.block, wasm.block_empty);
+ // block for the jump table itself
+ try func.startBlock(.block, wasm.block_empty);
+
+ // lower operand to determine jump table target
+ try func.emitWValue(operand);
+ try func.addImm32(@intCast(i32, lowest.?));
+ try func.addTag(.i32_sub);
+
+ // Account for default branch so always add '1'
+ const depth = @intCast(u32, highest.? - lowest.? + 1);
+ const jump_table: Mir.JumpTable = .{ .length = depth };
+ const table_extra_index = try func.addExtra(jump_table);
+ try func.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
+ try func.mir_extra.ensureUnusedCapacity(func.gpa, depth);
+
+ var value: u32 = lowest.?;
+ while (value <= highest.?) : (value += 1) {
+ const idx: u32 = blk: {
+ for (values.items) |val| {
+ if (val == value) break :blk 1;
+ }
+ break :blk 0;
+ };
+ func.mir_extra.appendAssumeCapacity(idx);
+ }
+ try func.endBlock();
+
+ // 'false' branch (i.e. error set does not have value
+ // ensure we set local to 0 in case the local was re-used.
+ try func.addImm32(0);
+ try func.addLabel(.local_set, result.local.value);
+ try func.addLabel(.br, 1);
+ try func.endBlock();
+
+ // 'true' branch
+ try func.addImm32(1);
+ try func.addLabel(.local_set, result.local.value);
+ try func.addLabel(.br, 0);
+ try func.endBlock();
+
+ return func.finishAir(inst, result, &.{ty_op.operand});
+}
diff --git a/src/clang.zig b/src/clang.zig
index 04261f06f0..f368bb0c3c 100644
--- a/src/clang.zig
+++ b/src/clang.zig
@@ -460,6 +460,9 @@ pub const Expr = opaque {
pub const evaluateAsConstantExpr = ZigClangExpr_EvaluateAsConstantExpr;
extern fn ZigClangExpr_EvaluateAsConstantExpr(*const Expr, *ExprEvalResult, Expr_ConstantExprKind, *const ASTContext) bool;
+
+ pub const castToStringLiteral = ZigClangExpr_castToStringLiteral;
+ extern fn ZigClangExpr_castToStringLiteral(*const Expr) ?*const StringLiteral;
};
pub const FieldDecl = opaque {
@@ -1053,6 +1056,12 @@ pub const InitListExpr = opaque {
pub const getArrayFiller = ZigClangInitListExpr_getArrayFiller;
extern fn ZigClangInitListExpr_getArrayFiller(*const InitListExpr) *const Expr;
+ pub const hasArrayFiller = ZigClangInitListExpr_hasArrayFiller;
+ extern fn ZigClangInitListExpr_hasArrayFiller(*const InitListExpr) bool;
+
+ pub const isStringLiteralInit = ZigClangInitListExpr_isStringLiteralInit;
+ extern fn ZigClangInitListExpr_isStringLiteralInit(*const InitListExpr) bool;
+
pub const getNumInits = ZigClangInitListExpr_getNumInits;
extern fn ZigClangInitListExpr_getNumInits(*const InitListExpr) c_uint;
diff --git a/src/link/NvPtx.zig b/src/link/NvPtx.zig
index c542241cd9..69cd73a602 100644
--- a/src/link/NvPtx.zig
+++ b/src/link/NvPtx.zig
@@ -1,4 +1,4 @@
-//! NVidia PTX (Paralle Thread Execution)
+//! NVidia PTX (Parallel Thread Execution)
//! https://docs.nvidia.com/cuda/parallel-thread-execution/index.html
//! For this we rely on the nvptx backend of LLVM
//! Kernel functions need to be marked both as "export" and "callconv(.Kernel)"
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 2125a8faaa..0fe9ec5e3b 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -1209,6 +1209,11 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
}
}
+ if (wasm.undefs.fetchSwapRemove("__zig_errors_len")) |kv| {
+ const loc = try wasm.createSyntheticSymbol("__zig_errors_len", .data);
+ try wasm.discarded.putNoClobber(wasm.base.allocator, kv.value, loc);
+ _ = wasm.resolved_symbols.swapRemove(kv.value);
+ }
}
// Tries to find a global symbol by its name. Returns null when not found,
@@ -2185,6 +2190,43 @@ fn setupInitFunctions(wasm: *Wasm) !void {
std.sort.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);
}
+/// Generates an atom containing the global error set' size.
+/// This will only be generated if the symbol exists.
+fn setupErrorsLen(wasm: *Wasm) !void {
+ const loc = wasm.findGlobalSymbol("__zig_errors_len") orelse return;
+
+ const errors_len = wasm.base.options.module.?.global_error_set.count();
+ // overwrite existing atom if it already exists (maybe the error set has increased)
+ // if not, allcoate a new atom.
+ const atom_index = if (wasm.symbol_atom.get(loc)) |index| blk: {
+ const atom = wasm.getAtomPtr(index);
+ if (atom.next) |next_atom_index| {
+ const next_atom = wasm.getAtomPtr(next_atom_index);
+ next_atom.prev = atom.prev;
+ atom.next = null;
+ }
+ if (atom.prev) |prev_index| {
+ const prev_atom = wasm.getAtomPtr(prev_index);
+ prev_atom.next = atom.next;
+ atom.prev = null;
+ }
+ atom.deinit(wasm);
+ break :blk index;
+ } else new_atom: {
+ const atom_index = @intCast(Atom.Index, wasm.managed_atoms.items.len);
+ try wasm.symbol_atom.put(wasm.base.allocator, loc, atom_index);
+ try wasm.managed_atoms.append(wasm.base.allocator, undefined);
+ break :new_atom atom_index;
+ };
+ const atom = wasm.getAtomPtr(atom_index);
+ atom.* = Atom.empty;
+ atom.sym_index = loc.index;
+ atom.size = 2;
+ try atom.code.writer(wasm.base.allocator).writeIntLittle(u16, @intCast(u16, errors_len));
+
+ try wasm.parseAtom(atom_index, .{ .data = .read_only });
+}
+
/// Creates a function body for the `__wasm_call_ctors` symbol.
/// Loops over all constructors found in `init_funcs` and calls them
/// respectively based on their priority which was sorted by `setupInitFunctions`.
@@ -3317,6 +3359,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
// So we can rebuild the binary file on each incremental update
defer wasm.resetState();
try wasm.setupInitFunctions();
+ try wasm.setupErrorsLen();
try wasm.setupStart();
try wasm.setupImports();
if (wasm.base.options.module) |mod| {
diff --git a/src/main.zig b/src/main.zig
index 6a83791ca3..66b207aa43 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -402,8 +402,8 @@ const usage_build_generic =
\\ --name [name] Override root name (not a file path)
\\ -O [mode] Choose what to optimize for
\\ Debug (default) Optimizations off, safety on
- \\ ReleaseFast Optimizations on, safety off
- \\ ReleaseSafe Optimizations on, safety on
+ \\ ReleaseFast Optimize for performance, safety off
+ \\ ReleaseSafe Optimize for performance, safety on
\\ ReleaseSmall Optimize for small binary, safety off
\\ --mod [name]:[deps]:[src] Make a module available for dependency under the given name
\\ deps: [dep],[dep],...
diff --git a/src/print_zir.zig b/src/print_zir.zig
index 79c802f936..927d8a8b33 100644
--- a/src/print_zir.zig
+++ b/src/print_zir.zig
@@ -466,6 +466,7 @@ const Writer = struct {
.frame_address,
.breakpoint,
.c_va_start,
+ .in_comptime,
=> try self.writeExtNode(stream, extended),
.builtin_src => {
diff --git a/src/translate_c.zig b/src/translate_c.zig
index 45b9f38b75..9d8dcd80b9 100644
--- a/src/translate_c.zig
+++ b/src/translate_c.zig
@@ -2697,6 +2697,13 @@ fn transInitListExprArray(
return Tag.empty_array.create(c.arena, child_type);
}
+ if (expr.isStringLiteralInit()) {
+ assert(init_count == 1);
+ const init_expr = expr.getInit(0);
+ const string_literal = init_expr.castToStringLiteral().?;
+ return try transStringLiteral(c, scope, string_literal, .used);
+ }
+
const init_node = if (init_count != 0) blk: {
const init_list = try c.arena.alloc(Node, init_count);
@@ -2714,6 +2721,7 @@ fn transInitListExprArray(
break :blk init_node;
} else null;
+ assert(expr.hasArrayFiller());
const filler_val_expr = expr.getArrayFiller();
const filler_node = try Tag.array_filler.create(c.arena, .{
.type = child_type,
@@ -4176,6 +4184,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
try c.global_scope.nodes.append(decl_node);
}
+fn transQualTypeInitializedStringLiteral(c: *Context, elem_ty: Node, string_lit: *const clang.StringLiteral) TypeError!Node {
+ const string_lit_size = string_lit.getLength();
+ const array_size = @intCast(usize, string_lit_size);
+
+ // incomplete array initialized with empty string, will be translated as [1]T{0}
+ // see https://github.com/ziglang/zig/issues/8256
+ if (array_size == 0) return Tag.array_type.create(c.arena, .{ .len = 1, .elem_type = elem_ty });
+
+ return Tag.null_sentinel_array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
+}
+
/// Translate a qualtype for a variable with an initializer. This only matters
/// for incomplete arrays, since the initializer determines the size of the array.
fn transQualTypeInitialized(
@@ -4193,18 +4212,18 @@ fn transQualTypeInitialized(
switch (decl_init.getStmtClass()) {
.StringLiteralClass => {
const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);
- const string_lit_size = string_lit.getLength();
- const array_size = @intCast(usize, string_lit_size);
-
- // incomplete array initialized with empty string, will be translated as [1]T{0}
- // see https://github.com/ziglang/zig/issues/8256
- if (array_size == 0) return Tag.array_type.create(c.arena, .{ .len = 1, .elem_type = elem_ty });
-
- return Tag.null_sentinel_array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
+ return transQualTypeInitializedStringLiteral(c, elem_ty, string_lit);
},
.InitListExprClass => {
const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);
const size = init_expr.getNumInits();
+
+ if (init_expr.isStringLiteralInit()) {
+ assert(size == 1);
+ const string_lit = init_expr.getInit(0).castToStringLiteral().?;
+ return transQualTypeInitializedStringLiteral(c, elem_ty, string_lit);
+ }
+
return Tag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_ty });
},
else => {},
diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp
index ccc4453cdf..699431009f 100644
--- a/src/zig_clang.cpp
+++ b/src/zig_clang.cpp
@@ -2382,6 +2382,12 @@ bool ZigClangExpr_EvaluateAsConstantExpr(const ZigClangExpr *self, ZigClangExprE
return true;
}
+const ZigClangStringLiteral *ZigClangExpr_castToStringLiteral(const struct ZigClangExpr *self) {
+ auto casted_self = reinterpret_cast(self);
+ auto cast = clang::dyn_cast(casted_self);
+ return reinterpret_cast(cast);
+}
+
const ZigClangExpr *ZigClangInitListExpr_getInit(const ZigClangInitListExpr *self, unsigned i) {
auto casted = reinterpret_cast(self);
const clang::Expr *result = casted->getInit(i);
@@ -2394,6 +2400,16 @@ const ZigClangExpr *ZigClangInitListExpr_getArrayFiller(const ZigClangInitListEx
return reinterpret_cast(result);
}
+bool ZigClangInitListExpr_hasArrayFiller(const ZigClangInitListExpr *self) {
+ auto casted = reinterpret_cast(self);
+ return casted->hasArrayFiller();
+}
+
+bool ZigClangInitListExpr_isStringLiteralInit(const ZigClangInitListExpr *self) {
+ auto casted = reinterpret_cast(self);
+ return casted->isStringLiteralInit();
+}
+
const ZigClangFieldDecl *ZigClangInitListExpr_getInitializedFieldInUnion(const ZigClangInitListExpr *self) {
auto casted = reinterpret_cast(self);
const clang::FieldDecl *result = casted->getInitializedFieldInUnion();
diff --git a/src/zig_clang.h b/src/zig_clang.h
index 2fd91163f7..6efde35932 100644
--- a/src/zig_clang.h
+++ b/src/zig_clang.h
@@ -1220,9 +1220,12 @@ ZIG_EXTERN_C bool ZigClangExpr_EvaluateAsFloat(const struct ZigClangExpr *self,
ZigClangAPFloat **result, const struct ZigClangASTContext *ctx);
ZIG_EXTERN_C bool ZigClangExpr_EvaluateAsConstantExpr(const struct ZigClangExpr *,
struct ZigClangExprEvalResult *, ZigClangExpr_ConstantExprKind, const struct ZigClangASTContext *);
+ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangExpr_castToStringLiteral(const struct ZigClangExpr *self);
ZIG_EXTERN_C const ZigClangExpr *ZigClangInitListExpr_getInit(const ZigClangInitListExpr *, unsigned);
ZIG_EXTERN_C const ZigClangExpr *ZigClangInitListExpr_getArrayFiller(const ZigClangInitListExpr *);
+ZIG_EXTERN_C bool ZigClangInitListExpr_hasArrayFiller(const ZigClangInitListExpr *);
+ZIG_EXTERN_C bool ZigClangInitListExpr_isStringLiteralInit(const ZigClangInitListExpr *);
ZIG_EXTERN_C unsigned ZigClangInitListExpr_getNumInits(const ZigClangInitListExpr *);
ZIG_EXTERN_C const ZigClangFieldDecl *ZigClangInitListExpr_getInitializedFieldInUnion(const ZigClangInitListExpr *self);
diff --git a/stage1/zig.h b/stage1/zig.h
index 36f3318650..f73dfb72ef 100644
--- a/stage1/zig.h
+++ b/stage1/zig.h
@@ -253,97 +253,6 @@ typedef char bool;
#define zig_concat(lhs, rhs) lhs##rhs
#define zig_expand_concat(lhs, rhs) zig_concat(lhs, rhs)
-#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
-#include
-#define zig_atomic(type) _Atomic(type)
-#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
-#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
-#define zig_atomicrmw_xchg(obj, arg, order, type) atomic_exchange_explicit (obj, arg, order)
-#define zig_atomicrmw_add(obj, arg, order, type) atomic_fetch_add_explicit (obj, arg, order)
-#define zig_atomicrmw_sub(obj, arg, order, type) atomic_fetch_sub_explicit (obj, arg, order)
-#define zig_atomicrmw_or(obj, arg, order, type) atomic_fetch_or_explicit (obj, arg, order)
-#define zig_atomicrmw_xor(obj, arg, order, type) atomic_fetch_xor_explicit (obj, arg, order)
-#define zig_atomicrmw_and(obj, arg, order, type) atomic_fetch_and_explicit (obj, arg, order)
-#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand (obj, arg, order)
-#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
-#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
-#define zig_atomic_store(obj, arg, order, type) atomic_store_explicit (obj, arg, order)
-#define zig_atomic_load(obj, order, type) atomic_load_explicit (obj, order)
-#define zig_fence(order) atomic_thread_fence(order)
-#elif defined(__GNUC__)
-#define memory_order_relaxed __ATOMIC_RELAXED
-#define memory_order_consume __ATOMIC_CONSUME
-#define memory_order_acquire __ATOMIC_ACQUIRE
-#define memory_order_release __ATOMIC_RELEASE
-#define memory_order_acq_rel __ATOMIC_ACQ_REL
-#define memory_order_seq_cst __ATOMIC_SEQ_CST
-#define zig_atomic(type) type
-#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, false, succ, fail)
-#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) __atomic_compare_exchange_n(obj, &(expected), desired, true , succ, fail)
-#define zig_atomicrmw_xchg(obj, arg, order, type) __atomic_exchange_n(obj, arg, order)
-#define zig_atomicrmw_add(obj, arg, order, type) __atomic_fetch_add (obj, arg, order)
-#define zig_atomicrmw_sub(obj, arg, order, type) __atomic_fetch_sub (obj, arg, order)
-#define zig_atomicrmw_or(obj, arg, order, type) __atomic_fetch_or (obj, arg, order)
-#define zig_atomicrmw_xor(obj, arg, order, type) __atomic_fetch_xor (obj, arg, order)
-#define zig_atomicrmw_and(obj, arg, order, type) __atomic_fetch_and (obj, arg, order)
-#define zig_atomicrmw_nand(obj, arg, order, type) __atomic_fetch_nand(obj, arg, order)
-#define zig_atomicrmw_min(obj, arg, order, type) __atomic_fetch_min (obj, arg, order)
-#define zig_atomicrmw_max(obj, arg, order, type) __atomic_fetch_max (obj, arg, order)
-#define zig_atomic_store(obj, arg, order, type) __atomic_store_n (obj, arg, order)
-#define zig_atomic_load(obj, order, type) __atomic_load_n (obj, order)
-#define zig_fence(order) __atomic_thread_fence(order)
-#elif _MSC_VER && (_M_IX86 || _M_X64)
-#define memory_order_relaxed 0
-#define memory_order_consume 1
-#define memory_order_acquire 2
-#define memory_order_release 3
-#define memory_order_acq_rel 4
-#define memory_order_seq_cst 5
-#define zig_atomic(type) type
-#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_expand_concat(zig_msvc_cmpxchg_, type)(obj, &(expected), desired)
-#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_cmpxchg_strong(obj, expected, desired, succ, fail, type)
-#define zig_atomicrmw_xchg(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xchg_, type)(obj, arg)
-#define zig_atomicrmw_add(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_add_, type)(obj, arg)
-#define zig_atomicrmw_sub(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_sub_, type)(obj, arg)
-#define zig_atomicrmw_or(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_or_, type)(obj, arg)
-#define zig_atomicrmw_xor(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_xor_, type)(obj, arg)
-#define zig_atomicrmw_and(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_and_, type)(obj, arg)
-#define zig_atomicrmw_nand(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_nand_, type)(obj, arg)
-#define zig_atomicrmw_min(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_min_, type)(obj, arg)
-#define zig_atomicrmw_max(obj, arg, order, type) zig_expand_concat(zig_msvc_atomicrmw_max_, type)(obj, arg)
-#define zig_atomic_store(obj, arg, order, type) zig_expand_concat(zig_msvc_atomic_store_, type)(obj, arg)
-#define zig_atomic_load(obj, order, type) zig_expand_concat(zig_msvc_atomic_load_, type)(obj)
-#if _M_X64
-#define zig_fence(order) __faststorefence()
-#else
-#define zig_fence(order) zig_msvc_atomic_barrier()
-#endif
-
-// TODO: _MSC_VER && (_M_ARM || _M_ARM64)
-#else
-#define memory_order_relaxed 0
-#define memory_order_consume 1
-#define memory_order_acquire 2
-#define memory_order_release 3
-#define memory_order_acq_rel 4
-#define memory_order_seq_cst 5
-#define zig_atomic(type) type
-#define zig_cmpxchg_strong(obj, expected, desired, succ, fail, type) zig_unimplemented()
-#define zig_cmpxchg_weak(obj, expected, desired, succ, fail, type) zig_unimplemented()
-#define zig_atomicrmw_xchg(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_add(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_sub(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_or(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_xor(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_and(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_nand(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_min(obj, arg, order, type) zig_unimplemented()
-#define zig_atomicrmw_max(obj, arg, order, type) zig_unimplemented()
-#define zig_atomic_store(obj, arg, order, type) zig_unimplemented()
-#define zig_atomic_load(obj, order, type) zig_unimplemented()
-#define zig_fence(order) zig_unimplemented()
-#endif
-
#if __STDC_VERSION__ >= 201112L
#define zig_noreturn _Noreturn
#elif zig_has_attribute(noreturn) || defined(zig_gnuc)
@@ -502,15 +411,6 @@ typedef ptrdiff_t intptr_t;
#endif
-#define zig_make_small_i8(val) INT8_C(val)
-#define zig_make_small_u8(val) UINT8_C(val)
-#define zig_make_small_i16(val) INT16_C(val)
-#define zig_make_small_u16(val) UINT16_C(val)
-#define zig_make_small_i32(val) INT32_C(val)
-#define zig_make_small_u32(val) UINT32_C(val)
-#define zig_make_small_i64(val) INT64_C(val)
-#define zig_make_small_u64(val) UINT64_C(val)
-
#define zig_minInt_i8 INT8_MIN
#define zig_maxInt_i8 INT8_MAX
#define zig_minInt_u8 UINT8_C(0)
@@ -534,24 +434,24 @@ typedef ptrdiff_t intptr_t;
#define zig_minInt_u(w, bits) zig_intLimit(u, w, min, bits)
#define zig_maxInt_u(w, bits) zig_intLimit(u, w, max, bits)
-#define zig_int_operator(Type, RhsType, operation, operator) \
+#define zig_operator(Type, RhsType, operation, operator) \
static inline Type zig_##operation(Type lhs, RhsType rhs) { \
return lhs operator rhs; \
}
-#define zig_int_basic_operator(Type, operation, operator) \
- zig_int_operator(Type, Type, operation, operator)
-#define zig_int_shift_operator(Type, operation, operator) \
- zig_int_operator(Type, uint8_t, operation, operator)
+#define zig_basic_operator(Type, operation, operator) \
+ zig_operator(Type, Type, operation, operator)
+#define zig_shift_operator(Type, operation, operator) \
+ zig_operator(Type, uint8_t, operation, operator)
#define zig_int_helpers(w) \
- zig_int_basic_operator(uint##w##_t, and_u##w, &) \
- zig_int_basic_operator( int##w##_t, and_i##w, &) \
- zig_int_basic_operator(uint##w##_t, or_u##w, |) \
- zig_int_basic_operator( int##w##_t, or_i##w, |) \
- zig_int_basic_operator(uint##w##_t, xor_u##w, ^) \
- zig_int_basic_operator( int##w##_t, xor_i##w, ^) \
- zig_int_shift_operator(uint##w##_t, shl_u##w, <<) \
- zig_int_shift_operator( int##w##_t, shl_i##w, <<) \
- zig_int_shift_operator(uint##w##_t, shr_u##w, >>) \
+ zig_basic_operator(uint##w##_t, and_u##w, &) \
+ zig_basic_operator( int##w##_t, and_i##w, &) \
+ zig_basic_operator(uint##w##_t, or_u##w, |) \
+ zig_basic_operator( int##w##_t, or_i##w, |) \
+ zig_basic_operator(uint##w##_t, xor_u##w, ^) \
+ zig_basic_operator( int##w##_t, xor_i##w, ^) \
+ zig_shift_operator(uint##w##_t, shl_u##w, <<) \
+ zig_shift_operator( int##w##_t, shl_i##w, <<) \
+ zig_shift_operator(uint##w##_t, shr_u##w, >>) \
\
static inline int##w##_t zig_shr_i##w(int##w##_t lhs, uint8_t rhs) { \
int##w##_t sign_mask = lhs < INT##w##_C(0) ? -INT##w##_C(1) : INT##w##_C(0); \
@@ -576,13 +476,13 @@ typedef ptrdiff_t intptr_t;
? val | zig_minInt_i(w, bits) : val & zig_maxInt_i(w, bits); \
} \
\
- zig_int_basic_operator(uint##w##_t, div_floor_u##w, /) \
+ zig_basic_operator(uint##w##_t, div_floor_u##w, /) \
\
static inline int##w##_t zig_div_floor_i##w(int##w##_t lhs, int##w##_t rhs) { \
return lhs / rhs - (((lhs ^ rhs) & (lhs % rhs)) < INT##w##_C(0)); \
} \
\
- zig_int_basic_operator(uint##w##_t, mod_u##w, %) \
+ zig_basic_operator(uint##w##_t, mod_u##w, %) \
\
static inline int##w##_t zig_mod_i##w(int##w##_t lhs, int##w##_t rhs) { \
int##w##_t rem = lhs % rhs; \
@@ -1253,8 +1153,8 @@ typedef signed __int128 zig_i128;
#define zig_lo_u128(val) ((uint64_t)((val) >> 0))
#define zig_hi_i128(val) (( int64_t)((val) >> 64))
#define zig_lo_i128(val) ((uint64_t)((val) >> 0))
-#define zig_bitcast_u128(val) ((zig_u128)(val))
-#define zig_bitcast_i128(val) ((zig_i128)(val))
+#define zig_bitCast_u128(val) ((zig_u128)(val))
+#define zig_bitCast_i128(val) ((zig_i128)(val))
#define zig_cmp_int128(Type) \
static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
return (lhs > rhs) - (lhs < rhs); \
@@ -1288,8 +1188,8 @@ typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128;
#define zig_lo_u128(val) ((val).lo)
#define zig_hi_i128(val) ((val).hi)
#define zig_lo_i128(val) ((val).lo)
-#define zig_bitcast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo)
-#define zig_bitcast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo)
+#define zig_bitCast_u128(val) zig_make_u128((uint64_t)(val).hi, (val).lo)
+#define zig_bitCast_i128(val) zig_make_i128(( int64_t)(val).hi, (val).lo)
#define zig_cmp_int128(Type) \
static inline int32_t zig_cmp_##Type(zig_##Type lhs, zig_##Type rhs) { \
return (lhs.hi == rhs.hi) \
@@ -1303,9 +1203,6 @@ typedef struct { zig_align(16) int64_t hi; uint64_t lo; } zig_i128;
#endif /* zig_has_int128 */
-#define zig_make_small_u128(val) zig_make_u128(0, val)
-#define zig_make_small_i128(val) zig_make_i128((val) < 0 ? -INT64_C(1) : INT64_C(0), val)
-
#define zig_minInt_u128 zig_make_u128(zig_minInt_u64, zig_minInt_u64)
#define zig_maxInt_u128 zig_make_u128(zig_maxInt_u64, zig_maxInt_u64)
#define zig_minInt_i128 zig_make_i128(zig_minInt_i64, zig_minInt_u64)
@@ -1466,18 +1363,18 @@ static zig_i128 zig_mul_i128(zig_i128 lhs, zig_i128 rhs) {
}
static zig_u128 zig_mul_u128(zig_u128 lhs, zig_u128 rhs) {
- return zig_bitcast_u128(zig_mul_i128(zig_bitcast_i128(lhs), zig_bitcast_i128(rhs)));
+ return zig_bitCast_u128(zig_mul_i128(zig_bitCast_i128(lhs), zig_bitCast_i128(rhs)));
}
zig_extern zig_u128 __udivti3(zig_u128 lhs, zig_u128 rhs);
static zig_u128 zig_div_trunc_u128(zig_u128 lhs, zig_u128 rhs) {
return __udivti3(lhs, rhs);
-};
+}
zig_extern zig_i128 __divti3(zig_i128 lhs, zig_i128 rhs);
static zig_i128 zig_div_trunc_i128(zig_i128 lhs, zig_i128 rhs) {
return __divti3(lhs, rhs);
-};
+}
zig_extern zig_u128 __umodti3(zig_u128 lhs, zig_u128 rhs);
static zig_u128 zig_rem_u128(zig_u128 lhs, zig_u128 rhs) {
@@ -1503,10 +1400,6 @@ static inline zig_i128 zig_div_floor_i128(zig_i128 lhs, zig_i128 rhs) {
#define zig_div_floor_u128 zig_div_trunc_u128
#define zig_mod_u128 zig_rem_u128
-static inline zig_u128 zig_nand_u128(zig_u128 lhs, zig_u128 rhs) {
- return zig_not_u128(zig_and_u128(lhs, rhs), 128);
-}
-
static inline zig_u128 zig_min_u128(zig_u128 lhs, zig_u128 rhs) {
return zig_cmp_u128(lhs, rhs) < INT32_C(0) ? lhs : rhs;
}
@@ -1538,7 +1431,7 @@ static inline zig_u128 zig_shlw_u128(zig_u128 lhs, uint8_t rhs, uint8_t bits) {
}
static inline zig_i128 zig_shlw_i128(zig_i128 lhs, uint8_t rhs, uint8_t bits) {
- return zig_wrap_i128(zig_bitcast_i128(zig_shl_u128(zig_bitcast_u128(lhs), rhs)), bits);
+ return zig_wrap_i128(zig_bitCast_i128(zig_shl_u128(zig_bitCast_u128(lhs), rhs)), bits);
}
static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
@@ -1546,7 +1439,7 @@ static inline zig_u128 zig_addw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
}
static inline zig_i128 zig_addw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
- return zig_wrap_i128(zig_bitcast_i128(zig_add_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
+ return zig_wrap_i128(zig_bitCast_i128(zig_add_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
}
static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
@@ -1554,7 +1447,7 @@ static inline zig_u128 zig_subw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
}
static inline zig_i128 zig_subw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
- return zig_wrap_i128(zig_bitcast_i128(zig_sub_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
+ return zig_wrap_i128(zig_bitCast_i128(zig_sub_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
}
static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
@@ -1562,7 +1455,7 @@ static inline zig_u128 zig_mulw_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
}
static inline zig_i128 zig_mulw_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
- return zig_wrap_i128(zig_bitcast_i128(zig_mul_u128(zig_bitcast_u128(lhs), zig_bitcast_u128(rhs))), bits);
+ return zig_wrap_i128(zig_bitCast_i128(zig_mul_u128(zig_bitCast_u128(lhs), zig_bitCast_u128(rhs))), bits);
}
#if zig_has_int128
@@ -1697,7 +1590,7 @@ static inline bool zig_shlo_u128(zig_u128 *res, zig_u128 lhs, uint8_t rhs, uint8
static inline bool zig_shlo_i128(zig_i128 *res, zig_i128 lhs, uint8_t rhs, uint8_t bits) {
*res = zig_shlw_i128(lhs, rhs, bits);
- zig_i128 mask = zig_bitcast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)));
+ zig_i128 mask = zig_bitCast_i128(zig_shl_u128(zig_maxInt_u128, bits - rhs - UINT8_C(1)));
return zig_cmp_i128(zig_and_i128(lhs, mask), zig_make_i128(0, 0)) != INT32_C(0) &&
zig_cmp_i128(zig_and_i128(lhs, mask), mask) != INT32_C(0);
}
@@ -1711,7 +1604,7 @@ static inline zig_u128 zig_shls_u128(zig_u128 lhs, zig_u128 rhs, uint8_t bits) {
static inline zig_i128 zig_shls_i128(zig_i128 lhs, zig_i128 rhs, uint8_t bits) {
zig_i128 res;
- if (zig_cmp_u128(zig_bitcast_u128(rhs), zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_i128(rhs), bits)) return res;
+ if (zig_cmp_u128(zig_bitCast_u128(rhs), zig_make_u128(0, bits)) < INT32_C(0) && !zig_shlo_i128(&res, lhs, (uint8_t)zig_lo_i128(rhs), bits)) return res;
return zig_cmp_i128(lhs, zig_make_i128(0, 0)) < INT32_C(0) ? zig_minInt_i(128, bits) : zig_maxInt_i(128, bits);
}
@@ -1755,7 +1648,7 @@ static inline uint8_t zig_clz_u128(zig_u128 val, uint8_t bits) {
}
static inline uint8_t zig_clz_i128(zig_i128 val, uint8_t bits) {
- return zig_clz_u128(zig_bitcast_u128(val), bits);
+ return zig_clz_u128(zig_bitCast_u128(val), bits);
}
static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) {
@@ -1764,7 +1657,7 @@ static inline uint8_t zig_ctz_u128(zig_u128 val, uint8_t bits) {
}
static inline uint8_t zig_ctz_i128(zig_i128 val, uint8_t bits) {
- return zig_ctz_u128(zig_bitcast_u128(val), bits);
+ return zig_ctz_u128(zig_bitCast_u128(val), bits);
}
static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) {
@@ -1773,7 +1666,7 @@ static inline uint8_t zig_popcount_u128(zig_u128 val, uint8_t bits) {
}
static inline uint8_t zig_popcount_i128(zig_i128 val, uint8_t bits) {
- return zig_popcount_u128(zig_bitcast_u128(val), bits);
+ return zig_popcount_u128(zig_bitCast_u128(val), bits);
}
static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) {
@@ -1788,7 +1681,7 @@ static inline zig_u128 zig_byte_swap_u128(zig_u128 val, uint8_t bits) {
}
static inline zig_i128 zig_byte_swap_i128(zig_i128 val, uint8_t bits) {
- return zig_bitcast_i128(zig_byte_swap_u128(zig_bitcast_u128(val), bits));
+ return zig_bitCast_i128(zig_byte_swap_u128(zig_bitCast_u128(val), bits));
}
static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) {
@@ -1798,7 +1691,7 @@ static inline zig_u128 zig_bit_reverse_u128(zig_u128 val, uint8_t bits) {
}
static inline zig_i128 zig_bit_reverse_i128(zig_i128 val, uint8_t bits) {
- return zig_bitcast_i128(zig_bit_reverse_u128(zig_bitcast_u128(val), bits));
+ return zig_bitCast_i128(zig_bit_reverse_u128(zig_bitCast_u128(val), bits));
}
/* ========================== Big Integer Support =========================== */
@@ -1972,6 +1865,243 @@ static inline int32_t zig_cmp_big(const void *lhs, const void *rhs, bool is_sign
return 0;
}
+static inline void zig_and_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
+ uint8_t *res_bytes = res;
+ const uint8_t *lhs_bytes = lhs;
+ const uint8_t *rhs_bytes = rhs;
+ uint16_t byte_offset = 0;
+ uint16_t remaining_bytes = zig_int_bytes(bits);
+ (void)is_signed;
+
+ while (remaining_bytes >= 128 / CHAR_BIT) {
+ zig_u128 res_limb;
+ zig_u128 lhs_limb;
+ zig_u128 rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_and_u128(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 128 / CHAR_BIT;
+ byte_offset += 128 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 64 / CHAR_BIT) {
+ uint64_t res_limb;
+ uint64_t lhs_limb;
+ uint64_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_and_u64(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 64 / CHAR_BIT;
+ byte_offset += 64 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 32 / CHAR_BIT) {
+ uint32_t res_limb;
+ uint32_t lhs_limb;
+ uint32_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_and_u32(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 32 / CHAR_BIT;
+ byte_offset += 32 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 16 / CHAR_BIT) {
+ uint16_t res_limb;
+ uint16_t lhs_limb;
+ uint16_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_and_u16(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 16 / CHAR_BIT;
+ byte_offset += 16 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 8 / CHAR_BIT) {
+ uint8_t res_limb;
+ uint8_t lhs_limb;
+ uint8_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_and_u8(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 8 / CHAR_BIT;
+ byte_offset += 8 / CHAR_BIT;
+ }
+}
+
+static inline void zig_or_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
+ uint8_t *res_bytes = res;
+ const uint8_t *lhs_bytes = lhs;
+ const uint8_t *rhs_bytes = rhs;
+ uint16_t byte_offset = 0;
+ uint16_t remaining_bytes = zig_int_bytes(bits);
+ (void)is_signed;
+
+ while (remaining_bytes >= 128 / CHAR_BIT) {
+ zig_u128 res_limb;
+ zig_u128 lhs_limb;
+ zig_u128 rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_or_u128(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 128 / CHAR_BIT;
+ byte_offset += 128 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 64 / CHAR_BIT) {
+ uint64_t res_limb;
+ uint64_t lhs_limb;
+ uint64_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_or_u64(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 64 / CHAR_BIT;
+ byte_offset += 64 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 32 / CHAR_BIT) {
+ uint32_t res_limb;
+ uint32_t lhs_limb;
+ uint32_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_or_u32(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 32 / CHAR_BIT;
+ byte_offset += 32 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 16 / CHAR_BIT) {
+ uint16_t res_limb;
+ uint16_t lhs_limb;
+ uint16_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_or_u16(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 16 / CHAR_BIT;
+ byte_offset += 16 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 8 / CHAR_BIT) {
+ uint8_t res_limb;
+ uint8_t lhs_limb;
+ uint8_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_or_u8(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 8 / CHAR_BIT;
+ byte_offset += 8 / CHAR_BIT;
+ }
+}
+
+static inline void zig_xor_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
+ uint8_t *res_bytes = res;
+ const uint8_t *lhs_bytes = lhs;
+ const uint8_t *rhs_bytes = rhs;
+ uint16_t byte_offset = 0;
+ uint16_t remaining_bytes = zig_int_bytes(bits);
+ (void)is_signed;
+
+ while (remaining_bytes >= 128 / CHAR_BIT) {
+ zig_u128 res_limb;
+ zig_u128 lhs_limb;
+ zig_u128 rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_xor_u128(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 128 / CHAR_BIT;
+ byte_offset += 128 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 64 / CHAR_BIT) {
+ uint64_t res_limb;
+ uint64_t lhs_limb;
+ uint64_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_xor_u64(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 64 / CHAR_BIT;
+ byte_offset += 64 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 32 / CHAR_BIT) {
+ uint32_t res_limb;
+ uint32_t lhs_limb;
+ uint32_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_xor_u32(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 32 / CHAR_BIT;
+ byte_offset += 32 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 16 / CHAR_BIT) {
+ uint16_t res_limb;
+ uint16_t lhs_limb;
+ uint16_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_xor_u16(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 16 / CHAR_BIT;
+ byte_offset += 16 / CHAR_BIT;
+ }
+
+ while (remaining_bytes >= 8 / CHAR_BIT) {
+ uint8_t res_limb;
+ uint8_t lhs_limb;
+ uint8_t rhs_limb;
+
+ memcpy(&lhs_limb, &lhs_bytes[byte_offset], sizeof(lhs_limb));
+ memcpy(&rhs_limb, &rhs_bytes[byte_offset], sizeof(rhs_limb));
+ res_limb = zig_xor_u8(lhs_limb, rhs_limb);
+ memcpy(&res_bytes[byte_offset], &res_limb, sizeof(res_limb));
+
+ remaining_bytes -= 8 / CHAR_BIT;
+ byte_offset += 8 / CHAR_BIT;
+ }
+}
+
static inline bool zig_addo_big(void *res, const void *lhs, const void *rhs, bool is_signed, uint16_t bits) {
uint8_t *res_bytes = res;
const uint8_t *lhs_bytes = lhs;
@@ -2827,24 +2957,20 @@ long double __cdecl nanl(char const* input);
#endif
#if (zig_has_builtin(nan) && zig_has_builtin(nans) && zig_has_builtin(inf)) || defined(zig_gnuc)
-#define zig_has_float_builtins 1
-#define zig_make_special_f16(sign, name, arg, repr) sign zig_make_f16(__builtin_##name, )(arg)
-#define zig_make_special_f32(sign, name, arg, repr) sign zig_make_f32(__builtin_##name, )(arg)
-#define zig_make_special_f64(sign, name, arg, repr) sign zig_make_f64(__builtin_##name, )(arg)
-#define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80(__builtin_##name, )(arg)
+#define zig_make_special_f16(sign, name, arg, repr) sign zig_make_f16 (__builtin_##name, )(arg)
+#define zig_make_special_f32(sign, name, arg, repr) sign zig_make_f32 (__builtin_##name, )(arg)
+#define zig_make_special_f64(sign, name, arg, repr) sign zig_make_f64 (__builtin_##name, )(arg)
+#define zig_make_special_f80(sign, name, arg, repr) sign zig_make_f80 (__builtin_##name, )(arg)
#define zig_make_special_f128(sign, name, arg, repr) sign zig_make_f128(__builtin_##name, )(arg)
#else
-#define zig_has_float_builtins 0
-#define zig_make_special_f16(sign, name, arg, repr) zig_float_from_repr_f16(repr)
-#define zig_make_special_f32(sign, name, arg, repr) zig_float_from_repr_f32(repr)
-#define zig_make_special_f64(sign, name, arg, repr) zig_float_from_repr_f64(repr)
-#define zig_make_special_f80(sign, name, arg, repr) zig_float_from_repr_f80(repr)
-#define zig_make_special_f128(sign, name, arg, repr) zig_float_from_repr_f128(repr)
+#define zig_make_special_f16(sign, name, arg, repr) zig_bitCast_f16 (repr)
+#define zig_make_special_f32(sign, name, arg, repr) zig_bitCast_f32 (repr)
+#define zig_make_special_f64(sign, name, arg, repr) zig_bitCast_f64 (repr)
+#define zig_make_special_f80(sign, name, arg, repr) zig_bitCast_f80 (repr)
+#define zig_make_special_f128(sign, name, arg, repr) zig_bitCast_f128(repr)
#endif
#define zig_has_f16 1
-#define zig_bitSizeOf_f16 16
-typedef uint16_t zig_repr_f16;
#define zig_libc_name_f16(name) __##name##h
#define zig_init_special_f16(sign, name, arg, repr) zig_make_special_f16(sign, name, arg, repr)
#if FLT_MANT_DIG == 11
@@ -2854,10 +2980,6 @@ typedef float zig_f16;
typedef double zig_f16;
#define zig_make_f16(fp, repr) fp
#elif LDBL_MANT_DIG == 11
-#define zig_bitSizeOf_c_longdouble 16
-#ifndef ZIG_TARGET_ABI_MSVC
-typedef zig_repr_f16 zig_repr_c_longdouble;
-#endif
typedef long double zig_f16;
#define zig_make_f16(fp, repr) fp##l
#elif FLT16_MANT_DIG == 11 && (zig_has_builtin(inff16) || defined(zig_gnuc))
@@ -2869,8 +2991,8 @@ typedef __fp16 zig_f16;
#else
#undef zig_has_f16
#define zig_has_f16 0
-#define zig_bitSizeOf_repr_f16 16
-typedef zig_repr_f16 zig_f16;
+#define zig_repr_f16 u16
+typedef uint16_t zig_f16;
#define zig_make_f16(fp, repr) repr
#undef zig_make_special_f16
#define zig_make_special_f16(sign, name, arg, repr) repr
@@ -2878,15 +3000,12 @@ typedef zig_repr_f16 zig_f16;
#define zig_init_special_f16(sign, name, arg, repr) repr
#endif
#if __APPLE__ && (defined(__i386__) || defined(__x86_64__))
-typedef zig_repr_f16 zig_compiler_rt_f16;
+typedef uint16_t zig_compiler_rt_f16;
#else
typedef zig_f16 zig_compiler_rt_f16;
#endif
-#define zig_compiler_rt_abbrev_zig_compiler_rt_f16 zig_compiler_rt_abbrev_zig_f16
#define zig_has_f32 1
-#define zig_bitSizeOf_f32 32
-typedef uint32_t zig_repr_f32;
#define zig_libc_name_f32(name) name##f
#if _MSC_VER
#define zig_init_special_f32(sign, name, arg, repr) sign zig_make_f32(zig_msvc_flt_##name, )
@@ -2900,10 +3019,6 @@ typedef float zig_f32;
typedef double zig_f32;
#define zig_make_f32(fp, repr) fp
#elif LDBL_MANT_DIG == 24
-#define zig_bitSizeOf_c_longdouble 32
-#ifndef ZIG_TARGET_ABI_MSVC
-typedef zig_repr_f32 zig_repr_c_longdouble;
-#endif
typedef long double zig_f32;
#define zig_make_f32(fp, repr) fp##l
#elif FLT32_MANT_DIG == 24
@@ -2912,8 +3027,8 @@ typedef _Float32 zig_f32;
#else
#undef zig_has_f32
#define zig_has_f32 0
-#define zig_bitSizeOf_repr_f32 32
-typedef zig_repr_f32 zig_f32;
+#define zig_repr_f32 u32
+ypedef uint32_t zig_f32;
#define zig_make_f32(fp, repr) repr
#undef zig_make_special_f32
#define zig_make_special_f32(sign, name, arg, repr) repr
@@ -2922,20 +3037,12 @@ typedef zig_repr_f32 zig_f32;
#endif
#define zig_has_f64 1
-#define zig_bitSizeOf_f64 64
-typedef uint64_t zig_repr_f64;
#define zig_libc_name_f64(name) name
#if _MSC_VER
-#ifdef ZIG_TARGET_ABI_MSVC
-#define zig_bitSizeOf_c_longdouble 64
-#ifndef ZIG_TARGET_ABI_MSVC
-typedef zig_repr_f64 zig_repr_c_longdouble;
-#endif
-#endif
#define zig_init_special_f64(sign, name, arg, repr) sign zig_make_f64(zig_msvc_flt_##name, )
-#else /* _MSC_VER */
+#else
#define zig_init_special_f64(sign, name, arg, repr) zig_make_special_f64(sign, name, arg, repr)
-#endif /* _MSC_VER */
+#endif
#if FLT_MANT_DIG == 53
typedef float zig_f64;
#define zig_make_f64(fp, repr) fp##f
@@ -2943,10 +3050,6 @@ typedef float zig_f64;
typedef double zig_f64;
#define zig_make_f64(fp, repr) fp
#elif LDBL_MANT_DIG == 53
-#define zig_bitSizeOf_c_longdouble 64
-#ifndef ZIG_TARGET_ABI_MSVC
-typedef zig_repr_f64 zig_repr_c_longdouble;
-#endif
typedef long double zig_f64;
#define zig_make_f64(fp, repr) fp##l
#elif FLT64_MANT_DIG == 53
@@ -2958,8 +3061,8 @@ typedef _Float32x zig_f64;
#else
#undef zig_has_f64
#define zig_has_f64 0
-#define zig_bitSizeOf_repr_f64 64
-typedef zig_repr_f64 zig_f64;
+#define zig_repr_f64 u64
+typedef uint64_t zig_f64;
#define zig_make_f64(fp, repr) repr
#undef zig_make_special_f64
#define zig_make_special_f64(sign, name, arg, repr) repr
@@ -2968,8 +3071,6 @@ typedef zig_repr_f64 zig_f64;
#endif
#define zig_has_f80 1
-#define zig_bitSizeOf_f80 80
-typedef zig_u128 zig_repr_f80;
#define zig_libc_name_f80(name) __##name##x
#define zig_init_special_f80(sign, name, arg, repr) zig_make_special_f80(sign, name, arg, repr)
#if FLT_MANT_DIG == 64
@@ -2979,10 +3080,6 @@ typedef float zig_f80;
typedef double zig_f80;
#define zig_make_f80(fp, repr) fp
#elif LDBL_MANT_DIG == 64
-#define zig_bitSizeOf_c_longdouble 80
-#ifndef ZIG_TARGET_ABI_MSVC
-typedef zig_repr_f80 zig_repr_c_longdouble;
-#endif
typedef long double zig_f80;
#define zig_make_f80(fp, repr) fp##l
#elif FLT80_MANT_DIG == 64
@@ -2997,8 +3094,8 @@ typedef __float80 zig_f80;
#else
#undef zig_has_f80
#define zig_has_f80 0
-#define zig_bitSizeOf_repr_f80 128
-typedef zig_repr_f80 zig_f80;
+#define zig_repr_f80 u128
+typedef zig_u128 zig_f80;
#define zig_make_f80(fp, repr) repr
#undef zig_make_special_f80
#define zig_make_special_f80(sign, name, arg, repr) repr
@@ -3007,8 +3104,6 @@ typedef zig_repr_f80 zig_f80;
#endif
#define zig_has_f128 1
-#define zig_bitSizeOf_f128 128
-typedef zig_u128 zig_repr_f128;
#define zig_libc_name_f128(name) name##q
#define zig_init_special_f128(sign, name, arg, repr) zig_make_special_f128(sign, name, arg, repr)
#if FLT_MANT_DIG == 113
@@ -3018,10 +3113,6 @@ typedef float zig_f128;
typedef double zig_f128;
#define zig_make_f128(fp, repr) fp
#elif LDBL_MANT_DIG == 113
-#define zig_bitSizeOf_c_longdouble 128
-#ifndef ZIG_TARGET_ABI_MSVC
-typedef zig_repr_f128 zig_repr_c_longdouble;
-#endif
typedef long double zig_f128;
#define zig_make_f128(fp, repr) fp##l
#elif FLT128_MANT_DIG == 113
@@ -3038,50 +3129,49 @@ typedef __float128 zig_f128;
#else
#undef zig_has_f128
#define zig_has_f128 0
-#define zig_bitSizeOf_repr_f128 128
-typedef zig_repr_f128 zig_f128;
-#define zig_make_f128(fp, repr) repr
#undef zig_make_special_f128
-#define zig_make_special_f128(sign, name, arg, repr) repr
#undef zig_init_special_f128
+#if __APPLE__ || defined(__aarch64__)
+typedef __attribute__((__vector_size__(2 * sizeof(uint64_t)))) uint64_t zig_v2u64;
+zig_basic_operator(zig_v2u64, xor_v2u64, ^)
+#define zig_repr_f128 v2u64
+typedef zig_v2u64 zig_f128;
+#define zig_make_f128_zig_make_u128(hi, lo) (zig_f128){ lo, hi }
+#define zig_make_f128_zig_init_u128 zig_make_f128_zig_make_u128
+#define zig_make_f128(fp, repr) zig_make_f128_##repr
+#define zig_make_special_f128(sign, name, arg, repr) zig_make_f128_##repr
+#define zig_init_special_f128(sign, name, arg, repr) zig_make_f128_##repr
+#else
+#define zig_repr_f128 u128
+typedef zig_u128 zig_f128;
+#define zig_make_f128(fp, repr) repr
+#define zig_make_special_f128(sign, name, arg, repr) repr
#define zig_init_special_f128(sign, name, arg, repr) repr
#endif
+#endif
-#ifdef zig_bitSizeOf_c_longdouble
-
-#define zig_has_c_longdouble 1
-#ifdef ZIG_TARGET_ABI_MSVC
-#undef zig_bitSizeOf_c_longdouble
-#define zig_bitSizeOf_c_longdouble 64
+#if !_MSC_VER && defined(ZIG_TARGET_ABI_MSVC)
+/* Emulate msvc abi on a gnu compiler */
typedef zig_f64 zig_c_longdouble;
-typedef zig_repr_f64 zig_repr_c_longdouble;
+#elif _MSC_VER && !defined(ZIG_TARGET_ABI_MSVC)
+/* Emulate gnu abi on an msvc compiler */
+typedef zig_f128 zig_c_longdouble;
#else
+/* Target and compiler abi match */
typedef long double zig_c_longdouble;
#endif
-#else /* zig_bitSizeOf_c_longdouble */
-
-#define zig_has_c_longdouble 0
-#define zig_bitSizeOf_repr_c_longdouble 128
-typedef zig_f128 zig_c_longdouble;
-typedef zig_repr_f128 zig_repr_c_longdouble;
-
-#endif /* zig_bitSizeOf_c_longdouble */
-
-#if !zig_has_float_builtins
-#define zig_float_from_repr(Type) \
- static inline zig_##Type zig_float_from_repr_##Type(zig_repr_##Type repr) { \
+#define zig_bitCast_float(Type, ReprType) \
+ static inline zig_##Type zig_bitCast_##Type(ReprType repr) { \
zig_##Type result; \
memcpy(&result, &repr, sizeof(result)); \
return result; \
}
-
-zig_float_from_repr(f16)
-zig_float_from_repr(f32)
-zig_float_from_repr(f64)
-zig_float_from_repr(f80)
-zig_float_from_repr(f128)
-#endif
+zig_bitCast_float(f16, uint16_t)
+zig_bitCast_float(f32, uint32_t)
+zig_bitCast_float(f64, uint64_t)
+zig_bitCast_float(f80, zig_u128)
+zig_bitCast_float(f128, zig_u128)
#define zig_cast_f16 (zig_f16)
#define zig_cast_f32 (zig_f32)
@@ -3095,44 +3185,53 @@ zig_float_from_repr(f128)
#define zig_cast_f128 (zig_f128)
#endif
-#define zig_convert_builtin(ResType, operation, ArgType, version) \
- zig_extern ResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \
- zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ArgType);
-zig_convert_builtin(zig_compiler_rt_f16, trunc, zig_f32, 2)
-zig_convert_builtin(zig_compiler_rt_f16, trunc, zig_f64, 2)
-zig_convert_builtin(zig_f16, trunc, zig_f80, 2)
-zig_convert_builtin(zig_f16, trunc, zig_f128, 2)
-zig_convert_builtin(zig_f32, extend, zig_compiler_rt_f16, 2)
-zig_convert_builtin(zig_f32, trunc, zig_f64, 2)
-zig_convert_builtin(zig_f32, trunc, zig_f80, 2)
-zig_convert_builtin(zig_f32, trunc, zig_f128, 2)
-zig_convert_builtin(zig_f64, extend, zig_compiler_rt_f16, 2)
-zig_convert_builtin(zig_f64, extend, zig_f32, 2)
-zig_convert_builtin(zig_f64, trunc, zig_f80, 2)
-zig_convert_builtin(zig_f64, trunc, zig_f128, 2)
-zig_convert_builtin(zig_f80, extend, zig_f16, 2)
-zig_convert_builtin(zig_f80, extend, zig_f32, 2)
-zig_convert_builtin(zig_f80, extend, zig_f64, 2)
-zig_convert_builtin(zig_f80, trunc, zig_f128, 2)
-zig_convert_builtin(zig_f128, extend, zig_f16, 2)
-zig_convert_builtin(zig_f128, extend, zig_f32, 2)
-zig_convert_builtin(zig_f128, extend, zig_f64, 2)
-zig_convert_builtin(zig_f128, extend, zig_f80, 2)
+#define zig_convert_builtin(ExternResType, ResType, operation, ExternArgType, ArgType, version) \
+ zig_extern ExternResType zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \
+ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(ExternArgType); \
+ static inline ResType zig_expand_concat(zig_expand_concat(zig_##operation, \
+ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType)(ArgType arg) { \
+ ResType res; \
+ ExternResType extern_res; \
+ ExternArgType extern_arg; \
+ memcpy(&extern_arg, &arg, sizeof(extern_arg)); \
+ extern_res = zig_expand_concat(zig_expand_concat(zig_expand_concat(__##operation, \
+ zig_compiler_rt_abbrev_##ArgType), zig_compiler_rt_abbrev_##ResType), version)(extern_arg); \
+ memcpy(&res, &extern_res, sizeof(res)); \
+ return extern_res; \
+ }
+zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f32, zig_f32, 2)
+zig_convert_builtin(zig_compiler_rt_f16, zig_f16, trunc, zig_f64, zig_f64, 2)
+zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f80, zig_f80, 2)
+zig_convert_builtin(zig_f16, zig_f16, trunc, zig_f128, zig_f128, 2)
+zig_convert_builtin(zig_f32, zig_f32, extend, zig_compiler_rt_f16, zig_f16, 2)
+zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f64, zig_f64, 2)
+zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f80, zig_f80, 2)
+zig_convert_builtin(zig_f32, zig_f32, trunc, zig_f128, zig_f128, 2)
+zig_convert_builtin(zig_f64, zig_f64, extend, zig_compiler_rt_f16, zig_f16, 2)
+zig_convert_builtin(zig_f64, zig_f64, extend, zig_f32, zig_f32, 2)
+zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f80, zig_f80, 2)
+zig_convert_builtin(zig_f64, zig_f64, trunc, zig_f128, zig_f128, 2)
+zig_convert_builtin(zig_f80, zig_f80, extend, zig_f16, zig_f16, 2)
+zig_convert_builtin(zig_f80, zig_f80, extend, zig_f32, zig_f32, 2)
+zig_convert_builtin(zig_f80, zig_f80, extend, zig_f64, zig_f64, 2)
+zig_convert_builtin(zig_f80, zig_f80, trunc, zig_f128, zig_f128, 2)
+zig_convert_builtin(zig_f128, zig_f128, extend, zig_f16, zig_f16, 2)
+zig_convert_builtin(zig_f128, zig_f128, extend, zig_f32, zig_f32, 2)
+zig_convert_builtin(zig_f128, zig_f128, extend, zig_f64, zig_f64, 2)
+zig_convert_builtin(zig_f128, zig_f128, extend, zig_f80, zig_f80, 2)
-#define zig_float_negate_builtin_0(w) \
+#define zig_float_negate_builtin_0(w, c, sb) \
+ zig_expand_concat(zig_xor_, zig_repr_f##w)(arg, zig_make_f##w(-0x0.0p0, c sb))
+#define zig_float_negate_builtin_1(w, c, sb) -arg
+#define zig_float_negate_builtin(w, c, sb) \
static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \
- return zig_expand_concat(zig_xor_u, zig_bitSizeOf_repr_f##w)( \
- arg, \
- zig_expand_concat(zig_shl_u, zig_bitSizeOf_repr_f##w)( \
- zig_expand_concat(zig_make_small_u, zig_bitSizeOf_repr_f##w)(1), \
- UINT8_C(w - 1) \
- ) \
- ); \
- }
-#define zig_float_negate_builtin_1(w) \
- static inline zig_f##w zig_neg_f##w(zig_f##w arg) { \
- return -arg; \
+ return zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w, c, sb); \
}
+zig_float_negate_builtin(16, , UINT16_C(1) << 15 )
+zig_float_negate_builtin(32, , UINT32_C(1) << 31 )
+zig_float_negate_builtin(64, , UINT64_C(1) << 63 )
+zig_float_negate_builtin(80, zig_make_u128, (UINT64_C(1) << 15, UINT64_C(0)))
+zig_float_negate_builtin(128, zig_make_u128, (UINT64_C(1) << 63, UINT64_C(0)))
#define zig_float_less_builtin_0(Type, operation) \
zig_extern int32_t zig_expand_concat(zig_expand_concat(__##operation, \
@@ -3164,19 +3263,18 @@ zig_convert_builtin(zig_f128, extend, zig_f80, 2)
}
#define zig_float_builtins(w) \
- zig_convert_builtin( int32_t, fix, zig_f##w, ) \
- zig_convert_builtin(uint32_t, fixuns, zig_f##w, ) \
- zig_convert_builtin( int64_t, fix, zig_f##w, ) \
- zig_convert_builtin(uint64_t, fixuns, zig_f##w, ) \
- zig_convert_builtin(zig_i128, fix, zig_f##w, ) \
- zig_convert_builtin(zig_u128, fixuns, zig_f##w, ) \
- zig_convert_builtin(zig_f##w, float, int32_t, ) \
- zig_convert_builtin(zig_f##w, floatun, uint32_t, ) \
- zig_convert_builtin(zig_f##w, float, int64_t, ) \
- zig_convert_builtin(zig_f##w, floatun, uint64_t, ) \
- zig_convert_builtin(zig_f##w, float, zig_i128, ) \
- zig_convert_builtin(zig_f##w, floatun, zig_u128, ) \
- zig_expand_concat(zig_float_negate_builtin_, zig_has_f##w)(w) \
+ zig_convert_builtin( int32_t, int32_t, fix, zig_f##w, zig_f##w, ) \
+ zig_convert_builtin(uint32_t, uint32_t, fixuns, zig_f##w, zig_f##w, ) \
+ zig_convert_builtin( int64_t, int64_t, fix, zig_f##w, zig_f##w, ) \
+ zig_convert_builtin(uint64_t, uint64_t, fixuns, zig_f##w, zig_f##w, ) \
+ zig_convert_builtin(zig_i128, zig_i128, fix, zig_f##w, zig_f##w, ) \
+ zig_convert_builtin(zig_u128, zig_u128, fixuns, zig_f##w, zig_f##w, ) \
+ zig_convert_builtin(zig_f##w, zig_f##w, float, int32_t, int32_t, ) \
+ zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint32_t, uint32_t, ) \
+ zig_convert_builtin(zig_f##w, zig_f##w, float, int64_t, int64_t, ) \
+ zig_convert_builtin(zig_f##w, zig_f##w, floatun, uint64_t, uint64_t, ) \
+ zig_convert_builtin(zig_f##w, zig_f##w, float, zig_i128, zig_i128, ) \
+ zig_convert_builtin(zig_f##w, zig_f##w, floatun, zig_u128, zig_u128, ) \
zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, cmp) \
zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, ne) \
zig_expand_concat(zig_float_less_builtin_, zig_has_f##w)(f##w, eq) \
@@ -3224,9 +3322,238 @@ zig_float_builtins(64)
zig_float_builtins(80)
zig_float_builtins(128)
+/* ============================ Atomics Support ============================= */
+
+/* Note that atomics should be implemented as macros because most
+ compilers silently discard runtime atomic order information. */
+
+/* Define fallback implementations first that can later be undef'd on compilers with builtin support. */
+/* Note that zig_atomicrmw_expected is needed to handle aliasing between res and arg. */
+#define zig_atomicrmw_xchg_float(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_add_float(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_sub_float(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_min_float(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_libc_name_##Type(fmin)(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_max_float(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_libc_name_##Type(fmax)(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+
+#define zig_atomicrmw_xchg_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, arg, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_add_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_add_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_sub_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_sub_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_and_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_and_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_nand_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_not_##Type(zig_and_##Type(zig_atomicrmw_expected, arg), 128); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_or_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_or_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_xor_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_xor_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_min_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_min_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+#define zig_atomicrmw_max_int128(res, obj, arg, order, Type, ReprType) do { \
+ zig_##Type zig_atomicrmw_expected; \
+ zig_##Type zig_atomicrmw_desired; \
+ zig_atomic_load(zig_atomicrmw_expected, obj, memory_order_relaxed, Type, ReprType); \
+ do { \
+ zig_atomicrmw_desired = zig_max_##Type(zig_atomicrmw_expected, arg); \
+ } while (!zig_cmpxchg_weak(obj, zig_atomicrmw_expected, zig_atomicrmw_desired, order, memory_order_relaxed, Type, ReprType)); \
+ res = zig_atomicrmw_expected; \
+} while (0)
+
+#if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
+#include
+typedef enum memory_order zig_memory_order;
+#define zig_atomic(Type) _Atomic(Type)
+#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_strong_explicit(obj, &(expected), desired, succ, fail)
+#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) atomic_compare_exchange_weak_explicit (obj, &(expected), desired, succ, fail)
+#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = atomic_exchange_explicit (obj, arg, order)
+#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = atomic_fetch_add_explicit (obj, arg, order)
+#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = atomic_fetch_sub_explicit (obj, arg, order)
+#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = atomic_fetch_or_explicit (obj, arg, order)
+#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = atomic_fetch_xor_explicit (obj, arg, order)
+#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = atomic_fetch_and_explicit (obj, arg, order)
+#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order)
+#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order)
+#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order)
+#define zig_atomic_store( obj, arg, order, Type, ReprType) atomic_store_explicit (obj, arg, order)
+#define zig_atomic_load(res, obj, order, Type, ReprType) res = atomic_load_explicit (obj, order)
+#undef zig_atomicrmw_xchg_float
+#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
+#undef zig_atomicrmw_add_float
+#define zig_atomicrmw_add_float zig_atomicrmw_add
+#undef zig_atomicrmw_sub_float
+#define zig_atomicrmw_sub_float zig_atomicrmw_sub
+#define zig_fence(order) atomic_thread_fence(order)
+#elif defined(__GNUC__)
+typedef int zig_memory_order;
+#define memory_order_relaxed __ATOMIC_RELAXED
+#define memory_order_consume __ATOMIC_CONSUME
+#define memory_order_acquire __ATOMIC_ACQUIRE
+#define memory_order_release __ATOMIC_RELEASE
+#define memory_order_acq_rel __ATOMIC_ACQ_REL
+#define memory_order_seq_cst __ATOMIC_SEQ_CST
+#define zig_atomic(Type) Type
+#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), false, succ, fail)
+#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) __atomic_compare_exchange(obj, &(expected), &(desired), true, succ, fail)
+#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) __atomic_exchange(obj, &(arg), &(res), order)
+#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_add (obj, arg, order)
+#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_sub (obj, arg, order)
+#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_or (obj, arg, order)
+#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_xor (obj, arg, order)
+#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_and (obj, arg, order)
+#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_nand(obj, arg, order)
+#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_min (obj, arg, order)
+#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = __atomic_fetch_max (obj, arg, order)
+#define zig_atomic_store( obj, arg, order, Type, ReprType) __atomic_store (obj, &(arg), order)
+#define zig_atomic_load(res, obj, order, Type, ReprType) __atomic_load (obj, &(res), order)
+#undef zig_atomicrmw_xchg_float
+#define zig_atomicrmw_xchg_float zig_atomicrmw_xchg
+#define zig_fence(order) __atomic_thread_fence(order)
+#elif _MSC_VER && (_M_IX86 || _M_X64)
+#define memory_order_relaxed 0
+#define memory_order_consume 1
+#define memory_order_acquire 2
+#define memory_order_release 3
+#define memory_order_acq_rel 4
+#define memory_order_seq_cst 5
+#define zig_atomic(Type) Type
+#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_msvc_cmpxchg_##Type(obj, &(expected), desired)
+#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_cmpxchg_strong(obj, expected, desired, succ, fail, Type, ReprType)
+#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xchg_##Type(obj, arg)
+#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_add_ ##Type(obj, arg)
+#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_sub_ ##Type(obj, arg)
+#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_or_ ##Type(obj, arg)
+#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_xor_ ##Type(obj, arg)
+#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_and_ ##Type(obj, arg)
+#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_nand_##Type(obj, arg)
+#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_min_ ##Type(obj, arg)
+#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) res = zig_msvc_atomicrmw_max_ ##Type(obj, arg)
+#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_msvc_atomic_store_ ##Type(obj, arg)
+#define zig_atomic_load(res, obj, order, Type, ReprType) res = zig_msvc_atomic_load_ ##Type(obj)
+#if _M_X64
+#define zig_fence(order) __faststorefence()
+#else
+#define zig_fence(order) zig_msvc_atomic_barrier()
+#endif
+/* TODO: _MSC_VER && (_M_ARM || _M_ARM64) */
+#else
+#define memory_order_relaxed 0
+#define memory_order_consume 1
+#define memory_order_acquire 2
+#define memory_order_release 3
+#define memory_order_acq_rel 4
+#define memory_order_seq_cst 5
+#define zig_atomic(Type) Type
+#define zig_cmpxchg_strong( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
+#define zig_cmpxchg_weak( obj, expected, desired, succ, fail, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_xchg(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_add(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_sub(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_or(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_xor(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_and(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_nand(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_min(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomicrmw_max(res, obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomic_store( obj, arg, order, Type, ReprType) zig_atomics_unavailable
+#define zig_atomic_load(res, obj, order, Type, ReprType) zig_atomics_unavailable
+#define zig_fence(order) zig_fence_unavailable
+#endif
+
#if _MSC_VER && (_M_IX86 || _M_X64)
-// TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64
+/* TODO: zig_msvc_atomic_load should load 32 bit without interlocked on x86, and load 64 bit without interlocked on x64 */
#define zig_msvc_atomics(ZigType, Type, SigType, suffix) \
static inline bool zig_msvc_cmpxchg_##ZigType(Type volatile* obj, Type* expected, Type desired) { \
@@ -3316,51 +3643,30 @@ zig_msvc_atomics(u64, uint64_t, __int64, 64)
zig_msvc_atomics(i64, int64_t, __int64, 64)
#endif
-#define zig_msvc_flt_atomics(Type, ReprType, suffix) \
+#define zig_msvc_flt_atomics(Type, SigType, suffix) \
static inline bool zig_msvc_cmpxchg_##Type(zig_##Type volatile* obj, zig_##Type* expected, zig_##Type desired) { \
- ReprType exchange; \
- ReprType comparand; \
- ReprType initial; \
+ SigType exchange; \
+ SigType comparand; \
+ SigType initial; \
bool success; \
memcpy(&comparand, expected, sizeof(comparand)); \
memcpy(&exchange, &desired, sizeof(exchange)); \
- initial = _InterlockedCompareExchange##suffix((ReprType volatile*)obj, exchange, comparand); \
+ initial = _InterlockedCompareExchange##suffix((SigType volatile*)obj, exchange, comparand); \
success = initial == comparand; \
if (!success) memcpy(expected, &initial, sizeof(*expected)); \
return success; \
} \
- static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
- ReprType repr; \
- ReprType initial; \
+ static inline void zig_msvc_atomic_store_##Type(zig_##Type volatile* obj, zig_##Type arg) { \
+ SigType value; \
+ memcpy(&value, &arg, sizeof(value)); \
+ (void)_InterlockedExchange##suffix((SigType volatile*)obj, value); \
+ } \
+ static inline zig_##Type zig_msvc_atomic_load_##Type(zig_##Type volatile* obj) { \
zig_##Type result; \
- memcpy(&repr, &value, sizeof(repr)); \
- initial = _InterlockedExchange##suffix((ReprType volatile*)obj, repr); \
+ SigType initial = _InterlockedExchangeAdd##suffix((SigType volatile*)obj, (SigType)0); \
memcpy(&result, &initial, sizeof(result)); \
return result; \
- } \
- static inline zig_##Type zig_msvc_atomicrmw_add_##Type(zig_##Type volatile* obj, zig_##Type value) { \
- ReprType repr; \
- zig_##Type expected; \
- zig_##Type desired; \
- repr = *(ReprType volatile*)obj; \
- memcpy(&expected, &repr, sizeof(expected)); \
- do { \
- desired = expected + value; \
- } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
- return expected; \
- } \
- static inline zig_##Type zig_msvc_atomicrmw_sub_##Type(zig_##Type volatile* obj, zig_##Type value) { \
- ReprType repr; \
- zig_##Type expected; \
- zig_##Type desired; \
- repr = *(ReprType volatile*)obj; \
- memcpy(&expected, &repr, sizeof(expected)); \
- do { \
- desired = expected - value; \
- } while (!zig_msvc_cmpxchg_##Type(obj, &expected, desired)); \
- return expected; \
}
-
zig_msvc_flt_atomics(f32, long, )
#if _M_X64
zig_msvc_flt_atomics(f64, int64_t, 64)
@@ -3421,42 +3727,6 @@ static inline bool zig_msvc_cmpxchg_u128(zig_u128 volatile* obj, zig_u128* expec
static inline bool zig_msvc_cmpxchg_i128(zig_i128 volatile* obj, zig_i128* expected, zig_i128 desired) {
return _InterlockedCompareExchange128((__int64 volatile*)obj, (__int64)zig_hi_i128(desired), (__int64)zig_lo_i128(desired), (__int64*)expected);
}
-
-#define zig_msvc_atomics_128xchg(Type) \
- static inline zig_##Type zig_msvc_atomicrmw_xchg_##Type(zig_##Type volatile* obj, zig_##Type value) { \
- bool success = false; \
- zig_##Type prev; \
- while (!success) { \
- prev = *obj; \
- success = zig_msvc_cmpxchg_##Type(obj, &prev, value); \
- } \
- return prev; \
- }
-
-zig_msvc_atomics_128xchg(u128)
-zig_msvc_atomics_128xchg(i128)
-
-#define zig_msvc_atomics_128op(Type, operation) \
- static inline zig_##Type zig_msvc_atomicrmw_##operation##_##Type(zig_##Type volatile* obj, zig_##Type value) { \
- bool success = false; \
- zig_##Type new; \
- zig_##Type prev; \
- while (!success) { \
- prev = *obj; \
- new = zig_##operation##_##Type(prev, value); \
- success = zig_msvc_cmpxchg_##Type(obj, &prev, new); \
- } \
- return prev; \
- }
-
-zig_msvc_atomics_128op(u128, add)
-zig_msvc_atomics_128op(u128, sub)
-zig_msvc_atomics_128op(u128, or)
-zig_msvc_atomics_128op(u128, xor)
-zig_msvc_atomics_128op(u128, and)
-zig_msvc_atomics_128op(u128, nand)
-zig_msvc_atomics_128op(u128, min)
-zig_msvc_atomics_128op(u128, max)
#endif /* _M_IX86 */
#endif /* _MSC_VER && (_M_IX86 || _M_X64) */
diff --git a/stage1/zig1.wasm b/stage1/zig1.wasm
index 7855cfa8d5..1f6753f6cc 100644
Binary files a/stage1/zig1.wasm and b/stage1/zig1.wasm differ
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
index bdff7c4de4..fc364da0b8 100644
--- a/test/behavior/cast.zig
+++ b/test/behavior/cast.zig
@@ -401,7 +401,6 @@ test "expected [*c]const u8, found [*:0]const u8" {
}
test "explicit cast from integer to error type" {
- if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig
index 302de93591..0b3cf0771a 100644
--- a/test/behavior/eval.zig
+++ b/test/behavior/eval.zig
@@ -1649,3 +1649,15 @@ test "early exit in container level const" {
};
try expect(S.value == 1);
}
+
+test "@inComptime" {
+ const S = struct {
+ fn inComptime() bool {
+ return @inComptime();
+ }
+ };
+ try expectEqual(false, @inComptime());
+ try expectEqual(true, comptime @inComptime());
+ try expectEqual(false, S.inComptime());
+ try expectEqual(true, comptime S.inComptime());
+}
diff --git a/test/behavior/fn.zig b/test/behavior/fn.zig
index e854764649..0dba59f92f 100644
--- a/test/behavior/fn.zig
+++ b/test/behavior/fn.zig
@@ -455,6 +455,23 @@ test "method call with optional and error union first param" {
try s.errUnion();
}
+test "method call with optional pointer first param" {
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+
+ const S = struct {
+ x: i32 = 1234,
+
+ fn method(s: ?*@This()) !void {
+ try expect(s.?.x == 1234);
+ }
+ };
+ var s: S = .{};
+ try s.method();
+ const s_ptr = &s;
+ try s_ptr.method();
+}
+
test "using @ptrCast on function pointers" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
diff --git a/test/behavior/type.zig b/test/behavior/type.zig
index a12949fffd..0d309b9a6e 100644
--- a/test/behavior/type.zig
+++ b/test/behavior/type.zig
@@ -486,10 +486,9 @@ test "Type.Union from regular enum" {
}
test "Type.Fn" {
- if (true) {
- // https://github.com/ziglang/zig/issues/12360
- return error.SkipZigTest;
- }
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const some_opaque = opaque {};
const some_ptr = *some_opaque;
diff --git a/test/cases/compile_errors/union_init_with_none_or_multiple_fields.zig b/test/cases/compile_errors/union_init_with_none_or_multiple_fields.zig
index a700f0d0f2..f808ec8227 100644
--- a/test/cases/compile_errors/union_init_with_none_or_multiple_fields.zig
+++ b/test/cases/compile_errors/union_init_with_none_or_multiple_fields.zig
@@ -29,10 +29,10 @@ export fn u2m() void {
//
// :9:1: error: union initializer must initialize one field
// :1:12: note: union declared here
-// :14:20: error: cannot initialize multiple union fields at once, unions can only have one active field
+// :14:20: error: cannot initialize multiple union fields at once; unions can only have one active field
// :14:31: note: additional initializer here
// :1:12: note: union declared here
// :18:21: error: union initializer must initialize one field
-// :22:20: error: cannot initialize multiple union fields at once, unions can only have one active field
+// :22:20: error: cannot initialize multiple union fields at once; unions can only have one active field
// :22:31: note: additional initializer here
// :5:12: note: union declared here
diff --git a/test/cases/compile_errors/variadic_arg_validation.zig b/test/cases/compile_errors/variadic_arg_validation.zig
index 830d3a0877..bddcef92f6 100644
--- a/test/cases/compile_errors/variadic_arg_validation.zig
+++ b/test/cases/compile_errors/variadic_arg_validation.zig
@@ -21,7 +21,7 @@ pub export fn entry3() void {
// backend=stage2
// target=native
//
-// :4:33: error: integer and float literals passed variadic function must be casted to a fixed-size number type
+// :4:33: error: integer and float literals passed to variadic function must be casted to a fixed-size number type
// :9:24: error: arrays must be passed by reference to variadic function
// :13:24: error: cannot pass 'u48' to variadic function
// :13:24: note: only integers with power of two bits are extern compatible
diff --git a/test/cases/safety/pointer casting to null function pointer.zig b/test/cases/safety/pointer casting to null function pointer.zig
new file mode 100644
index 0000000000..bedbcdda85
--- /dev/null
+++ b/test/cases/safety/pointer casting to null function pointer.zig
@@ -0,0 +1,23 @@
+const std = @import("std");
+
+pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
+ _ = stack_trace;
+ if (std.mem.eql(u8, message, "cast causes pointer to be null")) {
+ std.process.exit(0);
+ }
+ std.process.exit(1);
+}
+
+fn getNullPtr() ?*const anyopaque {
+ return null;
+}
+pub fn main() !void {
+ const null_ptr: ?*const anyopaque = getNullPtr();
+ const required_ptr: *align(1) const fn() void = @ptrCast(*align(1) const fn() void, null_ptr);
+ _ = required_ptr;
+ return error.TestFailed;
+}
+
+// run
+// backend=llvm
+// target=native
diff --git a/test/tests.zig b/test/tests.zig
index 3202d19b3e..7ec1aaaa65 100644
--- a/test/tests.zig
+++ b/test/tests.zig
@@ -1040,6 +1040,12 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
});
compile_c.addIncludePath("lib"); // for zig.h
if (test_target.target.getOsTag() == .windows) {
+ if (true) {
+ // Unfortunately this requires about 8G of RAM for clang to compile
+ // and our Windows CI runners do not have this much.
+ step.dependOn(&these_tests.step);
+ continue;
+ }
if (test_target.link_libc == false) {
compile_c.subsystem = .Console;
compile_c.linkSystemLibrary("kernel32");
diff --git a/test/translate_c.zig b/test/translate_c.zig
index f4cd374a06..7534226881 100644
--- a/test/translate_c.zig
+++ b/test/translate_c.zig
@@ -3956,4 +3956,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ .name = "foo",
\\});
});
+
+ cases.add("string array initializer",
+ \\static const char foo[] = {"bar"};
+ , &[_][]const u8{
+ \\pub const foo: [3:0]u8 = "bar";
+ });
}
|