Commit 7bd3207921

Andrew Kelley <andrew@ziglang.org>
2025-04-27 21:17:59
make `@memcpy` and `@memmove` share panic handlers
1 parent fc55c1b
lib/std/debug/no_panic.zig
@@ -125,17 +125,15 @@ pub fn forLenMismatch() noreturn {
     @trap();
 }
 
-pub fn memcpyLenMismatch() noreturn {
-    @branchHint(.cold);
-    @trap();
-}
+/// Delete after next zig1.wasm update
+pub const memcpyLenMismatch = copyLenMismatch;
 
-pub fn memcpyAlias() noreturn {
+pub fn copyLenMismatch() noreturn {
     @branchHint(.cold);
     @trap();
 }
 
-pub fn memmoveLenMismatch() noreturn {
+pub fn memcpyAlias() noreturn {
     @branchHint(.cold);
     @trap();
 }
lib/std/debug/simple_panic.zig
@@ -120,18 +120,17 @@ pub fn forLenMismatch() noreturn {
     call("for loop over objects with non-equal lengths", null);
 }
 
-pub fn memcpyLenMismatch() noreturn {
-    call("@memcpy arguments have non-equal lengths", null);
+/// Delete after next zig1.wasm update
+pub const memcpyLenMismatch = copyLenMismatch;
+
+pub fn copyLenMismatch() noreturn {
+    call("source and destination have non-equal lengths", null);
 }
 
 pub fn memcpyAlias() noreturn {
     call("@memcpy arguments alias", null);
 }
 
-pub fn memmoveLenMismatch() noreturn {
-    call("@memmove arguments have non-equal lengths", null);
-}
-
 pub fn noreturnReturned() noreturn {
     call("'noreturn' function returned", null);
 }
lib/std/zig/Zir.zig
@@ -983,12 +983,12 @@ pub const Inst = struct {
         /// Implements the `@memcpy` builtin.
         /// Uses the `pl_node` union field with payload `Bin`.
         memcpy,
-        /// Implements the `@memset` builtin.
-        /// Uses the `pl_node` union field with payload `Bin`.
-        memset,
         /// Implements the `@memmove` builtin.
         /// Uses the `pl_node` union field with payload `Bin`.
         memmove,
+        /// Implements the `@memset` builtin.
+        /// Uses the `pl_node` union field with payload `Bin`.
+        memset,
         /// Implements the `@min` builtin for 2 args.
         /// Uses the `pl_node` union field with payload `Bin`
         min,
lib/std/debug.zig
@@ -126,18 +126,16 @@ pub fn FullPanic(comptime panicFn: fn ([]const u8, ?usize) noreturn) type {
             @branchHint(.cold);
             call("for loop over objects with non-equal lengths", @returnAddress());
         }
-        pub fn memcpyLenMismatch() noreturn {
+        /// Delete after next zig1.wasm update
+        pub const memcpyLenMismatch = copyLenMismatch;
+        pub fn copyLenMismatch() noreturn {
             @branchHint(.cold);
-            call("@memcpy arguments have non-equal lengths", @returnAddress());
+            call("source and destination arguments have non-equal lengths", @returnAddress());
         }
         pub fn memcpyAlias() noreturn {
             @branchHint(.cold);
             call("@memcpy arguments alias", @returnAddress());
         }
-        pub fn memmoveLenMismatch() noreturn {
-            @branchHint(.cold);
-            call("@memmove arguments have non-equal lengths", @returnAddress());
-        }
         pub fn noreturnReturned() noreturn {
             @branchHint(.cold);
             call("'noreturn' function returned", @returnAddress());
src/Sema.zig
@@ -1574,17 +1574,17 @@ fn analyzeBodyInner(
                 continue;
             },
             .memcpy => {
-                try sema.zirMemcpy(block, inst);
+                try sema.zirMemcpy(block, inst, .memcpy, true);
                 i += 1;
                 continue;
             },
-            .memset => {
-                try sema.zirMemset(block, inst);
+            .memmove => {
+                try sema.zirMemcpy(block, inst, .memmove, false);
                 i += 1;
                 continue;
             },
-            .memmove => {
-                try sema.zirMemmove(block, inst);
+            .memset => {
+                try sema.zirMemset(block, inst);
                 i += 1;
                 continue;
             },
@@ -25630,19 +25630,12 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A
     return block.addBitCast(new_ty, non_slice_ptr);
 }
 
-fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
-    return sema.analyzeCopy(block, inst, .memcpy);
-}
-
-fn zirMemmove(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
-    return sema.analyzeCopy(block, inst, .memmove);
-}
-
-fn analyzeCopy(
+fn zirMemcpy(
     sema: *Sema,
     block: *Block,
     inst: Zir.Inst.Index,
-    op: enum { memcpy, memmove },
+    air_tag: Air.Inst.Tag,
+    check_aliasing: bool,
 ) CompileError!void {
     const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
     const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
@@ -25659,12 +25652,12 @@ fn analyzeCopy(
     const zcu = pt.zcu;
 
     if (dest_ty.isConstPtr(zcu)) {
-        return sema.fail(block, dest_src, "cannot {s} to constant pointer", .{@tagName(op)});
+        return sema.fail(block, dest_src, "cannot copy to constant pointer", .{});
     }
 
     if (dest_len == .none and src_len == .none) {
         const msg = msg: {
-            const msg = try sema.errMsg(src, "unknown @{s} length", .{@tagName(op)});
+            const msg = try sema.errMsg(src, "unknown copy length", .{});
             errdefer msg.destroy(sema.gpa);
             try sema.errNote(dest_src, msg, "destination type '{}' provides no length", .{
                 dest_ty.fmt(pt),
@@ -25710,7 +25703,7 @@ fn analyzeCopy(
             if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
                 if (!(try sema.valuesEqual(dest_len_val, src_len_val, Type.usize))) {
                     const msg = msg: {
-                        const msg = try sema.errMsg(src, "non-matching @{s} lengths", .{@tagName(op)});
+                        const msg = try sema.errMsg(src, "non-matching copy lengths", .{});
                         errdefer msg.destroy(sema.gpa);
                         try sema.errNote(dest_src, msg, "length {} here", .{
                             dest_len_val.fmtValueSema(pt, sema),
@@ -25730,11 +25723,7 @@ fn analyzeCopy(
 
         if (block.wantSafety()) {
             const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);
-            const panic_id: Zcu.SimplePanicId = switch (op) {
-                .memcpy => .memcpy_len_mismatch,
-                .memmove => .memmove_len_mismatch,
-            };
-            try sema.addSafetyCheck(block, src, ok, panic_id);
+            try sema.addSafetyCheck(block, src, ok, .copy_len_mismatch);
         }
     } else if (dest_len != .none) {
         if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
@@ -25762,11 +25751,6 @@ fn analyzeCopy(
         return;
     }
 
-    const check_aliasing = switch (op) {
-        .memcpy => true,
-        .memmove => false,
-    };
-
     const runtime_src = rs: {
         const dest_ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src;
         const src_ptr_val = try sema.resolveDefinedValue(block, src_src, src_ptr) orelse break :rs src_src;
@@ -25898,10 +25882,7 @@ fn analyzeCopy(
     }
 
     _ = try block.addInst(.{
-        .tag = switch (op) {
-            .memcpy => .memcpy,
-            .memmove => .memmove,
-        },
+        .tag = air_tag,
         .data = .{ .bin_op = .{
             .lhs = new_dest_ptr,
             .rhs = new_src_ptr,
@@ -38124,9 +38105,8 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
         .@"panic.shiftRhsTooBig",
         .@"panic.invalidEnumValue",
         .@"panic.forLenMismatch",
-        .@"panic.memcpyLenMismatch",
+        .@"panic.copyLenMismatch",
         .@"panic.memcpyAlias",
-        .@"panic.memmoveLenMismatch",
         .@"panic.noreturnReturned",
         => try pt.funcType(.{
             .param_types = &.{},
src/Zcu.zig
@@ -300,9 +300,8 @@ pub const BuiltinDecl = enum {
     @"panic.shiftRhsTooBig",
     @"panic.invalidEnumValue",
     @"panic.forLenMismatch",
-    @"panic.memcpyLenMismatch",
+    @"panic.copyLenMismatch",
     @"panic.memcpyAlias",
-    @"panic.memmoveLenMismatch",
     @"panic.noreturnReturned",
 
     VaList,
@@ -378,9 +377,8 @@ pub const BuiltinDecl = enum {
             .@"panic.shiftRhsTooBig",
             .@"panic.invalidEnumValue",
             .@"panic.forLenMismatch",
-            .@"panic.memcpyLenMismatch",
+            .@"panic.copyLenMismatch",
             .@"panic.memcpyAlias",
-            .@"panic.memmoveLenMismatch",
             .@"panic.noreturnReturned",
             => .func,
         };
@@ -446,9 +444,8 @@ pub const SimplePanicId = enum {
     shift_rhs_too_big,
     invalid_enum_value,
     for_len_mismatch,
-    memcpy_len_mismatch,
+    copy_len_mismatch,
     memcpy_alias,
-    memmove_len_mismatch,
     noreturn_returned,
 
     pub fn toBuiltin(id: SimplePanicId) BuiltinDecl {
@@ -471,9 +468,8 @@ pub const SimplePanicId = enum {
             .shift_rhs_too_big          => .@"panic.shiftRhsTooBig",
             .invalid_enum_value         => .@"panic.invalidEnumValue",
             .for_len_mismatch           => .@"panic.forLenMismatch",
-            .memcpy_len_mismatch        => .@"panic.memcpyLenMismatch",
+            .copy_len_mismatch          => .@"panic.copyLenMismatch",
             .memcpy_alias               => .@"panic.memcpyAlias",
-            .memmove_len_mismatch       => .@"panic.memmoveLenMismatch",
             .noreturn_returned          => .@"panic.noreturnReturned",
             // zig fmt: on
         };
test/cases/compile_errors/bad_panic_call_signature.zig
@@ -27,9 +27,10 @@ pub const panic = struct {
     pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
     pub const invalidEnumValue = simple_panic.invalidEnumValue;
     pub const forLenMismatch = simple_panic.forLenMismatch;
-    pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
+    /// Delete after next zig1.wasm update
+    pub const memcpyLenMismatch = copyLenMismatch;
+    pub const copyLenMismatch = simple_panic.copyLenMismatch;
     pub const memcpyAlias = simple_panic.memcpyAlias;
-    pub const memmoveLenMismatch = simple_panic.memmoveLenMismatch;
     pub const noreturnReturned = simple_panic.noreturnReturned;
 };
 
test/cases/compile_errors/bad_panic_generic_signature.zig
@@ -23,9 +23,10 @@ pub const panic = struct {
     pub const shiftRhsTooBig = simple_panic.shiftRhsTooBig;
     pub const invalidEnumValue = simple_panic.invalidEnumValue;
     pub const forLenMismatch = simple_panic.forLenMismatch;
-    pub const memcpyLenMismatch = simple_panic.memcpyLenMismatch;
+    /// Delete after next zig1.wasm update
+    pub const memcpyLenMismatch = copyLenMismatch;
+    pub const copyLenMismatch = simple_panic.copyLenMismatch;
     pub const memcpyAlias = simple_panic.memcpyAlias;
-    pub const memmoveLenMismatch = simple_panic.memmoveLenMismatch;
     pub const noreturnReturned = simple_panic.noreturnReturned;
 };
 
test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig
@@ -66,29 +66,29 @@ pub export fn memset_array() void {
 // backend=stage2
 // target=native
 //
-// :5:5: error: unknown @memcpy length
+// :5:5: error: unknown copy length
 // :5:18: note: destination type '[*]u8' provides no length
 // :5:24: note: source type '[*]const u8' provides no length
 // :10:13: error: type '*u8' is not an indexable pointer
 // :10:13: note: operand must be a slice, a many pointer or a pointer to an array
 // :15:13: error: type '*u8' is not an indexable pointer
 // :15:13: note: operand must be a slice, a many pointer or a pointer to an array
-// :20:5: error: non-matching @memcpy lengths
+// :20:5: error: non-matching copy lengths
 // :20:13: note: length 6 here
 // :20:20: note: length 5 here
 // :24:13: error: cannot memset constant pointer
-// :29:13: error: cannot memcpy to constant pointer
+// :29:13: error: cannot copy 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:5: error: unknown copy 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:5: error: non-matching copy lengths
 // :49:14: note: length 6 here
 // :49:21: note: length 5 here
-// :54:14: error: cannot memmove to constant pointer
+// :54:14: error: cannot copy 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
test/cases/safety/memcpy_len_mismatch.zig
@@ -2,7 +2,7 @@ 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, "@memcpy arguments have non-equal lengths")) {
+    if (std.mem.eql(u8, message, "source and destination arguments have non-equal lengths")) {
         std.process.exit(0);
     }
     std.process.exit(1);
test/cases/safety/memmove_len_mismatch.zig
@@ -2,7 +2,7 @@ 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")) {
+    if (std.mem.eql(u8, message, "source and destination arguments have non-equal lengths")) {
         std.process.exit(0);
     }
     std.process.exit(1);
test/incremental/change_panic_handler_explicit
@@ -37,9 +37,10 @@ pub const panic = struct {
     pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
     pub const invalidEnumValue = no_panic.invalidEnumValue;
     pub const forLenMismatch = no_panic.forLenMismatch;
-    pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
+    /// Delete after next zig1.wasm update
+    pub const memcpyLenMismatch = copyLenMismatch;
+    pub const copyLenMismatch = no_panic.copyLenMismatch;
     pub const memcpyAlias = no_panic.memcpyAlias;
-    pub const memmoveLenMismatch = no_panic.memmoveLenMismatch;
     pub const noreturnReturned = no_panic.noreturnReturned;
 };
 fn myPanic(msg: []const u8, _: ?usize) noreturn {
@@ -85,9 +86,10 @@ pub const panic = struct {
     pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
     pub const invalidEnumValue = no_panic.invalidEnumValue;
     pub const forLenMismatch = no_panic.forLenMismatch;
-    pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
+    /// Delete after next zig1.wasm update
+    pub const memcpyLenMismatch = copyLenMismatch;
+    pub const copyLenMismatch = no_panic.copyLenMismatch;
     pub const memcpyAlias = no_panic.memcpyAlias;
-    pub const memmoveLenMismatch = no_panic.memmoveLenMismatch;
     pub const noreturnReturned = no_panic.noreturnReturned;
 };
 fn myPanic(msg: []const u8, _: ?usize) noreturn {
@@ -133,9 +135,10 @@ pub const panic = struct {
     pub const shiftRhsTooBig = no_panic.shiftRhsTooBig;
     pub const invalidEnumValue = no_panic.invalidEnumValue;
     pub const forLenMismatch = no_panic.forLenMismatch;
-    pub const memcpyLenMismatch = no_panic.memcpyLenMismatch;
+    /// Delete after next zig1.wasm update
+    pub const memcpyLenMismatch = copyLenMismatch;
+    pub const copyLenMismatch = no_panic.copyLenMismatch;
     pub const memcpyAlias = no_panic.memcpyAlias;
-    pub const memmoveLenMismatch = no_panic.memmoveLenMismatch;
     pub const noreturnReturned = no_panic.noreturnReturned;
 };
 fn myPanicNew(msg: []const u8, _: ?usize) noreturn {