authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-23 16:46:50-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-23 16:46:50-04:00
loga2b0b0015d8a0c7aff451ae723ed2f30360ca33f
tree8af430e781e1913c13dbdf5a158e457a03dd965d
parentb872539a13ac46abe57a59bafdf5392812468482
parent41e300adf17bc4056c574b32de4e07f129f2bd24
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11273 from topolarity/bugfix-11272

stage2: Properly "flatten" elem_ptrs before deref

2 files changed, 31 insertions(+), 25 deletions(-)

src/Sema.zig+10-25
...@@ -17045,17 +17045,9 @@ fn elemVal(...@@ -17045,17 +17045,9 @@ fn elemVal(
17045 const indexable_val = maybe_indexable_val orelse break :rs indexable_src;17045 const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
17046 const index_val = maybe_index_val orelse break :rs elem_index_src;17046 const index_val = maybe_index_val orelse break :rs elem_index_src;
17047 const index = @intCast(usize, index_val.toUnsignedInt(target));17047 const index = @intCast(usize, index_val.toUnsignedInt(target));
17048 const elem_ty = indexable_ty.elemType2();17048 const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, target);
17049
17050 var payload: Value.Payload.ElemPtr = .{ .data = .{
17051 .array_ptr = indexable_val,
17052 .elem_ty = elem_ty,
17053 .index = index,
17054 } };
17055 const elem_ptr_val = Value.initPayload(&payload.base);
17056
17057 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| {17049 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| {
17058 return sema.addConstant(elem_ty, elem_val);17050 return sema.addConstant(indexable_ty.elemType2(), elem_val);
17059 }17051 }
17060 break :rs indexable_src;17052 break :rs indexable_src;
17061 };17053 };
...@@ -17310,12 +17302,7 @@ fn elemValSlice(...@@ -17310,12 +17302,7 @@ fn elemValSlice(
17310 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";17302 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
17311 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });17303 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
17312 }17304 }
17313 var elem_ptr_pl: Value.Payload.ElemPtr = .{ .data = .{17305 const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, target);
17314 .array_ptr = slice_val.slicePtr(),
17315 .elem_ty = elem_ty,
17316 .index = index,
17317 } };
17318 const elem_ptr_val = Value.initPayload(&elem_ptr_pl.base);
17319 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| {17306 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| {
17320 return sema.addConstant(elem_ty, elem_val);17307 return sema.addConstant(elem_ty, elem_val);
17321 }17308 }
...@@ -18765,6 +18752,11 @@ fn beginComptimePtrLoad(...@@ -18765,6 +18752,11 @@ fn beginComptimePtrLoad(
18765 const elem_ty = elem_ptr.elem_ty;18752 const elem_ty = elem_ptr.elem_ty;
18766 var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);18753 var deref = try beginComptimePtrLoad(sema, block, src, elem_ptr.array_ptr, null);
1876718754
18755 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
18756 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
18757 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
18758 if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, target)));
18759
18768 if (elem_ptr.index != 0) {18760 if (elem_ptr.index != 0) {
18769 if (elem_ty.hasWellDefinedLayout()) {18761 if (elem_ty.hasWellDefinedLayout()) {
18770 if (deref.parent) |*parent| {18762 if (deref.parent) |*parent| {
...@@ -18793,13 +18785,6 @@ fn beginComptimePtrLoad(...@@ -18793,13 +18785,6 @@ fn beginComptimePtrLoad(
1879318785
18794 var array_tv = deref.pointee.?;18786 var array_tv = deref.pointee.?;
18795 const check_len = array_tv.ty.arrayLenIncludingSentinel();18787 const check_len = array_tv.ty.arrayLenIncludingSentinel();
18796 if (elem_ptr.index >= check_len) {
18797 // TODO have the deref include the decl so we can say "declared here"
18798 return sema.fail(block, src, "comptime load of index {d} out of bounds of array length {d}", .{
18799 elem_ptr.index, check_len,
18800 });
18801 }
18802
18803 if (maybe_array_ty) |load_ty| {18788 if (maybe_array_ty) |load_ty| {
18804 // It's possible that we're loading a [N]T, in which case we'd like to slice18789 // It's possible that we're loading a [N]T, in which case we'd like to slice
18805 // the pointee array directly from our parent array.18790 // the pointee array directly from our parent array.
...@@ -18813,10 +18798,10 @@ fn beginComptimePtrLoad(...@@ -18813,10 +18798,10 @@ fn beginComptimePtrLoad(
18813 }18798 }
18814 }18799 }
1881518800
18816 deref.pointee = .{18801 deref.pointee = if (elem_ptr.index < check_len) TypedValue{
18817 .ty = elem_ty,18802 .ty = elem_ty,
18818 .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),18803 .val = try array_tv.val.elemValue(sema.arena, elem_ptr.index),
18819 };18804 } else null;
18820 break :blk deref;18805 break :blk deref;
18821 },18806 },
1882218807
test/behavior/eval.zig+21
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const assert = std.debug.assert;
3const expect = std.testing.expect;4const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
56
...@@ -830,3 +831,23 @@ test "const type-annotated local initialized with function call has correct type...@@ -830,3 +831,23 @@ test "const type-annotated local initialized with function call has correct type
830 try expect(@TypeOf(x) == u64);831 try expect(@TypeOf(x) == u64);
831 try expect(x == 1234);832 try expect(x == 1234);
832}833}
834
835test "comptime pointer load through elem_ptr" {
836 const S = struct {
837 x: usize,
838 };
839
840 comptime {
841 var array: [10]S = undefined;
842 for (array) |*elem, i| {
843 elem.* = .{
844 .x = i,
845 };
846 }
847 var ptr = @ptrCast([*]S, &array);
848 var x = ptr[0].x;
849 assert(x == 0);
850 ptr += 1;
851 assert(ptr[1].x == 2);
852 }
853}