Sema: more runtime indexing comptime value checks

This commit is contained in:
Veikka Tuominen
2022-07-01 21:08:31 +03:00
parent 1569b9c165
commit c07c2d68c7
12 changed files with 98 additions and 88 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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