From 4e78836d29260e915e767bc907ff7ba6c652ef5f Mon Sep 17 00:00:00 2001 From: dweiller <4678790+dweiller@users.noreply.github.com> Date: Wed, 22 Jan 2025 18:44:27 +1100 Subject: [PATCH] test: add tests for @memmove --- test/behavior.zig | 1 + ...n_functions_returning_void_or_noreturn.zig | 2 + test/behavior/memmove.zig | 183 +++++++++++++++ .../compile_errors/@memmove_type_mismatch.zig | 218 ++++++++++++++++++ .../comptime_var_referenced_at_runtime.zig | 11 + .../incorrect_type_to_memset_memcpy.zig | 44 +++- test/cases/safety/memmove_len_mismatch.zig | 19 ++ test/standalone/zerolength_check/src/main.zig | 1 + 8 files changed, 478 insertions(+), 1 deletion(-) create mode 100644 test/behavior/memmove.zig create mode 100644 test/cases/compile_errors/@memmove_type_mismatch.zig create mode 100644 test/cases/safety/memmove_len_mismatch.zig diff --git a/test/behavior.zig b/test/behavior.zig index aba1c663eb..5ed256dfad 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -55,6 +55,7 @@ test { _ = @import("behavior/member_func.zig"); _ = @import("behavior/memcpy.zig"); _ = @import("behavior/memset.zig"); + _ = @import("behavior/memmove.zig"); _ = @import("behavior/merge_error_sets.zig"); _ = @import("behavior/muladd.zig"); _ = @import("behavior/multiple_externs_with_conflicting_types.zig"); diff --git a/test/behavior/builtin_functions_returning_void_or_noreturn.zig b/test/behavior/builtin_functions_returning_void_or_noreturn.zig index e20e1ed9bf..8a6cb13cca 100644 --- a/test/behavior/builtin_functions_returning_void_or_noreturn.zig +++ b/test/behavior/builtin_functions_returning_void_or_noreturn.zig @@ -6,6 +6,7 @@ var x: u8 = 1; // This excludes builtin functions that return void or noreturn that cannot be tested. test { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -17,6 +18,7 @@ test { try testing.expectEqual(void, @TypeOf(@breakpoint())); try testing.expectEqual({}, @export(&x, .{ .name = "x" })); try testing.expectEqual({}, @memcpy(@as([*]u8, @ptrFromInt(1))[0..0], @as([*]u8, @ptrFromInt(1))[0..0])); + try testing.expectEqual({}, @memmove(@as([*]u8, @ptrFromInt(1))[0..0], @as([*]u8, @ptrFromInt(1))[0..0])); try testing.expectEqual({}, @memset(@as([*]u8, @ptrFromInt(1))[0..0], undefined)); try testing.expectEqual(noreturn, @TypeOf(if (true) @panic("") else {})); try testing.expectEqual({}, @prefetch(&val, .{})); diff --git a/test/behavior/memmove.zig b/test/behavior/memmove.zig new file mode 100644 index 0000000000..a29535ec9a --- /dev/null +++ b/test/behavior/memmove.zig @@ -0,0 +1,183 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; + +test "memmove and memset intrinsics" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + + try testMemmoveMemset(); + try comptime testMemmoveMemset(); +} + +fn testMemmoveMemset() !void { + var foo: [20]u8 = undefined; + + @memset(foo[0..10], 'A'); + @memset(foo[10..20], 'B'); + + try expect(foo[0] == 'A'); + try expect(foo[11] == 'B'); + try expect(foo[19] == 'B'); + + @memmove(foo[10..20], foo[0..10]); + + try expect(foo[0] == 'A'); + try expect(foo[11] == 'A'); + try expect(foo[19] == 'A'); +} + +test "@memmove with both operands single-ptr-to-array, one is null-terminated" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + + try testMemmoveBothSinglePtrArrayOneIsNullTerminated(); + try comptime testMemmoveBothSinglePtrArrayOneIsNullTerminated(); +} + +fn testMemmoveBothSinglePtrArrayOneIsNullTerminated() !void { + var buf: [100]u8 = undefined; + const suffix = "hello"; + @memmove(buf[buf.len - suffix.len ..], suffix); + try expect(buf[95] == 'h'); + try expect(buf[96] == 'e'); + try expect(buf[97] == 'l'); + try expect(buf[98] == 'l'); + try expect(buf[99] == 'o'); + + const start = buf.len - suffix.len - 3; + const end = start + suffix.len; + @memmove(buf[start..end], buf[buf.len - suffix.len ..]); + try expect(buf[92] == 'h'); + try expect(buf[93] == 'e'); + try expect(buf[94] == 'l'); + try expect(buf[95] == 'l'); + try expect(buf[96] == 'o'); + try expect(buf[97] == 'l'); + try expect(buf[98] == 'l'); + try expect(buf[99] == 'o'); + + @memmove(buf[start + 2 .. end + 2], buf[start..end]); + try expect(buf[92] == 'h'); + try expect(buf[93] == 'e'); + try expect(buf[94] == 'h'); + try expect(buf[95] == 'e'); + try expect(buf[96] == 'l'); + try expect(buf[97] == 'l'); + try expect(buf[98] == 'o'); + try expect(buf[99] == 'o'); +} + +test "@memmove dest many pointer" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + + try testMemmoveDestManyPtr(); + try comptime testMemmoveDestManyPtr(); +} + +fn testMemmoveDestManyPtr() !void { + var str = "hello".*; + var buf: [8]u8 = undefined; + var len: usize = 5; + _ = &len; + @memmove(@as([*]u8, @ptrCast(&buf)), @as([*]const u8, @ptrCast(&str))[0..len]); + try expect(buf[0] == 'h'); + try expect(buf[1] == 'e'); + try expect(buf[2] == 'l'); + try expect(buf[3] == 'l'); + try expect(buf[4] == 'o'); + @memmove(buf[3..].ptr, buf[0..len]); + try expect(buf[0] == 'h'); + try expect(buf[1] == 'e'); + try expect(buf[2] == 'l'); + try expect(buf[3] == 'h'); + try expect(buf[4] == 'e'); + try expect(buf[5] == 'l'); + try expect(buf[6] == 'l'); + try expect(buf[7] == 'o'); + @memmove(buf[2..7].ptr, buf[3 .. len + 3]); + try expect(buf[0] == 'h'); + try expect(buf[1] == 'e'); + try expect(buf[2] == 'h'); + try expect(buf[3] == 'e'); + try expect(buf[4] == 'l'); + try expect(buf[5] == 'l'); + try expect(buf[6] == 'o'); + try expect(buf[7] == 'o'); +} + +test "@memmove slice" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + + try testMemmoveSlice(); + try comptime testMemmoveSlice(); +} + +fn testMemmoveSlice() !void { + var buf: [8]u8 = undefined; + const dst1: []u8 = buf[0..5]; + const dst2: []u8 = buf[3..8]; + const dst3: []u8 = buf[2..7]; + const src: []const u8 = "hello"; + @memmove(dst1, src); + try expect(buf[0] == 'h'); + try expect(buf[1] == 'e'); + try expect(buf[2] == 'l'); + try expect(buf[3] == 'l'); + try expect(buf[4] == 'o'); + @memmove(dst2, dst1); + try expect(buf[0] == 'h'); + try expect(buf[1] == 'e'); + try expect(buf[2] == 'l'); + try expect(buf[3] == 'h'); + try expect(buf[4] == 'e'); + try expect(buf[5] == 'l'); + try expect(buf[6] == 'l'); + try expect(buf[7] == 'o'); + @memmove(dst3, dst2); + try expect(buf[0] == 'h'); + try expect(buf[1] == 'e'); + try expect(buf[2] == 'h'); + try expect(buf[3] == 'e'); + try expect(buf[4] == 'l'); + try expect(buf[5] == 'l'); + try expect(buf[6] == 'o'); + try expect(buf[7] == 'o'); +} + +comptime { + const S = struct { + buffer: [8]u8 = undefined, + fn set(self: *@This(), items: []const u8) void { + @memmove(self.buffer[0..items.len], items); + @memmove(self.buffer[3..], self.buffer[0..items.len]); + @memmove(self.buffer[2 .. 2 + items.len], self.buffer[3..]); + } + }; + + var s = S{}; + s.set("hello"); + if (!std.mem.eql(u8, s.buffer[0..8], "hehelloo")) @compileError("bad"); +} diff --git a/test/cases/compile_errors/@memmove_type_mismatch.zig b/test/cases/compile_errors/@memmove_type_mismatch.zig new file mode 100644 index 0000000000..698bd9115f --- /dev/null +++ b/test/cases/compile_errors/@memmove_type_mismatch.zig @@ -0,0 +1,218 @@ +export fn foo() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []u8 = &buf; + const src: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + + @memmove(dest, src); +} + +export fn bar() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []u8 = &buf; + const src: *align(1) [8]u16 = @ptrCast(&buf); + + @memmove(dest, src); +} + +export fn baz() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []u8 = &buf; + const src: [*]align(1) u16 = @ptrCast(&buf); + + @memmove(dest, src); +} + +export fn qux() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *[8]u8 = &buf; + const src: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + + @memmove(dest, src); +} + +export fn quux() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *[8]u8 = &buf; + const src: *align(1) [8]u16 = @ptrCast(&buf); + + @memmove(dest, src); +} + +export fn quuux() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *[8]u8 = &buf; + const src: [*]align(1) u16 = @ptrCast(&buf); + + @memmove(dest, src); +} + +export fn foo2() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + const src: []u8 = &buf; + + @memmove(dest, src); +} + +export fn bar2() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *align(1) [8]u16 = @ptrCast(&buf); + const src: []u8 = &buf; + + @memmove(dest, src); +} + +export fn baz2() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: [*]align(1) u16 = @ptrCast(&buf); + const src: []u8 = &buf; + + @memmove(dest, src); +} + +export fn qux2() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + const src: *[8]u8 = &buf; + + @memmove(dest, src); +} + +export fn quux2() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *align(1) [8]u16 = @ptrCast(&buf); + const src: *[8]u8 = &buf; + + @memmove(dest, src); +} + +export fn quuux2() void { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: [*]align(1) u16 = @ptrCast(&buf); + const src: *[8]u8 = &buf; + + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []u8 = &buf; + const src: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []u8 = &buf; + const src: *align(1) [8]u16 = @ptrCast(&buf); + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []u8 = &buf; + const src: [*]align(1) u16 = @ptrCast(&buf); + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *[8]u8 = &buf; + const src: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *[8]u8 = &buf; + const src: *align(1) [8]u16 = @ptrCast(&buf); + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *[8]u8 = &buf; + const src: [*]align(1) u16 = @ptrCast(&buf); + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + const src: []u8 = &buf; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *align(1) [8]u16 = @ptrCast(&buf); + const src: []u8 = &buf; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: [*]align(1) u16 = @ptrCast(&buf); + const src: []u8 = &buf; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: []align(1) u16 = @as([*]align(1) u16, @ptrCast(&buf))[0..4]; + const src: *[8]u8 = &buf; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: *align(1) [8]u16 = @ptrCast(&buf); + const src: *[8]u8 = &buf; + @memmove(dest, src); +} + +comptime { + var buf: [8]u8 = .{ 0, 1, 2, 3, 4, 5, 6, 7 }; + const dest: [*]align(1) u16 = @ptrCast(&buf); + const src: *[8]u8 = &buf; + @memmove(dest, src); +} + +// error +// +// :6:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :6:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :14:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :14:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :22:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :22:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :30:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :30:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :38:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :38:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :46:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :46:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :54:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :62:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :70:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :78:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :86:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :94:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :101:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :101:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :108:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :108:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :115:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :115:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :122:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :122:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :129:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :129:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :136:5: error: pointer element type 'u16' cannot coerce into element type 'u8' +// :136:5: note: unsigned 8-bit int cannot represent all possible unsigned 16-bit values +// :143:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :150:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :157:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :164:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :171:5: error: pointer element type 'u8' cannot coerce into element type 'u16' +// :178:5: error: pointer element type 'u8' cannot coerce into element type 'u16' diff --git a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig index 4ededdffac..e060da33a8 100644 --- a/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig +++ b/test/cases/compile_errors/comptime_var_referenced_at_runtime.zig @@ -63,6 +63,14 @@ export fn far() void { @memset(&rt, elem); } +export fn bax() void { + comptime var x: [2]u32 = undefined; + x = .{ 1, 2 }; + + var rt: [2]u32 = undefined; + @memmove(&rt, &x); +} + // error // // :5:19: error: runtime value contains reference to comptime var @@ -92,3 +100,6 @@ export fn far() void { // :63:18: error: runtime value contains reference to comptime var // :63:18: note: comptime var pointers are not available at runtime // :59:27: note: 'runtime_value' points to comptime var declared here +// :71:19: error: runtime value contains reference to comptime var +// :71:19: note: comptime var pointers are not available at runtime +// :67:30: note: 'runtime_value' points to comptime var declared here diff --git a/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig b/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig index 26b31dd506..3bc9065fa1 100644 --- a/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig +++ b/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig @@ -28,10 +28,39 @@ pub export fn memcpy_const_dest_ptr() void { var buf2: [5]u8 = .{ 1, 2, 3, 4, 5 }; @memcpy(&buf1, &buf2); } -pub export fn memset_array() void { +pub export fn memcpy_array() void { const buf: [5]u8 = .{ 1, 2, 3, 4, 5 }; @memcpy(buf, 1); } +pub export fn entry_memmove() void { + var buf: [5]u8 = .{ 1, 2, 3, 4, 5 }; + const slice: []u8 = &buf; + const a: u32 = 1234; + @memmove(slice.ptr, @as([*]const u8, @ptrCast(&a))); +} +pub export fn entry1_memmove() void { + var buf: [5]u8 = .{ 1, 2, 3, 4, 5 }; + const ptr: *u8 = &buf[0]; + @memmove(ptr, 0); +} +pub export fn non_matching_lengths_memmove() void { + var buf1: [5]u8 = .{ 1, 2, 3, 4, 5 }; + var buf2: [6]u8 = .{ 1, 2, 3, 4, 5, 6 }; + @memmove(&buf2, &buf1); +} +pub export fn memcpy_const_dest_ptr_memmove() void { + const buf1: [5]u8 = .{ 1, 2, 3, 4, 5 }; + var buf2: [5]u8 = .{ 1, 2, 3, 4, 5 }; + @memmove(&buf1, &buf2); +} +pub export fn memmove_array() void { + const buf: [5]u8 = .{ 1, 2, 3, 4, 5 }; + @memmove(buf, 1); +} +pub export fn memset_array() void { + const buf: [5]u8 = .{ 1, 2, 3, 4, 5 }; + @memset(buf, 1); +} // error // backend=stage2 @@ -51,3 +80,16 @@ pub export fn memset_array() void { // :29:13: error: cannot memcpy to constant pointer // :33:13: error: type '[5]u8' is not an indexable pointer // :33:13: note: operand must be a slice, a many pointer or a pointer to an array +// :39:5: error: unknown @memmove length +// :39:19: note: destination type '[*]u8' provides no length +// :39:25: note: source type '[*]const u8' provides no length +// :44:14: error: type '*u8' is not an indexable pointer +// :44:14: note: operand must be a slice, a many pointer or a pointer to an array +// :49:5: error: non-matching @memmove lengths +// :49:14: note: length 6 here +// :49:21: note: length 5 here +// :54:14: error: cannot memmove to constant pointer +// :58:14: error: type '[5]u8' is not an indexable pointer +// :58:14: note: operand must be a slice, a many pointer or a pointer to an array +// :62:13: error: type '[5]u8' is not an indexable pointer +// :62:13: note: operand must be a slice, a many pointer or a pointer to an array diff --git a/test/cases/safety/memmove_len_mismatch.zig b/test/cases/safety/memmove_len_mismatch.zig new file mode 100644 index 0000000000..89908a8c4e --- /dev/null +++ b/test/cases/safety/memmove_len_mismatch.zig @@ -0,0 +1,19 @@ +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, "@memmove arguments have non-equal lengths")) { + std.process.exit(0); + } + std.process.exit(1); +} +pub fn main() !void { + var buffer = [2]u8{ 1, 2 } ** 5; + var len: usize = 5; + _ = &len; + @memmove(buffer[0..len], buffer[len .. len + 4]); + return error.TestFailed; +} +// run +// backend=llvm +// target=native diff --git a/test/standalone/zerolength_check/src/main.zig b/test/standalone/zerolength_check/src/main.zig index 1cb8358c9d..2f674ab4ff 100644 --- a/test/standalone/zerolength_check/src/main.zig +++ b/test/standalone/zerolength_check/src/main.zig @@ -5,6 +5,7 @@ test { const source = foo(); @memcpy(dest, source); + @memmove(dest, source); @memset(dest, 4); @memset(dest, undefined);