| author | |
| committer | |
| log | 149031204c0c804a66571a751b259da95886640d |
| tree | 4c36c2b86776a5c0116e7212bc31dd1f4bfe3f78 |
| parent | d97441d37ef08813187f1b44ec29612619104585 |
| signature |
This check isn't valid in such cases, because the source and destination
pointers both refer to zero bits of memory, meaning they effectively
never alias.
Resolves: #216553 files changed, 52 insertions(+), 0 deletions(-)
src/Sema.zig+16| ... | ... | @@ -25928,6 +25928,22 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25928 | 25928 | } |
| 25929 | 25929 | } |
| 25930 | 25930 | |
| 25931 | zero_bit: { | |
| 25932 | const src_comptime = try src_elem_ty.comptimeOnlySema(pt); | |
| 25933 | const dest_comptime = try dest_elem_ty.comptimeOnlySema(pt); | |
| 25934 | assert(src_comptime == dest_comptime); // IMC | |
| 25935 | if (src_comptime) break :zero_bit; | |
| 25936 | ||
| 25937 | const src_has_bits = try src_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt); | |
| 25938 | const dest_has_bits = try dest_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt); | |
| 25939 | assert(src_has_bits == dest_has_bits); // IMC | |
| 25940 | if (src_has_bits) break :zero_bit; | |
| 25941 | ||
| 25942 | // The element type is zero-bit. We've done all validation (aside from the aliasing check, | |
| 25943 | // which we must skip) so we're done. | |
| 25944 | return; | |
| 25945 | } | |
| 25946 | ||
| 25931 | 25947 | const runtime_src = rs: { |
| 25932 | 25948 | const dest_ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src; |
| 25933 | 25949 | const src_ptr_val = try sema.resolveDefinedValue(block, src_src, src_ptr) orelse break :rs src_src; |
src/Type.zig+7| ... | ... | @@ -452,6 +452,13 @@ pub fn hasRuntimeBitsIgnoreComptime(ty: Type, zcu: *const Zcu) bool { |
| 452 | 452 | return hasRuntimeBitsInner(ty, true, .eager, zcu, {}) catch unreachable; |
| 453 | 453 | } |
| 454 | 454 | |
| 455 | pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!bool { | |
| 456 | return hasRuntimeBitsInner(ty, true, .sema, pt.zcu, pt.tid) catch |err| switch (err) { | |
| 457 | error.NeedLazy => unreachable, // this would require a resolve strat of lazy | |
| 458 | else => |e| return e, | |
| 459 | }; | |
| 460 | } | |
| 461 | ||
| 455 | 462 | /// true if and only if the type takes up space in memory at runtime. |
| 456 | 463 | /// There are two reasons a type will return false: |
| 457 | 464 | /// * the type is a comptime-only type. For example, the type `type` itself. |
test/behavior/memcpy.zig+29| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | const expect = std.testing.expect; |
| 4 | const assert = std.debug.assert; | |
| 4 | 5 | |
| 5 | 6 | test "memcpy and memset intrinsics" { |
| 6 | 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| ... | ... | @@ -99,3 +100,31 @@ comptime { |
| 99 | 100 | s.set("hello"); |
| 100 | 101 | if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad"); |
| 101 | 102 | } |
| 103 | ||
| 104 | test "@memcpy comptime-only type" { | |
| 105 | const in: [4]type = .{ u8, u16, u32, u64 }; | |
| 106 | comptime var out: [4]type = undefined; | |
| 107 | @memcpy(&out, &in); | |
| 108 | ||
| 109 | comptime assert(out[0] == u8); | |
| 110 | comptime assert(out[1] == u16); | |
| 111 | comptime assert(out[2] == u32); | |
| 112 | comptime assert(out[3] == u64); | |
| 113 | } | |
| 114 | ||
| 115 | test "@memcpy zero-bit type with aliasing" { | |
| 116 | const S = struct { | |
| 117 | fn doTheTest() void { | |
| 118 | var buf: [3]void = @splat({}); | |
| 119 | const slice: []void = &buf; | |
| 120 | // These two pointers are the same, but it's still not considered aliasing because | |
| 121 | // the input and output slices both correspond to zero bits of memory. | |
| 122 | @memcpy(slice, slice); | |
| 123 | comptime assert(buf[0] == {}); | |
| 124 | comptime assert(buf[1] == {}); | |
| 125 | comptime assert(buf[2] == {}); | |
| 126 | } | |
| 127 | }; | |
| 128 | S.doTheTest(); | |
| 129 | comptime S.doTheTest(); | |
| 130 | } |