Commit 4e78836d29

dweiller <4678790+dweiller@users.noreply.github.com>
2025-01-22 08:44:27
test: add tests for @memmove
1 parent 898ca82
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, .{}));
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");
+}
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'
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
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
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
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);
 
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");