diff --git a/test/behavior.zig b/test/behavior.zig index 6ec59fa22df7..249d3191e65d 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -149,6 +149,7 @@ test { _ = @import("behavior/byval_arg_var.zig"); _ = @import("behavior/c_char_signedness.zig"); _ = @import("behavior/call.zig"); + _ = @import("behavior/call_tail.zig"); _ = @import("behavior/cast.zig"); _ = @import("behavior/cast_int.zig"); _ = @import("behavior/comptime_memory.zig"); diff --git a/test/behavior/call_tail.zig b/test/behavior/call_tail.zig new file mode 100644 index 000000000000..371bab812362 --- /dev/null +++ b/test/behavior/call_tail.zig @@ -0,0 +1,59 @@ +const builtin = @import("builtin"); +const std = @import("std"); +const expect = std.testing.expect; + +var base: usize = undefined; +var result_off: [7]usize = undefined; +var result_len: [7]usize = undefined; +var result_index: usize = 0; + +noinline fn insertionSort(data: []u64) void { + result_off[result_index] = @intFromPtr(data.ptr) - base; + result_len[result_index] = data.len; + result_index += 1; + if (data.len > 1) { + var least_i: usize = 0; + var i: usize = 1; + while (i < data.len) : (i += 1) { + if (data[i] < data[least_i]) + least_i = i; + } + std.mem.swap(u64, &data[0], &data[least_i]); + + // there used to be a bug where + // `data[1..]` is created on the stack + // and pointed to by the first argument register + // then stack is invalidated by the tailcall and + // overwritten by callee + // https://github.com/ziglang/zig/issues/9703 + return @call(.always_tail, insertionSort, .{data[1..]}); + } +} + +test "arguments pointed to on stack into tailcall" { + switch (builtin.cpu.arch) { + .wasm32, .mips, .mipsel, .powerpc, .powerpcle, .powerpc64le => return error.SkipZigTest, + else => {}, + } + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + + var data = [_]u64{ 1, 6, 2, 7, 1, 9, 3 }; + base = @intFromPtr(&data); + insertionSort(data[0..]); + try expect(result_len[0] == 7); + try expect(result_len[1] == 6); + try expect(result_len[2] == 5); + try expect(result_len[3] == 4); + try expect(result_len[4] == 3); + try expect(result_len[5] == 2); + try expect(result_len[6] == 1); + + try expect(result_off[0] == 0); + try expect(result_off[1] == 8); + try expect(result_off[2] == 16); + try expect(result_off[3] == 24); + try expect(result_off[4] == 32); + try expect(result_off[5] == 40); + try expect(result_off[6] == 48); +} diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index db776e598e27..dd7ded911de9 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -189,3 +189,15 @@ test "errdefer used in function that doesn't return an error" { }; try expect(S.foo() == 5); } + +// Originally reported at https://github.com/ziglang/zig/issues/10591 +const defer_assign = switch (block: { + var x = 0; + defer x = 1; + break :block x; +}) { + else => |i| i, +}; +comptime { + if (defer_assign != 0) @compileError("defer_assign failed!"); +} diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 24af16fc931c..80eabeaf933b 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -1703,3 +1703,13 @@ test "@inComptime" { try expectEqual(false, S.inComptime()); try expectEqual(true, comptime S.inComptime()); } + +// comptime partial array assign +comptime { + var foo = [3]u8{ 0x55, 0x55, 0x55 }; + var bar = [2]u8{ 1, 2 }; + foo[0..2].* = bar; + assert(foo[0] == 1); + assert(foo[1] == 2); + assert(foo[2] == 0x55); +} diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index e2970c36035f..d3d761c3dbc4 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -640,3 +640,13 @@ test "store undefined to packed result location" { var s = packed struct { x: u4, y: u4 }{ .x = x, .y = if (x > 0) x else undefined }; try expectEqual(x, s.x); } + +test "bitcast back and forth" { + // Originally reported at https://github.com/ziglang/zig/issues/9914 + const S = packed struct { one: u6, two: u1 }; + const s = S{ .one = 0b110101, .two = 0b1 }; + const u: u7 = @bitCast(s); + const s2: S = @bitCast(u); + try expect(s.one == s2.one); + try expect(s.two == s2.two); +} diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index 3a2ec9db190f..8837c42a864c 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -284,3 +284,12 @@ test "@ptrCast undefined value at comptime" { _ = x; } } + +test "comptime @ptrCast with packed struct leaves value unmodified" { + const S = packed struct { three: u3 }; + const st: S = .{ .three = 6 }; + try expect(st.three == 6); + const p: *const [1]u3 = @ptrCast(&st); + try expect(p.*[0] == 6); + try expect(st.three == 6); +} diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 0ae7c510ef0e..7d90247a30ef 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -797,3 +797,22 @@ test "inline switch range that includes the maximum value of the switched type" } } } + +test "nested break ignores switch conditions and breaks instead" { + const S = struct { + fn register_to_address(ident: []const u8) !u8 { + const reg: u8 = if (std.mem.eql(u8, ident, "zero")) 0x00 else blk: { + break :blk switch (ident[0]) { + 0x61 => (try std.fmt.parseInt(u8, ident[1..], 0)) + 1, + 0x66 => (try std.fmt.parseInt(u8, ident[1..], 0)) + 1, + else => { + break :blk 0xFF; + }, + }; + }; + return reg; + } + }; + // Originally reported at https://github.com/ziglang/zig/issues/10196 + try expect(0x01 == try S.register_to_address("a0")); +} diff --git a/test/behavior/union.zig b/test/behavior/union.zig index f7a481e311ef..3ea6f17a264a 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1692,3 +1692,24 @@ test "packed union field pointer has correct alignment" { try expectEqual(@as(u20, 456), bp.*); try expectEqual(@as(u20, 789), cp.*); } + +test "union with 128 bit integer" { + const ValueTag = enum { int, other }; + + const Value3 = union(ValueTag) { + int: i128, + other: bool, + }; + var values: [2]Value3 = undefined; + values[0] = .{ .int = 3 }; + values[1] = .{ .int = 4 }; + + var ok: usize = 0; + + for (values) |val| { + switch (val) { + .int => ok += 1, + else => return error.TestFailed, + } + } +}