From a9b68308b9eeb494524e2b7ab0d63cfa6b623cd0 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Thu, 26 Jan 2023 00:45:40 -0500 Subject: cbe: fixes for tls, support for not linking libc, and enabling tests - cbe: Implement linksection support, to support TLS when not linking libc - cbe: Support under-aligned variables / struct fields - cbe: Support packed structs (in the C definition of packed) - windows: Fix regression with x86 _tls_array - compiler_rt: Add 128-bit atomics to compiler_rt - tests: Re-enable threadlocal tests on cbe+windows, and llvm+x86 - tests: Re-enable f80 tests that now pass - ci: change windows ci to run the CBE behaviour tests with -lc, to match how the compiler is bootstrapped - update zig1.wasm --- test/behavior/math.zig | 3 --- test/behavior/muladd.zig | 2 -- test/behavior/threadlocal.zig | 18 ++++++++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) (limited to 'test/behavior') diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 2257a116b7..c5e36da383 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1332,7 +1332,6 @@ test "float remainder division using @rem" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try frem(f16); comptime try frem(f32); @@ -1375,7 +1374,6 @@ test "float modulo division using @mod" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try fmod(f16); comptime try fmod(f32); @@ -1438,7 +1436,6 @@ test "@round f80" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 try testRound(f80, 12.0); comptime try testRound(f80, 12.0); diff --git a/test/behavior/muladd.zig b/test/behavior/muladd.zig index da00355b35..a2d9e6d16d 100644 --- a/test/behavior/muladd.zig +++ b/test/behavior/muladd.zig @@ -50,7 +50,6 @@ test "@mulAdd f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try testMulAdd80(); try testMulAdd80(); @@ -178,7 +177,6 @@ test "vector f80" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.os.tag == .windows) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/12602 comptime try vector80(); try vector80(); diff --git a/test/behavior/threadlocal.zig b/test/behavior/threadlocal.zig index 1844c5b92d..ebeb1177c2 100644 --- a/test/behavior/threadlocal.zig +++ b/test/behavior/threadlocal.zig @@ -7,8 +7,10 @@ test "thread local variable" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { + .x86_64, .x86 => {}, + else => return error.SkipZigTest, + }; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { @@ -23,8 +25,10 @@ test "pointer to thread local array" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { + .x86_64, .x86 => {}, + else => return error.SkipZigTest, + }; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const s = "Hello world"; @@ -39,8 +43,10 @@ test "reference a global threadlocal variable" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch != .x86_64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_c and builtin.os.tag == .windows) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) { + .x86_64, .x86 => {}, + else => return error.SkipZigTest, + }; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO _ = nrfx_uart_rx(&g_uart0); -- cgit v1.2.3 From 23b7d28896609e3f01765730599119baf53a56c9 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 22 Jan 2023 16:40:00 +0100 Subject: std: restrict mem.span() and mem.len() to sentinel terminated pointers These functions are currently footgunny when working with pointers to arrays and slices. They just return the stated length of the array/slice without iterating and looking for the first sentinel, even if the array/slice is a sentinel terminated type. From looking at the quite small list of places in the standard library/compiler that this change breaks existing code, the new code looks to be more readable in all cases. The usage of std.mem.span/len was totally unneeded in most of the cases affected by this breaking change. We could remove these functions entirely in favor of other existing functions in std.mem such as std.mem.sliceTo(), but that would be a somewhat nasty breaking change as std.mem.span() is very widely used for converting sentinel terminated pointers to slices. It is however not at all widely used for anything else. Therefore I think it is better to break these few non-standard and potentially incorrect usages of these functions now and at some later time, if deemed worthwhile, finally remove these functions. If we wait for at least a full release cycle so that everyone adapts to this change first, updating for the removal could be a simple find and replace without needing to worry about the semantics. --- lib/std/Thread.zig | 2 +- lib/std/bounded_array.zig | 6 ++- lib/std/cstr.zig | 1 - lib/std/fs.zig | 2 +- lib/std/io/fixed_buffer_stream.zig | 25 ++++++--- lib/std/mem.zig | 102 +++++++++---------------------------- src/link/MachO/load_commands.zig | 2 +- src/main.zig | 8 +-- test/behavior/basic.zig | 2 +- 9 files changed, 56 insertions(+), 94 deletions(-) (limited to 'test/behavior') diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig index d27474584f..8004f94d7f 100644 --- a/lib/std/Thread.zig +++ b/lib/std/Thread.zig @@ -166,7 +166,7 @@ pub const GetNameError = error{ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]const u8 { buffer_ptr[max_name_len] = 0; - var buffer = std.mem.span(buffer_ptr); + var buffer: [:0]u8 = buffer_ptr; switch (target.os.tag) { .linux => if (use_pthreads and is_gnu) { diff --git a/lib/std/bounded_array.zig b/lib/std/bounded_array.zig index 3d74e5e47f..7f1957d6dc 100644 --- a/lib/std/bounded_array.zig +++ b/lib/std/bounded_array.zig @@ -29,7 +29,11 @@ pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { } /// View the internal array as a slice whose size was previously set. - pub fn slice(self: anytype) mem.Span(@TypeOf(&self.buffer)) { + pub fn slice(self: anytype) switch (@TypeOf(&self.buffer)) { + *[buffer_capacity]T => []T, + *const [buffer_capacity]T => []const T, + else => unreachable, + } { return self.buffer[0..self.len]; } diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig index 068fc419ac..52524c5084 100644 --- a/lib/std/cstr.zig +++ b/lib/std/cstr.zig @@ -28,7 +28,6 @@ test "cstr fns" { fn testCStrFnsImpl() !void { try testing.expect(cmp("aoeu", "aoez") == -1); - try testing.expect(mem.len("123456789") == 9); } /// Returns a mutable, null-terminated slice with the same length as `slice`. diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 1b00064108..244f3a38ce 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -834,7 +834,7 @@ pub const IterableDir = struct { self.end_index = self.index; // Force fd_readdir in the next loop. continue :start_over; } - const name = mem.span(self.buf[name_index .. name_index + entry.d_namlen]); + const name = self.buf[name_index .. name_index + entry.d_namlen]; const next_index = name_index + entry.d_namlen; self.index = next_index; diff --git a/lib/std/io/fixed_buffer_stream.zig b/lib/std/io/fixed_buffer_stream.zig index f486356491..2fcb260c72 100644 --- a/lib/std/io/fixed_buffer_stream.zig +++ b/lib/std/io/fixed_buffer_stream.zig @@ -113,14 +113,27 @@ pub fn FixedBufferStream(comptime Buffer: type) type { }; } -pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(NonSentinelSpan(@TypeOf(buffer))) { - return .{ .buffer = mem.span(buffer), .pos = 0 }; +pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { + return .{ .buffer = buffer, .pos = 0 }; } -fn NonSentinelSpan(comptime T: type) type { - var ptr_info = @typeInfo(mem.Span(T)).Pointer; - ptr_info.sentinel = null; - return @Type(.{ .Pointer = ptr_info }); +fn Slice(comptime T: type) type { + switch (@typeInfo(T)) { + .Pointer => |ptr_info| { + var new_ptr_info = ptr_info; + switch (ptr_info.size) { + .Slice => {}, + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |info| new_ptr_info.child = info.child, + else => @compileError("invalid type given to fixedBufferStream"), + }, + else => @compileError("invalid type given to fixedBufferStream"), + } + new_ptr_info.size = .Slice; + return @Type(.{ .Pointer = new_ptr_info }); + }, + else => @compileError("invalid type given to fixedBufferStream"), + } } test "FixedBufferStream output" { diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 8691c5bbad..371ef8fd8d 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -636,12 +636,9 @@ test "indexOfDiff" { try testing.expectEqual(indexOfDiff(u8, "xne", "one"), 0); } -/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and -/// returns a slice. If there is a sentinel on the input type, there will be a -/// sentinel on the output type. The constness of the output type matches -/// the constness of the input type. `[*c]` pointers are assumed to be 0-terminated, -/// and assumed to not allow null. -pub fn Span(comptime T: type) type { +/// Takes a sentinel-terminated pointer and returns a slice preserving pointer attributes. +/// `[*c]` pointers are assumed to be 0-terminated and assumed to not be allowzero. +fn Span(comptime T: type) type { switch (@typeInfo(T)) { .Optional => |optional_info| { return ?Span(optional_info.child); @@ -649,39 +646,22 @@ pub fn Span(comptime T: type) type { .Pointer => |ptr_info| { var new_ptr_info = ptr_info; switch (ptr_info.size) { - .One => switch (@typeInfo(ptr_info.child)) { - .Array => |info| { - new_ptr_info.child = info.child; - new_ptr_info.sentinel = info.sentinel; - }, - else => @compileError("invalid type given to std.mem.Span"), - }, .C => { new_ptr_info.sentinel = &@as(ptr_info.child, 0); new_ptr_info.is_allowzero = false; }, - .Many, .Slice => {}, + .Many => if (ptr_info.sentinel == null) @compileError("invalid type given to std.mem.span: " ++ @typeName(T)), + .One, .Slice => @compileError("invalid type given to std.mem.span: " ++ @typeName(T)), } new_ptr_info.size = .Slice; return @Type(.{ .Pointer = new_ptr_info }); }, - else => @compileError("invalid type given to std.mem.Span"), + else => {}, } + @compileError("invalid type given to std.mem.span: " ++ @typeName(T)); } test "Span" { - try testing.expect(Span(*[5]u16) == []u16); - try testing.expect(Span(?*[5]u16) == ?[]u16); - try testing.expect(Span(*const [5]u16) == []const u16); - try testing.expect(Span(?*const [5]u16) == ?[]const u16); - try testing.expect(Span([]u16) == []u16); - try testing.expect(Span(?[]u16) == ?[]u16); - try testing.expect(Span([]const u8) == []const u8); - try testing.expect(Span(?[]const u8) == ?[]const u8); - try testing.expect(Span([:1]u16) == [:1]u16); - try testing.expect(Span(?[:1]u16) == ?[:1]u16); - try testing.expect(Span([:1]const u8) == [:1]const u8); - try testing.expect(Span(?[:1]const u8) == ?[:1]const u8); try testing.expect(Span([*:1]u16) == [:1]u16); try testing.expect(Span(?[*:1]u16) == ?[:1]u16); try testing.expect(Span([*:1]const u8) == [:1]const u8); @@ -692,13 +672,10 @@ test "Span" { try testing.expect(Span(?[*c]const u8) == ?[:0]const u8); } -/// Takes a pointer to an array, a sentinel-terminated pointer, or a slice, and -/// returns a slice. If there is a sentinel on the input type, there will be a -/// sentinel on the output type. The constness of the output type matches -/// the constness of the input type. -/// -/// When there is both a sentinel and an array length or slice length, the -/// length value is used instead of the sentinel. +/// Takes a sentinel-terminated pointer and returns a slice, iterating over the +/// memory to find the sentinel and determine the length. +/// Ponter attributes such as const are preserved. +/// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn span(ptr: anytype) Span(@TypeOf(ptr)) { if (@typeInfo(@TypeOf(ptr)) == .Optional) { if (ptr) |non_null| { @@ -722,7 +699,6 @@ test "span" { var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; const ptr = @as([*:3]u16, array[0..2 :3]); try testing.expect(eql(u16, span(ptr), &[_]u16{ 1, 2 })); - try testing.expect(eql(u16, span(&array), &[_]u16{ 1, 2, 3, 4, 5 })); try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null))); } @@ -919,22 +895,15 @@ test "lenSliceTo" { } } -/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer, -/// a slice or a tuple, and returns the length. -/// In the case of a sentinel-terminated array, it uses the array length. -/// For C pointers it assumes it is a pointer-to-many with a 0 sentinel. +/// Takes a sentinel-terminated pointer and iterates over the memory to find the +/// sentinel and determine the length. +/// `[*c]` pointers are assumed to be non-null and 0-terminated. pub fn len(value: anytype) usize { - return switch (@typeInfo(@TypeOf(value))) { - .Array => |info| info.len, - .Vector => |info| info.len, + switch (@typeInfo(@TypeOf(value))) { .Pointer => |info| switch (info.size) { - .One => switch (@typeInfo(info.child)) { - .Array => value.len, - else => @compileError("invalid type given to std.mem.len"), - }, .Many => { const sentinel_ptr = info.sentinel orelse - @compileError("length of pointer with no sentinel"); + @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))); const sentinel = @ptrCast(*align(1) const info.child, sentinel_ptr).*; return indexOfSentinel(info.child, sentinel, value); }, @@ -942,41 +911,18 @@ pub fn len(value: anytype) usize { assert(value != null); return indexOfSentinel(info.child, 0, value); }, - .Slice => value.len, + else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))), }, - .Struct => |info| if (info.is_tuple) { - return info.fields.len; - } else @compileError("invalid type given to std.mem.len"), - else => @compileError("invalid type given to std.mem.len"), - }; + else => @compileError("invalid type given to std.mem.len: " ++ @typeName(@TypeOf(value))), + } } test "len" { - try testing.expect(len("aoeu") == 4); - - { - var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 }; - try testing.expect(len(&array) == 5); - try testing.expect(len(array[0..3]) == 3); - array[2] = 0; - const ptr = @as([*:0]u16, array[0..2 :0]); - try testing.expect(len(ptr) == 2); - } - { - var array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 }; - try testing.expect(len(&array) == 5); - array[2] = 0; - try testing.expect(len(&array) == 5); - } - { - const vector: meta.Vector(2, u32) = [2]u32{ 1, 2 }; - try testing.expect(len(vector) == 2); - } - { - const tuple = .{ 1, 2 }; - try testing.expect(len(tuple) == 2); - try testing.expect(tuple[0] == 1); - } + var array: [5]u16 = [_]u16{ 1, 2, 0, 4, 5 }; + const ptr = @as([*:4]u16, array[0..3 :4]); + try testing.expect(len(ptr) == 3); + const c_ptr = @as([*c]u16, ptr); + try testing.expect(len(c_ptr) == 2); } pub fn indexOfSentinel(comptime Elem: type, comptime sentinel: Elem, ptr: [*:sentinel]const Elem) usize { diff --git a/src/link/MachO/load_commands.zig b/src/link/MachO/load_commands.zig index 0e3760526c..a452551a0a 100644 --- a/src/link/MachO/load_commands.zig +++ b/src/link/MachO/load_commands.zig @@ -12,7 +12,7 @@ pub const default_dyld_path: [*:0]const u8 = "/usr/lib/dyld"; fn calcInstallNameLen(cmd_size: u64, name: []const u8, assume_max_path_len: bool) u64 { const darwin_path_max = 1024; - const name_len = if (assume_max_path_len) darwin_path_max else std.mem.len(name) + 1; + const name_len = if (assume_max_path_len) darwin_path_max else name.len + 1; return mem.alignForwardGeneric(u64, cmd_size + name_len, @alignOf(u64)); } diff --git a/src/main.zig b/src/main.zig index fdc761ac92..72e7e094e6 100644 --- a/src/main.zig +++ b/src/main.zig @@ -893,7 +893,7 @@ fn buildOutputType( i: usize = 0, fn next(it: *@This()) ?[]const u8 { if (it.i >= it.args.len) { - if (it.resp_file) |*resp| return if (resp.next()) |sentinel| std.mem.span(sentinel) else null; + if (it.resp_file) |*resp| return resp.next(); return null; } defer it.i += 1; @@ -901,7 +901,7 @@ fn buildOutputType( } fn nextOrFatal(it: *@This()) []const u8 { if (it.i >= it.args.len) { - if (it.resp_file) |*resp| if (resp.next()) |sentinel| return std.mem.span(sentinel); + if (it.resp_file) |*resp| if (resp.next()) |ret| return ret; fatal("expected parameter after {s}", .{it.args[it.i - 1]}); } defer it.i += 1; @@ -4973,7 +4973,7 @@ pub const ClangArgIterator = struct { // rather than an argument to a parameter. // We adjust the len below when necessary. self.other_args = (self.argv.ptr + self.next_index)[0..1]; - var arg = mem.span(self.argv[self.next_index]); + var arg = self.argv[self.next_index]; self.incrementArgIndex(); if (mem.startsWith(u8, arg, "@")) { @@ -5017,7 +5017,7 @@ pub const ClangArgIterator = struct { self.has_next = true; self.other_args = (self.argv.ptr + self.next_index)[0..1]; // We adjust len below when necessary. - arg = mem.span(self.argv[self.next_index]); + arg = self.argv[self.next_index]; self.incrementArgIndex(); } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index ebca81be96..8a97b3cbcd 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -703,7 +703,7 @@ test "string concatenation" { comptime try expect(@TypeOf(a) == *const [12:0]u8); comptime try expect(@TypeOf(b) == *const [12:0]u8); - const len = mem.len(b); + const len = b.len; const len_with_null = len + 1; { var i: u32 = 0; -- cgit v1.2.3 From dd300d47b22c740ab75ace54057a3831606f7952 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Mon, 23 Jan 2023 20:23:12 +0200 Subject: add test for already implemented proposal Closes #1564 --- test/behavior/sizeof_and_typeof.zig | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'test/behavior') diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index ef4487d9b9..cfe948ac02 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -292,3 +292,12 @@ test "@sizeOf optional of previously unresolved union" { const Node = union { a: usize }; try expect(@sizeOf(?Node) == @sizeOf(Node) + @alignOf(Node)); } + +test "@offsetOf zero-bit field" { + const S = packed struct { + a: u32, + b: u0, + c: u32, + }; + try expect(@offsetOf(S, "b") == @offsetOf(S, "c")); +} -- cgit v1.2.3 From 47ff57ed7ddbf4c4a0f93208fc96851c9033b8b7 Mon Sep 17 00:00:00 2001 From: Techatrix <19954306+Techatrix@users.noreply.github.com> Date: Tue, 31 Jan 2023 17:01:56 +0100 Subject: wasm: apply request change --- src/arch/wasm/CodeGen.zig | 7 +++++-- test/behavior/cast.zig | 3 --- test/behavior/optional.zig | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'test/behavior') diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index d0ff27a3e2..c0d0c11b56 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3880,8 +3880,11 @@ fn isNull(func: *CodeGen, operand: WValue, optional_ty: Type, opcode: wasm.Opcod try func.addMemArg(.i32_load8_u, .{ .offset = operand.offset(), .alignment = 1 }); } } else if (payload_ty.isSlice()) { - // move the ptr on top of the stack - _ = try func.load(operand, Type.usize, 0); + switch (func.arch()) { + .wasm32 => try func.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = 4 }), + .wasm64 => try func.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = 8 }), + else => unreachable, + } } // Compare the null value with '0' diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 7c0746bfcd..dbb4c07f64 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -1179,7 +1179,6 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { test "implicitly cast from [N]T to ?[]const T" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try expect(mem.eql(u8, castToOptionalSlice().?, "hi")); @@ -1264,7 +1263,6 @@ test "cast from array reference to fn: runtime fn ptr" { test "*const [N]null u8 to ?[]const u8" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO const S = struct { @@ -1413,7 +1411,6 @@ test "cast i8 fn call peers to i32 result" { test "cast compatible optional types" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO var a: ?[:0]const u8 = null; diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 3e91c6807c..3a5b7b008b 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -439,7 +439,6 @@ test "Optional slice size is optimized" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO try expect(@sizeOf(?[]u8) == @sizeOf([]u8)); @@ -479,7 +478,6 @@ test "cast slice to const slice nested in error union and optional" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; const S = struct { fn inner() !?[]u8 { -- cgit v1.2.3 From 629c3108aa71f94bd26dba8d4f20c9f3a3945bd4 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Wed, 1 Feb 2023 21:41:02 +0200 Subject: AstGen: fix orelse type coercion in call arguments Closes #14506 --- src/AstGen.zig | 8 +++++++- test/behavior/basic.zig | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'test/behavior') diff --git a/src/AstGen.zig b/src/AstGen.zig index a5667ce9e8..10673a2b37 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -8721,6 +8721,7 @@ fn callExpr( defer arg_block.unstack(); // `call_inst` is reused to provide the param type. + arg_block.rl_ty_inst = call_inst; const arg_ref = try expr(&arg_block, &arg_block.base, .{ .rl = .{ .coerced_ty = call_inst }, .ctx = .fn_arg }, param_node); _ = try arg_block.addBreak(.break_inline, call_index, arg_ref); @@ -10869,7 +10870,12 @@ const GenZir = struct { // we emit ZIR for the block break instructions to have the result values, // and then rvalue() on that to pass the value to the result location. switch (parent_ri.rl) { - .ty, .coerced_ty => |ty_inst| { + .coerced_ty => |ty_inst| { + // Type coercion needs to happend before breaks. + gz.rl_ty_inst = ty_inst; + gz.break_result_info = .{ .rl = .{ .ty = ty_inst } }; + }, + .ty => |ty_inst| { gz.rl_ty_inst = ty_inst; gz.break_result_info = parent_ri; }, diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 8a97b3cbcd..b82bfab99e 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -1125,3 +1125,21 @@ test "returning an opaque type from a function" { }; try expect(S.foo(123).b == 123); } + +test "orelse coercion as function argument" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + + const Loc = struct { start: i32 = -1 }; + const Container = struct { + a: ?Loc = null, + fn init(a: Loc) @This() { + return .{ + .a = a, + }; + } + }; + var optional: ?Loc = .{}; + var foo = Container.init(optional orelse .{}); + try expect(foo.a.?.start == -1); +} -- cgit v1.2.3 From 9db084f43d6f253f36484b9e3b76ea483917a893 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Thu, 2 Feb 2023 00:54:07 -0800 Subject: Add test for optional error set return types Closes #5820 --- test/behavior/error.zig | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'test/behavior') diff --git a/test/behavior/error.zig b/test/behavior/error.zig index b2a6cc5a50..f30290eb91 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -896,3 +896,18 @@ test "optional error union return type" { }; try expect(1234 == try S.foo().?); } + +test "optional error set return type" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + const E = error{ A, B }; + const S = struct { + fn foo(return_null: bool) ?E { + return if (return_null) null else E.A; + } + }; + + try expect(null == S.foo(true)); + try expect(E.A == S.foo(false).?); +} -- cgit v1.2.3