| author | |
| committer | |
| log | 05cff8a558fda0e974ea7d00f26f8f4ff6e1195f |
| tree | c99a4d2366532e5937ca7f944eb0008601a4edce |
| parent | 426d65d700012b27ffa652258554032f171ad77d |
| parent | 7666d5fc2653023670f6e61b6d19b0ba15750d67 |
| signature |
frontend: vectors and arrays no longer support in-memory coercion9 files changed, 36 insertions(+), 50 deletions(-)
doc/langref.html.in+8| ... | @@ -1969,6 +1969,14 @@ or | ... | @@ -1969,6 +1969,14 @@ or |
| 1969 | </p> | 1969 | </p> |
| 1970 | {#see_also|@splat|@shuffle|@select|@reduce#} | 1970 | {#see_also|@splat|@shuffle|@select|@reduce#} |
| 1971 | 1971 | ||
| 1972 | {#header_open|Relationship with Arrays#} | ||
| 1973 | <p>Vectors and {#link|Arrays#} each have a well-defined <strong>bit layout</strong> | ||
| 1974 | and therefore support {#link|@bitCast#} between each other. {#link|Type Coercion#} implicitly peforms | ||
| 1975 | {#syntax#}@bitCast{#endsyntax#}.</p> | ||
| 1976 | <p>Arrays have well-defined byte layout, but vectors do not, making {#link|@ptrCast#} between | ||
| 1977 | them {#link|Illegal Behavior#}.</p> | ||
| 1978 | {#header_close#} | ||
| 1979 | |||
| 1972 | {#header_open|Destructuring Vectors#} | 1980 | {#header_open|Destructuring Vectors#} |
| 1973 | <p> | 1981 | <p> |
| 1974 | Vectors can be destructured: | 1982 | Vectors can be destructured: |
doc/langref/test_vector.zig+1-1| ... | @@ -17,7 +17,7 @@ test "Basic vector usage" { | ... | @@ -17,7 +17,7 @@ test "Basic vector usage" { |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | test "Conversion between vectors, arrays, and slices" { | 19 | test "Conversion between vectors, arrays, and slices" { |
| 20 | // Vectors and fixed-length arrays can be automatically assigned back and forth | 20 | // Vectors can be coerced to arrays, and vice versa. |
| 21 | const arr1: [4]f32 = [_]f32{ 1.1, 3.2, 4.5, 5.6 }; | 21 | const arr1: [4]f32 = [_]f32{ 1.1, 3.2, 4.5, 5.6 }; |
| 22 | const vec: @Vector(4, f32) = arr1; | 22 | const vec: @Vector(4, f32) = arr1; |
| 23 | const arr2: [4]f32 = vec; | 23 | const arr2: [4]f32 = vec; |
lib/std/debug.zig+1-1| ... | @@ -569,7 +569,7 @@ pub fn assertReadable(slice: []const volatile u8) void { | ... | @@ -569,7 +569,7 @@ pub fn assertReadable(slice: []const volatile u8) void { |
| 569 | /// Invokes detectable illegal behavior when the provided array is not aligned | 569 | /// Invokes detectable illegal behavior when the provided array is not aligned |
| 570 | /// to the provided amount. | 570 | /// to the provided amount. |
| 571 | pub fn assertAligned(ptr: anytype, comptime alignment: std.mem.Alignment) void { | 571 | pub fn assertAligned(ptr: anytype, comptime alignment: std.mem.Alignment) void { |
| 572 | const aligned_ptr: *align(alignment.toByteUnits()) anyopaque = @ptrCast(@alignCast(ptr)); | 572 | const aligned_ptr: *align(alignment.toByteUnits()) const anyopaque = @ptrCast(@alignCast(ptr)); |
| 573 | _ = aligned_ptr; | 573 | _ = aligned_ptr; |
| 574 | } | 574 | } |
| 575 | 575 |
lib/std/mem.zig+3-3| ... | @@ -1156,10 +1156,10 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co | ... | @@ -1156,10 +1156,10 @@ pub fn indexOfSentinel(comptime T: type, comptime sentinel: T, p: [*:sentinel]co |
| 1156 | } | 1156 | } |
| 1157 | } | 1157 | } |
| 1158 | 1158 | ||
| 1159 | assert(std.mem.isAligned(@intFromPtr(&p[i]), block_size)); | 1159 | std.debug.assertAligned(&p[i], .fromByteUnits(block_size)); |
| 1160 | while (true) { | 1160 | while (true) { |
| 1161 | const block: *const Block = @ptrCast(@alignCast(p[i..][0..block_len])); | 1161 | const block: Block = p[i..][0..block_len].*; |
| 1162 | const matches = block.* == mask; | 1162 | const matches = block == mask; |
| 1163 | if (@reduce(.Or, matches)) { | 1163 | if (@reduce(.Or, matches)) { |
| 1164 | return i + std.simd.firstTrue(matches).?; | 1164 | return i + std.simd.firstTrue(matches).?; |
| 1165 | } | 1165 | } |
src/Sema.zig-44| ... | @@ -29649,50 +29649,6 @@ pub fn coerceInMemoryAllowed( | ... | @@ -29649,50 +29649,6 @@ pub fn coerceInMemoryAllowed( |
| 29649 | return .ok; | 29649 | return .ok; |
| 29650 | } | 29650 | } |
| 29651 | 29651 | ||
| 29652 | // Arrays <-> Vectors | ||
| 29653 | if ((dest_tag == .vector and src_tag == .array) or | ||
| 29654 | (dest_tag == .array and src_tag == .vector)) | ||
| 29655 | { | ||
| 29656 | const dest_len = dest_ty.arrayLen(zcu); | ||
| 29657 | const src_len = src_ty.arrayLen(zcu); | ||
| 29658 | if (dest_len != src_len) { | ||
| 29659 | return .{ .array_len = .{ | ||
| 29660 | .actual = src_len, | ||
| 29661 | .wanted = dest_len, | ||
| 29662 | } }; | ||
| 29663 | } | ||
| 29664 | |||
| 29665 | const dest_elem_ty = dest_ty.childType(zcu); | ||
| 29666 | const src_elem_ty = src_ty.childType(zcu); | ||
| 29667 | const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src, null); | ||
| 29668 | if (child != .ok) { | ||
| 29669 | return .{ .array_elem = .{ | ||
| 29670 | .child = try child.dupe(sema.arena), | ||
| 29671 | .actual = src_elem_ty, | ||
| 29672 | .wanted = dest_elem_ty, | ||
| 29673 | } }; | ||
| 29674 | } | ||
| 29675 | |||
| 29676 | if (dest_tag == .array) { | ||
| 29677 | const dest_info = dest_ty.arrayInfo(zcu); | ||
| 29678 | if (dest_info.sentinel != null) { | ||
| 29679 | return .{ .array_sentinel = .{ | ||
| 29680 | .actual = Value.@"unreachable", | ||
| 29681 | .wanted = dest_info.sentinel.?, | ||
| 29682 | .ty = dest_info.elem_type, | ||
| 29683 | } }; | ||
| 29684 | } | ||
| 29685 | } | ||
| 29686 | |||
| 29687 | // The memory layout of @Vector(N, iM) is the same as the integer type i(N*M), | ||
| 29688 | // that is to say, the padding bits are not in the same place as the array [N]iM. | ||
| 29689 | // If there's no padding, the bitcast is possible. | ||
| 29690 | const elem_bit_size = dest_elem_ty.bitSize(zcu); | ||
| 29691 | const elem_abi_byte_size = dest_elem_ty.abiSize(zcu); | ||
| 29692 | if (elem_abi_byte_size * 8 == elem_bit_size) | ||
| 29693 | return .ok; | ||
| 29694 | } | ||
| 29695 | |||
| 29696 | // Optionals | 29652 | // Optionals |
| 29697 | if (dest_tag == .optional and src_tag == .optional) { | 29653 | if (dest_tag == .optional and src_tag == .optional) { |
| 29698 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { | 29654 | if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) { |
test/behavior/cast.zig+1| ... | @@ -1737,6 +1737,7 @@ test "peer type resolution: array and vector with same child type" { | ... | @@ -1737,6 +1737,7 @@ test "peer type resolution: array and vector with same child type" { |
| 1737 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1737 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1738 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 1738 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 1739 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO | 1739 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO |
| 1740 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | ||
| 1740 | 1741 | ||
| 1741 | var arr: [2]u32 = .{ 0, 1 }; | 1742 | var arr: [2]u32 = .{ 0, 1 }; |
| 1742 | var vec: @Vector(2, u32) = .{ 2, 3 }; | 1743 | var vec: @Vector(2, u32) = .{ 2, 3 }; |
test/behavior/union.zig+5-1| ... | @@ -103,7 +103,11 @@ test "basic extern unions" { | ... | @@ -103,7 +103,11 @@ test "basic extern unions" { |
| 103 | var foo = FooExtern{ .int = 1 }; | 103 | var foo = FooExtern{ .int = 1 }; |
| 104 | try expect(foo.int == 1); | 104 | try expect(foo.int == 1); |
| 105 | foo.str.slice = "Well"; | 105 | foo.str.slice = "Well"; |
| 106 | try expect(std.mem.eql(u8, std.mem.sliceTo(foo.str.slice, 0), "Well")); | 106 | try expect(foo.str.slice[0] == 'W'); |
| 107 | try expect(foo.str.slice[1] == 'e'); | ||
| 108 | try expect(foo.str.slice[2] == 'l'); | ||
| 109 | try expect(foo.str.slice[3] == 'l'); | ||
| 110 | try expect(foo.str.slice[4] == 0); | ||
| 107 | } | 111 | } |
| 108 | 112 | ||
| 109 | const ExternPtrOrInt = extern union { | 113 | const ExternPtrOrInt = extern union { |
test/behavior/vector.zig+1| ... | @@ -196,6 +196,7 @@ test "array to vector" { | ... | @@ -196,6 +196,7 @@ test "array to vector" { |
| 196 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 196 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 197 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 197 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 198 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; | 198 | if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; |
| 199 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | ||
| 199 | 200 | ||
| 200 | const S = struct { | 201 | const S = struct { |
| 201 | fn doTheTest() !void { | 202 | fn doTheTest() !void { |
test/cases/compile_errors/in_memory_coerce_vector_to_array.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | export fn entry() void { | ||
| 2 | _ = foo() catch {}; | ||
| 3 | } | ||
| 4 | fn foo() anyerror![4]u32 { | ||
| 5 | return bar(); | ||
| 6 | } | ||
| 7 | fn bar() anyerror!@Vector(4, u32) { | ||
| 8 | return .{ 1, 2, 3, 4 }; | ||
| 9 | } | ||
| 10 | // error | ||
| 11 | // backend=stage2 | ||
| 12 | // target=native | ||
| 13 | // | ||
| 14 | // :5:15: error: expected type 'anyerror![4]u32', found 'anyerror!@Vector(4, u32)' | ||
| 15 | // :5:15: note: error union payload '@Vector(4, u32)' cannot cast into error union payload '[4]u32' | ||
| 16 | // :4:18: note: function return type declared here | ||