authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-01 21:08:31+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-07 10:50:06+03:00
logc07c2d68c7c8276f8d215cfd21f0dcd92db9cf79
treebb4303a3dfd20e114cd6223055d665775badf996
parent1569b9c16590f8c5359003ae310093217e5fcf63

Sema: more runtime indexing comptime value checks


17 files changed, 153 insertions(+), 143 deletions(-)

src/Sema.zig+40-36
...@@ -19494,6 +19494,34 @@ fn elemVal(...@@ -19494,6 +19494,34 @@ fn elemVal(
19494 }19494 }
19495}19495}
1949619496
19497fn validateRuntimeElemAccess(
19498 sema: *Sema,
19499 block: *Block,
19500 elem_index_src: LazySrcLoc,
19501 elem_ty: Type,
19502 parent_ty: Type,
19503 parent_src: LazySrcLoc,
19504) CompileError!void {
19505 const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false);
19506 if (!valid_rt) {
19507 const msg = msg: {
19508 const msg = try sema.errMsg(
19509 block,
19510 elem_index_src,
19511 "values of type '{}' must be comptime known, but index value is runtime known",
19512 .{parent_ty.fmt(sema.mod)},
19513 );
19514 errdefer msg.destroy(sema.gpa);
19515
19516 const src_decl = sema.mod.declPtr(block.src_decl);
19517 try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, parent_src.toSrcLoc(src_decl), parent_ty);
19518
19519 break :msg msg;
19520 };
19521 return sema.failWithOwnedErrorMsg(block, msg);
19522 }
19523}
19524
19497fn tupleFieldPtr(19525fn tupleFieldPtr(
19498 sema: *Sema,19526 sema: *Sema,
19499 block: *Block,19527 block: *Block,
...@@ -19534,6 +19562,8 @@ fn tupleFieldPtr(...@@ -19534,6 +19562,8 @@ fn tupleFieldPtr(
19534 );19562 );
19535 }19563 }
1953619564
19565 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src);
19566
19537 try sema.requireRuntimeBlock(block, tuple_ptr_src);19567 try sema.requireRuntimeBlock(block, tuple_ptr_src);
19538 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);19568 return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty);
19539}19569}
...@@ -19572,6 +19602,8 @@ fn tupleField(...@@ -19572,6 +19602,8 @@ fn tupleField(
19572 return sema.addConstant(field_ty, field_values[field_index]);19602 return sema.addConstant(field_ty, field_values[field_index]);
19573 }19603 }
1957419604
19605 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
19606
19575 try sema.requireRuntimeBlock(block, tuple_src);19607 try sema.requireRuntimeBlock(block, tuple_src);
19576 return block.addStructFieldVal(tuple, field_index, field_ty);19608 return block.addStructFieldVal(tuple, field_index, field_ty);
19577}19609}
...@@ -19622,24 +19654,7 @@ fn elemValArray(...@@ -19622,24 +19654,7 @@ fn elemValArray(
19622 }19654 }
19623 }19655 }
1962419656
19625 const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false);19657 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
19626 if (!valid_rt) {
19627 const msg = msg: {
19628 const msg = try sema.errMsg(
19629 block,
19630 elem_index_src,
19631 "values of type '{}' must be comptime known, but index value is runtime known",
19632 .{array_ty.fmt(sema.mod)},
19633 );
19634 errdefer msg.destroy(sema.gpa);
19635
19636 const src_decl = sema.mod.declPtr(block.src_decl);
19637 try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, array_src.toSrcLoc(src_decl), array_ty);
19638
19639 break :msg msg;
19640 };
19641 return sema.failWithOwnedErrorMsg(block, msg);
19642 }
1964319658
19644 const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;19659 const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src;
19645 try sema.requireRuntimeBlock(block, runtime_src);19660 try sema.requireRuntimeBlock(block, runtime_src);
...@@ -19697,23 +19712,8 @@ fn elemPtrArray(...@@ -19697,23 +19712,8 @@ fn elemPtrArray(
19697 }19712 }
19698 }19713 }
1969919714
19700 const valid_rt = try sema.validateRunTimeType(block, elem_index_src, array_ty.elemType2(), false);19715 if (!init) {
19701 if (!valid_rt and !init) {19716 try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(), array_ty, array_ptr_src);
19702 const msg = msg: {
19703 const msg = try sema.errMsg(
19704 block,
19705 elem_index_src,
19706 "values of type '{}' must be comptime known, but index value is runtime known",
19707 .{array_ty.fmt(sema.mod)},
19708 );
19709 errdefer msg.destroy(sema.gpa);
19710
19711 const src_decl = sema.mod.declPtr(block.src_decl);
19712 try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, array_ptr_src.toSrcLoc(src_decl), array_ty);
19713
19714 break :msg msg;
19715 };
19716 return sema.failWithOwnedErrorMsg(block, msg);
19717 }19717 }
1971819718
19719 const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;19719 const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;
...@@ -19769,6 +19769,8 @@ fn elemValSlice(...@@ -19769,6 +19769,8 @@ fn elemValSlice(
19769 }19769 }
19770 }19770 }
1977119771
19772 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
19773
19772 try sema.requireRuntimeBlock(block, runtime_src);19774 try sema.requireRuntimeBlock(block, runtime_src);
19773 if (block.wantSafety()) {19775 if (block.wantSafety()) {
19774 const len_inst = if (maybe_slice_val) |slice_val|19776 const len_inst = if (maybe_slice_val) |slice_val|
...@@ -19822,6 +19824,8 @@ fn elemPtrSlice(...@@ -19822,6 +19824,8 @@ fn elemPtrSlice(
19822 }19824 }
19823 }19825 }
1982419826
19827 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src);
19828
19825 const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;19829 const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src;
19826 try sema.requireRuntimeBlock(block, runtime_src);19830 try sema.requireRuntimeBlock(block, runtime_src);
19827 if (block.wantSafety()) {19831 if (block.wantSafety()) {
...@@ -22426,7 +22430,7 @@ fn analyzeLoad(...@@ -22426,7 +22430,7 @@ fn analyzeLoad(
22426 }22430 }
2242722431
22428 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {22432 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
22429 if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| {22433 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
22430 return sema.addConstant(elem_ty, elem_val);22434 return sema.addConstant(elem_ty, elem_val);
22431 }22435 }
22432 if (block.is_typeof) {22436 if (block.is_typeof) {
test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig created+16
...@@ -0,0 +1,16 @@
1const Foo = struct {
2 name: []const u8,
3 T: type,
4};
5export fn entry() void {
6 const xx: [2]Foo = .{ .{ .name = "", .T = u8 }, .{ .name = "", .T = u8 } };
7 for (xx) |f| { _ = f;}
8}
9
10// error
11// backend=stage2
12// target=native
13//
14// :7:10: error: values of type '[2]tmp.Foo' must be comptime known, but index value is runtime known
15// :3:8: note: struct requires comptime because of this field
16// :3:8: note: types are not available at runtime
test/cases/compile_errors/range_operator_in_switch_used_on_error_set.zig created+20
...@@ -0,0 +1,20 @@
1export fn entry() void {
2 foo(452) catch |err| switch (err) {
3 error.Foo ... error.Bar => {},
4 else => {},
5 };
6}
7fn foo(x: i32) !void {
8 switch (x) {
9 0 ... 10 => return error.Foo,
10 11 ... 20 => return error.Bar,
11 else => {},
12 }
13}
14
15// error
16// backend=llvm
17// target=native
18//
19// :2:34: error: ranges not allowed when switching on type '@typeInfo(@typeInfo(@TypeOf(tmp.foo)).Fn.return_type.?).ErrorUnion.error_set'
20// :3:19: note: range here
test/cases/compile_errors/reading_past_end_of_pointer_casted_array.zig created+13
...@@ -0,0 +1,13 @@
1comptime {
2 const array: [4]u8 = "aoeu".*;
3 const sub_array = array[1..];
4 const int_ptr = @ptrCast(*const u24, sub_array);
5 const deref = int_ptr.*;
6 _ = deref;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :5:26: error: dereference of '*const u24' exceeds bounds of containing decl of type '[4]u8'
test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig created+20
...@@ -0,0 +1,20 @@
1const Struct = struct {
2 a: u32,
3};
4fn getIndex() usize {
5 return 2;
6}
7export fn entry() void {
8 const index = getIndex();
9 const field = @typeInfo(Struct).Struct.fields[index];
10 _ = field;
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :9:51: error: values of type '[]const builtin.Type.StructField' must be comptime known, but index value is runtime known
18// :287:21: note: struct requires comptime because of this field
19// :287:21: note: types are not available at runtime
20// :290:20: note: struct requires comptime because of this field
test/cases/compile_errors/stage1/obj/non-inline_for_loop_on_a_type_that_requires_comptime.zig deleted-14
...@@ -1,14 +0,0 @@
1const Foo = struct {
2 name: []const u8,
3 T: type,
4};
5export fn entry() void {
6 const xx: [2]Foo = undefined;
7 for (xx) |f| { _ = f;}
8}
9
10// error
11// backend=stage1
12// target=native
13//
14// tmp.zig:7:5: error: values of type 'Foo' must be comptime known, but index value is runtime known
test/cases/compile_errors/stage1/obj/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig deleted-13
...@@ -1,13 +0,0 @@
1export fn entry() bool {
2 var x: u0 = 0;
3 const p = @ptrCast(?*u0, &x);
4 return p == null;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation
12// tmp.zig:3:31: note: '*u0' has no in-memory bits
13// tmp.zig:3:24: note: '?*u0' has in-memory bits
test/cases/compile_errors/stage1/obj/ptrToInt_on_void.zig deleted-9
...@@ -1,9 +0,0 @@
1export fn entry() bool {
2 return @ptrToInt(&{}) == @ptrToInt(&{});
3}
4
5// error
6// backend=stage1
7// target=native
8//
9// tmp.zig:2:23: error: pointer to size 0 type has no address
test/cases/compile_errors/stage1/obj/range_operator_in_switch_used_on_error_set.zig deleted-19
...@@ -1,19 +0,0 @@
1export fn entry() void {
2 try foo(452) catch |err| switch (err) {
3 error.A ... error.B => {},
4 else => {},
5 };
6}
7fn foo(x: i32) !void {
8 switch (x) {
9 0 ... 10 => return error.Foo,
10 11 ... 20 => return error.Bar,
11 else => {},
12 }
13}
14
15// error
16// backend=stage1
17// target=native
18//
19// tmp.zig:3:17: error: operator not allowed for errors
test/cases/compile_errors/stage1/obj/reading_past_end_of_pointer_casted_array.zig deleted-13
...@@ -1,13 +0,0 @@
1comptime {
2 const array: [4]u8 = "aoeu".*;
3 const sub_array = array[1..];
4 const int_ptr = @ptrCast(*const u24, sub_array);
5 const deref = int_ptr.*;
6 _ = deref;
7}
8
9// error
10// backend=stage1
11// target=native
12//
13// tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes
test/cases/compile_errors/stage1/obj/recursive_inferred_error_set.zig deleted-12
...@@ -1,12 +0,0 @@
1export fn entry() void {
2 foo() catch unreachable;
3}
4fn foo() !void {
5 try foo();
6}
7
8// error
9// backend=stage1
10// target=native
11//
12// tmp.zig:5:5: error: cannot resolve inferred error set '@typeInfo(@typeInfo(@TypeOf(foo)).Fn.return_type.?).ErrorUnion.error_set': function 'foo' not fully analyzed yet
test/cases/compile_errors/stage1/obj/runtime_index_into_comptime_type_slice.zig deleted-17
...@@ -1,17 +0,0 @@
1const Struct = struct {
2 a: u32,
3};
4fn getIndex() usize {
5 return 2;
6}
7export fn entry() void {
8 const index = getIndex();
9 const field = @typeInfo(Struct).Struct.fields[index];
10 _ = field;
11}
12
13// error
14// backend=stage1
15// target=native
16//
17// tmp.zig:9:51: error: values of type 'std.builtin.Type.StructField' must be comptime known, but index value is runtime known
test/cases/compile_errors/stage1/obj/slicing_of_global_undefined_pointer.zig deleted-10
...@@ -1,10 +0,0 @@
1var buf: *[1]u8 = undefined;
2export fn entry() void {
3 _ = buf[0..1];
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:3:12: error: non-zero length slice of undefined pointer
test/cases/compile_errors/stage1/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig created+13
...@@ -0,0 +1,13 @@
1export fn entry() bool {
2 var x: u0 = 0;
3 const p = @ptrCast(?*u0, &x);
4 return p == null;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:15: error: '*u0' and '?*u0' do not have the same in-memory representation
12// tmp.zig:3:31: note: '*u0' has no in-memory bits
13// tmp.zig:3:24: note: '?*u0' has in-memory bits
test/cases/compile_errors/stage1/ptrToInt_on_void.zig created+9
...@@ -0,0 +1,9 @@
1export fn entry() bool {
2 return @ptrToInt(&{}) == @ptrToInt(&{});
3}
4
5// error
6// backend=stage1
7// target=native
8//
9// tmp.zig:2:23: error: pointer to size 0 type has no address
test/cases/compile_errors/stage1/recursive_inferred_error_set.zig created+12
...@@ -0,0 +1,12 @@
1export fn entry() void {
2 foo() catch unreachable;
3}
4fn foo() !void {
5 try foo();
6}
7
8// error
9// backend=stage1
10// target=native
11//
12// tmp.zig:5:5: error: cannot resolve inferred error set '@typeInfo(@typeInfo(@TypeOf(foo)).Fn.return_type.?).ErrorUnion.error_set': function 'foo' not fully analyzed yet
test/cases/compile_errors/stage1/slicing_of_global_undefined_pointer.zig created+10
...@@ -0,0 +1,10 @@
1var buf: *[1]u8 = undefined;
2export fn entry() void {
3 _ = buf[0..1];
4}
5
6// error
7// backend=stage1
8// target=native
9//
10// tmp.zig:3:12: error: non-zero length slice of undefined pointer