authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-28 17:13:43+03:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-06-30 09:57:38+02:00
log2e7dc5e15192431c64eca458ecfdce3d07b89f69
treeabaf49ad2840c5ac799105e79dd0b536daed30ba
parent03b356e34af37d74cf92087c0303a1b2c74d3afc

Sema: improve vector overflow errors


5 files changed, 62 insertions(+), 46 deletions(-)

src/Sema.zig+35-17
...@@ -139,6 +139,7 @@ pub const Block = struct {...@@ -139,6 +139,7 @@ pub const Block = struct {
139139
140 is_comptime: bool,140 is_comptime: bool,
141 is_typeof: bool = false,141 is_typeof: bool = false,
142 is_coerce_result_ptr: bool = false,
142143
143 /// when null, it is determined by build mode, changed by @setRuntimeSafety144 /// when null, it is determined by build mode, changed by @setRuntimeSafety
144 want_safety: ?bool = null,145 want_safety: ?bool = null,
...@@ -1734,9 +1735,20 @@ fn failWithErrorSetCodeMissing(...@@ -1734,9 +1735,20 @@ fn failWithErrorSetCodeMissing(
1734 });1735 });
1735}1736}
17361737
1737fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value) CompileError {1738fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
1739 if (int_ty.zigTypeTag() == .Vector) {
1740 const msg = msg: {
1741 const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
1742 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
1743 });
1744 errdefer msg.destroy(sema.gpa);
1745 try sema.errNote(block, src, msg, "when computing vector element at index '{d}'", .{vector_index});
1746 break :msg msg;
1747 };
1748 return sema.failWithOwnedErrorMsg(block, msg);
1749 }
1738 return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{1750 return sema.fail(block, src, "overflow of integer type '{}' with value '{}'", .{
1739 int_ty.fmt(sema.mod), val.fmtValue(Type.@"comptime_int", sema.mod),1751 int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
1740 });1752 });
1741}1753}
17421754
...@@ -1971,6 +1983,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -1971,6 +1983,7 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
1971 // kind of transformations to make on the result pointer.1983 // kind of transformations to make on the result pointer.
1972 var trash_block = block.makeSubBlock();1984 var trash_block = block.makeSubBlock();
1973 trash_block.is_comptime = false;1985 trash_block.is_comptime = false;
1986 trash_block.is_coerce_result_ptr = true;
1974 defer trash_block.instructions.deinit(sema.gpa);1987 defer trash_block.instructions.deinit(sema.gpa);
19751988
1976 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));1989 const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
...@@ -10453,8 +10466,9 @@ fn analyzeArithmetic(...@@ -10453,8 +10466,9 @@ fn analyzeArithmetic(
10453 if (maybe_rhs_val) |rhs_val| {10466 if (maybe_rhs_val) |rhs_val| {
10454 if (is_int) {10467 if (is_int) {
10455 const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type);10468 const sum = try sema.intAdd(block, src, lhs_val, rhs_val, resolved_type);
10456 if (!(try sema.intFitsInType(block, src, sum, resolved_type))) {10469 var vector_index: usize = undefined;
10457 return sema.failWithIntegerOverflow(block, src, resolved_type, sum);10470 if (!(try sema.intFitsInType(block, src, sum, resolved_type, &vector_index))) {
10471 return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index);
10458 }10472 }
10459 return sema.addConstant(resolved_type, sum);10473 return sema.addConstant(resolved_type, sum);
10460 } else {10474 } else {
...@@ -10547,8 +10561,9 @@ fn analyzeArithmetic(...@@ -10547,8 +10561,9 @@ fn analyzeArithmetic(
10547 if (maybe_rhs_val) |rhs_val| {10561 if (maybe_rhs_val) |rhs_val| {
10548 if (is_int) {10562 if (is_int) {
10549 const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type);10563 const diff = try sema.intSub(block, src, lhs_val, rhs_val, resolved_type);
10550 if (!(try sema.intFitsInType(block, src, diff, resolved_type))) {10564 var vector_index: usize = undefined;
10551 return sema.failWithIntegerOverflow(block, src, resolved_type, diff);10565 if (!(try sema.intFitsInType(block, src, diff, resolved_type, &vector_index))) {
10566 return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index);
10552 }10567 }
10553 return sema.addConstant(resolved_type, diff);10568 return sema.addConstant(resolved_type, diff);
10554 } else {10569 } else {
...@@ -10921,8 +10936,9 @@ fn analyzeArithmetic(...@@ -10921,8 +10936,9 @@ fn analyzeArithmetic(
10921 }10936 }
10922 if (is_int) {10937 if (is_int) {
10923 const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target);10938 const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, target);
10924 if (!(try sema.intFitsInType(block, src, product, resolved_type))) {10939 var vector_index: usize = undefined;
10925 return sema.failWithIntegerOverflow(block, src, resolved_type, product);10940 if (!(try sema.intFitsInType(block, src, product, resolved_type, &vector_index))) {
10941 return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index);
10926 }10942 }
10927 return sema.addConstant(resolved_type, product);10943 return sema.addConstant(resolved_type, product);
10928 } else {10944 } else {
...@@ -16456,15 +16472,15 @@ fn analyzeShuffle(...@@ -16456,15 +16472,15 @@ fn analyzeShuffle(
16456 }16472 }
16457 if (unsigned >= operand_info[chosen][0]) {16473 if (unsigned >= operand_info[chosen][0]) {
16458 const msg = msg: {16474 const msg = msg: {
16459 const msg = try sema.errMsg(block, mask_src, "mask index {d} has out-of-bounds selection", .{i});16475 const msg = try sema.errMsg(block, mask_src, "mask index '{d}' has out-of-bounds selection", .{i});
16460 errdefer msg.destroy(sema.gpa);16476 errdefer msg.destroy(sema.gpa);
1646116477
16462 try sema.errNote(block, operand_info[chosen][1], msg, "selected index {d} out of bounds of '{}'", .{16478 try sema.errNote(block, operand_info[chosen][1], msg, "selected index '{d}' out of bounds of '{}'", .{
16463 unsigned,16479 unsigned,
16464 operand_info[chosen][2].fmt(sema.mod),16480 operand_info[chosen][2].fmt(sema.mod),
16465 });16481 });
1646616482
16467 if (chosen == 1) {16483 if (chosen == 0) {
16468 try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{});16484 try sema.errNote(block, b_src, msg, "selections from the second vector are specified with negative numbers", .{});
16469 }16485 }
1647016486
...@@ -17750,7 +17766,7 @@ fn zirBuiltinExtern(...@@ -17750,7 +17766,7 @@ fn zirBuiltinExtern(
17750}17766}
1775117767
17752fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {17768fn requireFunctionBlock(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
17753 if (sema.func == null and !block.is_typeof) {17769 if (sema.func == null and !block.is_typeof and !block.is_coerce_result_ptr) {
17754 return sema.fail(block, src, "instruction illegal outside function body", .{});17770 return sema.fail(block, src, "instruction illegal outside function body", .{});
17755 }17771 }
17756}17772}
...@@ -19881,7 +19897,7 @@ fn coerce(...@@ -19881,7 +19897,7 @@ fn coerce(
19881 .Int, .ComptimeInt => {19897 .Int, .ComptimeInt => {
19882 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {19898 if (try sema.resolveDefinedValue(block, inst_src, inst)) |val| {
19883 // comptime known integer to other number19899 // comptime known integer to other number
19884 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty))) {19900 if (!(try sema.intFitsInType(block, inst_src, val, dest_ty, null))) {
19885 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });19901 return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
19886 }19902 }
19887 return try sema.addConstant(dest_ty, val);19903 return try sema.addConstant(dest_ty, val);
...@@ -25829,7 +25845,7 @@ fn floatToIntScalar(...@@ -25829,7 +25845,7 @@ fn floatToIntScalar(
25829 else25845 else
25830 try Value.Tag.int_big_positive.create(sema.arena, result_limbs);25846 try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
2583125847
25832 if (!(try sema.intFitsInType(block, src, result, int_ty))) {25848 if (!(try sema.intFitsInType(block, src, result, int_ty, null))) {
25833 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{25849 return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
25834 val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),25850 val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
25835 });25851 });
...@@ -25845,6 +25861,7 @@ fn intFitsInType(...@@ -25845,6 +25861,7 @@ fn intFitsInType(
25845 src: LazySrcLoc,25861 src: LazySrcLoc,
25846 self: Value,25862 self: Value,
25847 ty: Type,25863 ty: Type,
25864 vector_index: ?*usize,
25848) CompileError!bool {25865) CompileError!bool {
25849 const target = sema.mod.getTarget();25866 const target = sema.mod.getTarget();
25850 switch (self.tag()) {25867 switch (self.tag()) {
...@@ -25954,8 +25971,9 @@ fn intFitsInType(...@@ -25954,8 +25971,9 @@ fn intFitsInType(
2595425971
25955 .aggregate => {25972 .aggregate => {
25956 assert(ty.zigTypeTag() == .Vector);25973 assert(ty.zigTypeTag() == .Vector);
25957 for (self.castTag(.aggregate).?.data) |elem| {25974 for (self.castTag(.aggregate).?.data) |elem, i| {
25958 if (!(try sema.intFitsInType(block, src, elem, ty.scalarType()))) {25975 if (!(try sema.intFitsInType(block, src, elem, ty.scalarType(), null))) {
25976 if (vector_index) |some| some.* = i;
25959 return false;25977 return false;
25960 }25978 }
25961 }25979 }
...@@ -25993,7 +26011,7 @@ fn enumHasInt(...@@ -25993,7 +26011,7 @@ fn enumHasInt(
25993 int: Value,26011 int: Value,
25994) CompileError!bool {26012) CompileError!bool {
25995 switch (ty.tag()) {26013 switch (ty.tag()) {
25996 .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty),26014 .enum_nonexhaustive => return sema.intFitsInType(block, src, int, ty, null),
25997 .enum_full => {26015 .enum_full => {
25998 const enum_full = ty.castTag(.enum_full).?.data;26016 const enum_full = ty.castTag(.enum_full).?.data;
25999 const tag_ty = enum_full.tag_ty;26017 const tag_ty = enum_full.tag_ty;
test/cases/compile_errors/comptime_vector_overflow_shows_the_index.zig created+13
...@@ -0,0 +1,13 @@
1comptime {
2 var a: @import("std").meta.Vector(4, u8) = [_]u8{ 1, 2, 255, 4 };
3 var b: @import("std").meta.Vector(4, u8) = [_]u8{ 5, 6, 1, 8 };
4 var x = a + b;
5 _ = x;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :4:15: error: overflow of vector type '@Vector(4, u8)' with value '.{ 6, 8, 256, 12 }'
13// :4:15: note: when computing vector element at index '2'
test/cases/compile_errors/shuffle_with_selected_index_past_first_vector_length.zig created+14
...@@ -0,0 +1,14 @@
1export fn entry() void {
2 const v: @import("std").meta.Vector(4, u32) = [4]u32{ 10, 11, 12, 13 };
3 const x: @import("std").meta.Vector(4, u32) = [4]u32{ 14, 15, 16, 17 };
4 var z = @shuffle(u32, v, x, [8]i32{ 0, 1, 2, 3, 7, 6, 5, 4 });
5 _ = z;
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :4:39: error: mask index '4' has out-of-bounds selection
13// :4:27: note: selected index '7' out of bounds of '@Vector(4, u32)'
14// :4:30: note: selections from the second vector are specified with negative numbers
test/cases/compile_errors/stage1/test/comptime_vector_overflow_shows_the_index.zig deleted-14
...@@ -1,14 +0,0 @@
1comptime {
2 var a: @import("std").meta.Vector(4, u8) = [_]u8{ 1, 2, 255, 4 };
3 var b: @import("std").meta.Vector(4, u8) = [_]u8{ 5, 6, 1, 8 };
4 var x = a + b;
5 _ = x;
6}
7
8// error
9// backend=stage1
10// target=native
11// is_test=1
12//
13// tmp.zig:4:15: error: operation caused overflow
14// tmp.zig:4:15: note: when computing vector element at index 2
test/cases/compile_errors/stage1/test/shuffle_with_selected_index_past_first_vector_length.zig deleted-15
...@@ -1,15 +0,0 @@
1export fn entry() void {
2 const v: @import("std").meta.Vector(4, u32) = [4]u32{ 10, 11, 12, 13 };
3 const x: @import("std").meta.Vector(4, u32) = [4]u32{ 14, 15, 16, 17 };
4 var z = @shuffle(u32, v, x, [8]i32{ 0, 1, 2, 3, 7, 6, 5, 4 });
5 _ = z;
6}
7
8// error
9// backend=stage1
10// target=native
11// is_test=1
12//
13// tmp.zig:4:39: error: mask index '4' has out-of-bounds selection
14// tmp.zig:4:27: note: selected index '7' out of bounds of @Vector(4, u32)
15// tmp.zig:4:30: note: selections from the second vector are specified with negative numbers