From c07c2d68c7c8276f8d215cfd21f0dcd92db9cf79 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Fri, 1 Jul 2022 21:08:31 +0300 Subject: [PATCH] Sema: more runtime indexing comptime value checks --- src/Sema.zig | 76 ++++++++++--------- ..._loop_on_a_type_that_requires_comptime.zig | 16 ++++ ...e_operator_in_switch_used_on_error_set.zig | 20 +++++ ...ading_past_end_of_pointer_casted_array.zig | 4 +- ...runtime_index_into_comptime_type_slice.zig | 20 +++++ ..._loop_on_a_type_that_requires_comptime.zig | 14 ---- ...e_operator_in_switch_used_on_error_set.zig | 19 ----- ...runtime_index_into_comptime_type_slice.zig | 17 ----- ...Cast_a_0_bit_type_to_a_non-_0_bit_type.zig | 0 .../stage1/{obj => }/ptrToInt_on_void.zig | 0 .../recursive_inferred_error_set.zig | 0 .../slicing_of_global_undefined_pointer.zig | 0 12 files changed, 98 insertions(+), 88 deletions(-) create mode 100644 test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig create mode 100644 test/cases/compile_errors/range_operator_in_switch_used_on_error_set.zig rename test/cases/compile_errors/{stage1/obj => }/reading_past_end_of_pointer_casted_array.zig (64%) create mode 100644 test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig delete mode 100644 test/cases/compile_errors/stage1/obj/non-inline_for_loop_on_a_type_that_requires_comptime.zig delete mode 100644 test/cases/compile_errors/stage1/obj/range_operator_in_switch_used_on_error_set.zig delete mode 100644 test/cases/compile_errors/stage1/obj/runtime_index_into_comptime_type_slice.zig rename test/cases/compile_errors/stage1/{obj => }/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig (100%) rename test/cases/compile_errors/stage1/{obj => }/ptrToInt_on_void.zig (100%) rename test/cases/compile_errors/stage1/{obj => }/recursive_inferred_error_set.zig (100%) rename test/cases/compile_errors/stage1/{obj => }/slicing_of_global_undefined_pointer.zig (100%) diff --git a/src/Sema.zig b/src/Sema.zig index 8c43109a36..237cbf588e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -19494,6 +19494,34 @@ fn elemVal( } } +fn validateRuntimeElemAccess( + sema: *Sema, + block: *Block, + elem_index_src: LazySrcLoc, + elem_ty: Type, + parent_ty: Type, + parent_src: LazySrcLoc, +) CompileError!void { + const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false); + if (!valid_rt) { + const msg = msg: { + const msg = try sema.errMsg( + block, + elem_index_src, + "values of type '{}' must be comptime known, but index value is runtime known", + .{parent_ty.fmt(sema.mod)}, + ); + errdefer msg.destroy(sema.gpa); + + const src_decl = sema.mod.declPtr(block.src_decl); + try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, parent_src.toSrcLoc(src_decl), parent_ty); + + break :msg msg; + }; + return sema.failWithOwnedErrorMsg(block, msg); + } +} + fn tupleFieldPtr( sema: *Sema, block: *Block, @@ -19534,6 +19562,8 @@ fn tupleFieldPtr( ); } + try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_ptr_src); + try sema.requireRuntimeBlock(block, tuple_ptr_src); return block.addStructFieldPtr(tuple_ptr, field_index, ptr_field_ty); } @@ -19572,6 +19602,8 @@ fn tupleField( return sema.addConstant(field_ty, field_values[field_index]); } + try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src); + try sema.requireRuntimeBlock(block, tuple_src); return block.addStructFieldVal(tuple, field_index, field_ty); } @@ -19622,24 +19654,7 @@ fn elemValArray( } } - const valid_rt = try sema.validateRunTimeType(block, elem_index_src, elem_ty, false); - if (!valid_rt) { - const msg = msg: { - const msg = try sema.errMsg( - block, - elem_index_src, - "values of type '{}' must be comptime known, but index value is runtime known", - .{array_ty.fmt(sema.mod)}, - ); - errdefer msg.destroy(sema.gpa); - - const src_decl = sema.mod.declPtr(block.src_decl); - try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, array_src.toSrcLoc(src_decl), array_ty); - - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); - } + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src); const runtime_src = if (maybe_undef_array_val != null) elem_index_src else array_src; try sema.requireRuntimeBlock(block, runtime_src); @@ -19697,23 +19712,8 @@ fn elemPtrArray( } } - const valid_rt = try sema.validateRunTimeType(block, elem_index_src, array_ty.elemType2(), false); - if (!valid_rt and !init) { - const msg = msg: { - const msg = try sema.errMsg( - block, - elem_index_src, - "values of type '{}' must be comptime known, but index value is runtime known", - .{array_ty.fmt(sema.mod)}, - ); - errdefer msg.destroy(sema.gpa); - - const src_decl = sema.mod.declPtr(block.src_decl); - try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, array_ptr_src.toSrcLoc(src_decl), array_ty); - - break :msg msg; - }; - return sema.failWithOwnedErrorMsg(block, msg); + if (!init) { + try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(), array_ty, array_ptr_src); } const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src; @@ -19769,6 +19769,8 @@ fn elemValSlice( } } + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src); + try sema.requireRuntimeBlock(block, runtime_src); if (block.wantSafety()) { const len_inst = if (maybe_slice_val) |slice_val| @@ -19822,6 +19824,8 @@ fn elemPtrSlice( } } + try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ptr_ty, slice_ty, slice_src); + const runtime_src = if (maybe_undef_slice_val != null) elem_index_src else slice_src; try sema.requireRuntimeBlock(block, runtime_src); if (block.wantSafety()) { @@ -22426,7 +22430,7 @@ fn analyzeLoad( } if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| { - if (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) |elem_val| { + if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| { return sema.addConstant(elem_ty, elem_val); } if (block.is_typeof) { diff --git a/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig b/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig new file mode 100644 index 0000000000..ec598e8f05 --- /dev/null +++ b/test/cases/compile_errors/non-inline_for_loop_on_a_type_that_requires_comptime.zig @@ -0,0 +1,16 @@ +const Foo = struct { + name: []const u8, + T: type, +}; +export fn entry() void { + const xx: [2]Foo = .{ .{ .name = "", .T = u8 }, .{ .name = "", .T = u8 } }; + for (xx) |f| { _ = f;} +} + +// error +// backend=stage2 +// target=native +// +// :7:10: error: values of type '[2]tmp.Foo' must be comptime known, but index value is runtime known +// :3:8: note: struct requires comptime because of this field +// :3:8: note: types are not available at runtime diff --git a/test/cases/compile_errors/range_operator_in_switch_used_on_error_set.zig b/test/cases/compile_errors/range_operator_in_switch_used_on_error_set.zig new file mode 100644 index 0000000000..859197929c --- /dev/null +++ b/test/cases/compile_errors/range_operator_in_switch_used_on_error_set.zig @@ -0,0 +1,20 @@ +export fn entry() void { + foo(452) catch |err| switch (err) { + error.Foo ... error.Bar => {}, + else => {}, + }; +} +fn foo(x: i32) !void { + switch (x) { + 0 ... 10 => return error.Foo, + 11 ... 20 => return error.Bar, + else => {}, + } +} + +// error +// backend=llvm +// target=native +// +// :2:34: error: ranges not allowed when switching on type '@typeInfo(@typeInfo(@TypeOf(tmp.foo)).Fn.return_type.?).ErrorUnion.error_set' +// :3:19: note: range here diff --git a/test/cases/compile_errors/stage1/obj/reading_past_end_of_pointer_casted_array.zig b/test/cases/compile_errors/reading_past_end_of_pointer_casted_array.zig similarity index 64% rename from test/cases/compile_errors/stage1/obj/reading_past_end_of_pointer_casted_array.zig rename to test/cases/compile_errors/reading_past_end_of_pointer_casted_array.zig index cece3345c3..906b292753 100644 --- a/test/cases/compile_errors/stage1/obj/reading_past_end_of_pointer_casted_array.zig +++ b/test/cases/compile_errors/reading_past_end_of_pointer_casted_array.zig @@ -7,7 +7,7 @@ comptime { } // error -// backend=stage1 +// backend=stage2 // target=native // -// tmp.zig:5:26: error: attempt to read 4 bytes from [4]u8 at index 1 which is 3 bytes +// :5:26: error: dereference of '*const u24' exceeds bounds of containing decl of type '[4]u8' diff --git a/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig b/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig new file mode 100644 index 0000000000..2dac2d1dc8 --- /dev/null +++ b/test/cases/compile_errors/runtime_index_into_comptime_type_slice.zig @@ -0,0 +1,20 @@ +const Struct = struct { + a: u32, +}; +fn getIndex() usize { + return 2; +} +export fn entry() void { + const index = getIndex(); + const field = @typeInfo(Struct).Struct.fields[index]; + _ = field; +} + +// error +// backend=stage2 +// target=native +// +// :9:51: error: values of type '[]const builtin.Type.StructField' must be comptime known, but index value is runtime known +// :287:21: note: struct requires comptime because of this field +// :287:21: note: types are not available at runtime +// :290:20: note: struct requires comptime because of this field diff --git a/test/cases/compile_errors/stage1/obj/non-inline_for_loop_on_a_type_that_requires_comptime.zig b/test/cases/compile_errors/stage1/obj/non-inline_for_loop_on_a_type_that_requires_comptime.zig deleted file mode 100644 index d2b4e28ea6..0000000000 --- a/test/cases/compile_errors/stage1/obj/non-inline_for_loop_on_a_type_that_requires_comptime.zig +++ /dev/null @@ -1,14 +0,0 @@ -const Foo = struct { - name: []const u8, - T: type, -}; -export fn entry() void { - const xx: [2]Foo = undefined; - for (xx) |f| { _ = f;} -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:7:5: error: values of type 'Foo' must be comptime known, but index value is runtime known diff --git a/test/cases/compile_errors/stage1/obj/range_operator_in_switch_used_on_error_set.zig b/test/cases/compile_errors/stage1/obj/range_operator_in_switch_used_on_error_set.zig deleted file mode 100644 index 8108f42979..0000000000 --- a/test/cases/compile_errors/stage1/obj/range_operator_in_switch_used_on_error_set.zig +++ /dev/null @@ -1,19 +0,0 @@ -export fn entry() void { - try foo(452) catch |err| switch (err) { - error.A ... error.B => {}, - else => {}, - }; -} -fn foo(x: i32) !void { - switch (x) { - 0 ... 10 => return error.Foo, - 11 ... 20 => return error.Bar, - else => {}, - } -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:17: error: operator not allowed for errors diff --git a/test/cases/compile_errors/stage1/obj/runtime_index_into_comptime_type_slice.zig b/test/cases/compile_errors/stage1/obj/runtime_index_into_comptime_type_slice.zig deleted file mode 100644 index 379767c7f3..0000000000 --- a/test/cases/compile_errors/stage1/obj/runtime_index_into_comptime_type_slice.zig +++ /dev/null @@ -1,17 +0,0 @@ -const Struct = struct { - a: u32, -}; -fn getIndex() usize { - return 2; -} -export fn entry() void { - const index = getIndex(); - const field = @typeInfo(Struct).Struct.fields[index]; - _ = field; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:9:51: error: values of type 'std.builtin.Type.StructField' must be comptime known, but index value is runtime known diff --git a/test/cases/compile_errors/stage1/obj/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig b/test/cases/compile_errors/stage1/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig similarity index 100% rename from test/cases/compile_errors/stage1/obj/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig rename to test/cases/compile_errors/stage1/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig diff --git a/test/cases/compile_errors/stage1/obj/ptrToInt_on_void.zig b/test/cases/compile_errors/stage1/ptrToInt_on_void.zig similarity index 100% rename from test/cases/compile_errors/stage1/obj/ptrToInt_on_void.zig rename to test/cases/compile_errors/stage1/ptrToInt_on_void.zig diff --git a/test/cases/compile_errors/stage1/obj/recursive_inferred_error_set.zig b/test/cases/compile_errors/stage1/recursive_inferred_error_set.zig similarity index 100% rename from test/cases/compile_errors/stage1/obj/recursive_inferred_error_set.zig rename to test/cases/compile_errors/stage1/recursive_inferred_error_set.zig diff --git a/test/cases/compile_errors/stage1/obj/slicing_of_global_undefined_pointer.zig b/test/cases/compile_errors/stage1/slicing_of_global_undefined_pointer.zig similarity index 100% rename from test/cases/compile_errors/stage1/obj/slicing_of_global_undefined_pointer.zig rename to test/cases/compile_errors/stage1/slicing_of_global_undefined_pointer.zig