Commit c07c2d68c7

Veikka Tuominen <git@vexu.eu>
2022-07-01 20:08:31
Sema: more runtime indexing comptime value checks
1 parent 1569b9c
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) {
test/cases/compile_errors/stage1/obj/non-inline_for_loop_on_a_type_that_requires_comptime.zig
@@ -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
test/cases/compile_errors/stage1/obj/range_operator_in_switch_used_on_error_set.zig
@@ -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
test/cases/compile_errors/stage1/obj/runtime_index_into_comptime_type_slice.zig
@@ -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
test/cases/compile_errors/stage1/obj/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig → test/cases/compile_errors/stage1/ptrCast_a_0_bit_type_to_a_non-_0_bit_type.zig
File renamed without changes
test/cases/compile_errors/stage1/obj/ptrToInt_on_void.zig → test/cases/compile_errors/stage1/ptrToInt_on_void.zig
File renamed without changes
test/cases/compile_errors/stage1/obj/recursive_inferred_error_set.zig → test/cases/compile_errors/stage1/recursive_inferred_error_set.zig
File renamed without changes
test/cases/compile_errors/stage1/obj/slicing_of_global_undefined_pointer.zig → test/cases/compile_errors/stage1/slicing_of_global_undefined_pointer.zig
File renamed without changes
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
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
test/cases/compile_errors/stage1/obj/reading_past_end_of_pointer_casted_array.zig → 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'
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