Skip to content

Commit 6d89d7b

Browse files
committed
Fix Sema unreachable when shfting by vector containing undef elems
Added additional checks for undefined values and vectors containing undefined elements in `zirShl` and `zirShr`. This also fixes a bug when shifting by a partially undefined vector that reached unreachable in `compareHetero` and `getUnsignedInt`. This patch pretends that `Value.isUndefDeep()` is already implemented (TBC).
1 parent 6ec275e commit 6d89d7b

File tree

2 files changed

+22
-20
lines changed

2 files changed

+22
-20
lines changed

src/Sema.zig

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13572,8 +13572,8 @@ fn zirShl(
1357213572
const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs);
1357313573

1357413574
if (maybe_rhs_val) |rhs_val| {
13575-
if (rhs_val.isUndef(zcu)) {
13576-
return pt.undefRef(sema.typeOf(lhs));
13575+
if (rhs_val.anyScalarIsUndef(zcu)) {
13576+
return sema.failWithUseOfUndef(block, rhs_src);
1357713577
}
1357813578
// If rhs is 0, return lhs without doing any calculations.
1357913579
if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {
@@ -13621,7 +13621,9 @@ fn zirShl(
1362113621
}
1362213622

1362313623
const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
13624-
if (lhs_val.isUndef(zcu)) return pt.undefRef(lhs_ty);
13624+
if (lhs_val.anyScalarIsUndef(zcu)) {
13625+
return sema.failWithUseOfUndef(block, lhs_src);
13626+
}
1362513627
const rhs_val = maybe_rhs_val orelse {
1362613628
if (scalar_ty.zigTypeTag(zcu) == .comptime_int) {
1362713629
return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{});
@@ -13753,8 +13755,10 @@ fn zirShr(
1375313755
const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs);
1375413756

1375513757
const runtime_src = if (maybe_rhs_val) |rhs_val| rs: {
13756-
if (rhs_val.isUndef(zcu)) {
13757-
return pt.undefRef(lhs_ty);
13758+
switch (air_tag) {
13759+
.shr => if (rhs_val.isUndefDeep(zcu)) return pt.undefRef(lhs_ty),
13760+
.shr_exact => if (rhs_val.anyScalarIsUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src),
13761+
else => unreachable,
1375813762
}
1375913763
// If rhs is 0, return lhs without doing any calculations.
1376013764
if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {
@@ -13766,6 +13770,7 @@ fn zirShr(
1376613770
var i: usize = 0;
1376713771
while (i < rhs_ty.vectorLen(zcu)) : (i += 1) {
1376813772
const rhs_elem = try rhs_val.elemValue(pt, i);
13773+
if (rhs_elem.isUndef(zcu)) continue;
1376913774
if (rhs_elem.compareHetero(.gte, bit_value, zcu)) {
1377013775
return sema.fail(block, rhs_src, "shift amount '{f}' at index '{d}' is too large for operand type '{f}'", .{
1377113776
rhs_elem.fmtValueSema(pt, sema),
@@ -13785,6 +13790,7 @@ fn zirShr(
1378513790
var i: usize = 0;
1378613791
while (i < rhs_ty.vectorLen(zcu)) : (i += 1) {
1378713792
const rhs_elem = try rhs_val.elemValue(pt, i);
13793+
if (rhs_elem.isUndef(zcu)) continue;
1378813794
if (rhs_elem.compareHetero(.lt, try pt.intValue(rhs_ty.childType(zcu), 0), zcu)) {
1378913795
return sema.fail(block, rhs_src, "shift by negative amount '{f}' at index '{d}'", .{
1379013796
rhs_elem.fmtValueSema(pt, sema),
@@ -13798,15 +13804,17 @@ fn zirShr(
1379813804
});
1379913805
}
1380013806
if (maybe_lhs_val) |lhs_val| {
13801-
if (lhs_val.isUndef(zcu)) {
13802-
return pt.undefRef(lhs_ty);
13803-
}
13804-
if (air_tag == .shr_exact) {
13805-
// Detect if any ones would be shifted out.
13806-
const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, pt);
13807-
if (!(try truncated.compareAllWithZeroSema(.eq, pt))) {
13808-
return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
13809-
}
13807+
switch (air_tag) {
13808+
.shr => if (lhs_val.isUndefDeep(zcu)) return pt.undefRef(lhs_ty),
13809+
.shr_exact => {
13810+
if (lhs_val.anyScalarIsUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src);
13811+
// Detect if any ones would be shifted out.
13812+
const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, pt);
13813+
if (!(try truncated.compareAllWithZeroSema(.eq, pt))) {
13814+
return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
13815+
}
13816+
},
13817+
else => unreachable,
1381013818
}
1381113819
const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, pt);
1381213820
return Air.internedToRef(val.toIntern());

test/behavior/bit_shifting.zig

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,6 @@ test "Saturating Shift Left where lhs is of a computed type" {
154154
try expect(value.exponent == 0);
155155
}
156156

157-
comptime {
158-
var image: [1]u8 = undefined;
159-
_ = &image;
160-
_ = @shlExact(@as(u16, image[0]), 8);
161-
}
162-
163157
test "Saturating Shift Left" {
164158
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
165159
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;

0 commit comments

Comments
 (0)