authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-30 22:57:20+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-01 10:22:25+03:00
loga6bf8c2593ae6e60d4c4804d4e9fd87fe29885ed
tree57b34649c7efdf725967eb06ccb1af26ba077749
parente6ebf56dd6cf2e2c23af952d2e9e327703c9cd02

Sema: add more validation to zirFieldParentPtr


19 files changed, 179 insertions(+), 153 deletions(-)

src/Sema.zig+38-14
...@@ -8378,19 +8378,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8378,19 +8378,15 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8378 block,8378 block,
8379 src,8379 src,
8380 msg,8380 msg,
8381 "unhandled error value: error.{s}",8381 "unhandled error value: 'error.{s}'",
8382 .{error_name},8382 .{error_name},
8383 );8383 );
8384 }8384 }
8385 }8385 }
83868386
8387 if (maybe_msg) |msg| {8387 if (maybe_msg) |msg| {
8388 try sema.mod.errNoteNonLazy(8388 maybe_msg = null;
8389 operand_ty.declSrcLoc(sema.mod),8389 try sema.addDeclaredHereNote(msg, operand_ty);
8390 msg,
8391 "error set '{}' declared here",
8392 .{operand_ty.fmt(sema.mod)},
8393 );
8394 return sema.failWithOwnedErrorMsg(block, msg);8390 return sema.failWithOwnedErrorMsg(block, msg);
8395 }8391 }
83968392
...@@ -17143,9 +17139,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -17143,9 +17139,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
17143 const field_index = struct_obj.fields.getIndex(field_name) orelse17139 const field_index = struct_obj.fields.getIndex(field_name) orelse
17144 return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);17140 return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);
1714517141
17146 if (field_ptr_ty.zigTypeTag() != .Pointer) {17142 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
17147 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{field_ptr_ty.fmt(sema.mod)});
17148 }
17149 const field = struct_obj.fields.values()[field_index];17143 const field = struct_obj.fields.values()[field_index];
17150 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;17144 const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
1715117145
...@@ -17168,8 +17162,29 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -17168,8 +17162,29 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
17168 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);17162 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
1716917163
17170 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {17164 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
17171 const payload = field_ptr_val.castTag(.field_ptr).?.data;17165 const payload = field_ptr_val.castTag(.field_ptr) orelse {
17172 return sema.addConstant(result_ptr, payload.container_ptr);17166 return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
17167 };
17168 if (payload.data.field_index != field_index) {
17169 const msg = msg: {
17170 const msg = try sema.errMsg(
17171 block,
17172 src,
17173 "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'",
17174 .{
17175 field_name,
17176 field_index,
17177 payload.data.field_index,
17178 struct_ty.fmt(sema.mod),
17179 },
17180 );
17181 errdefer msg.destroy(sema.gpa);
17182 try sema.addDeclaredHereNote(msg, struct_ty);
17183 break :msg msg;
17184 };
17185 return sema.failWithOwnedErrorMsg(block, msg);
17186 }
17187 return sema.addConstant(result_ptr, payload.data.container_ptr);
17173 }17188 }
1717417189
17175 try sema.requireRuntimeBlock(block, src);17190 try sema.requireRuntimeBlock(block, src);
...@@ -18515,7 +18530,16 @@ fn fieldVal(...@@ -18515,7 +18530,16 @@ fn fieldVal(
18515 kw_name, child_type.fmt(sema.mod), field_name,18530 kw_name, child_type.fmt(sema.mod), field_name,
18516 });18531 });
18517 },18532 },
18518 else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}),18533 else => {
18534 const msg = msg: {
18535 const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)});
18536 errdefer msg.destroy(sema.gpa);
18537 if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
18538 if (child_type.zigTypeTag() == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
18539 break :msg msg;
18540 };
18541 return sema.failWithOwnedErrorMsg(block, msg);
18542 },
18519 }18543 }
18520 },18544 },
18521 .Struct => if (is_pointer_to) {18545 .Struct => if (is_pointer_to) {
...@@ -18739,7 +18763,7 @@ fn fieldPtr(...@@ -18739,7 +18763,7 @@ fn fieldPtr(
18739 },18763 },
18740 else => {},18764 else => {},
18741 }18765 }
18742 return sema.fail(block, src, "type '{}' does not support field access (fieldPtr, {}.{s})", .{ object_ty.fmt(sema.mod), object_ptr_ty.fmt(sema.mod), field_name });18766 return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
18743}18767}
1874418768
18745fn fieldCallBind(18769fn fieldCallBind(
test/cases/compile_errors/division_by_zero.zig created+17
...@@ -0,0 +1,17 @@
1const lit_int_x = 1 / 0;
2const lit_float_x = 1.0 / 0.0;
3const int_x = @as(u32, 1) / @as(u32, 0);
4const float_x = @as(f32, 1.0) / @as(f32, 0.0);
5
6export fn entry1() usize { return @sizeOf(@TypeOf(lit_int_x)); }
7export fn entry2() usize { return @sizeOf(@TypeOf(lit_float_x)); }
8export fn entry3() usize { return @sizeOf(@TypeOf(int_x)); }
9export fn entry4() usize { return @sizeOf(@TypeOf(float_x)); } // no error on purpose
10
11// error
12// backend=stage2
13// target=native
14//
15// :1:23: error: division by zero here causes undefined behavior
16// :2:27: error: division by zero here causes undefined behavior
17// :3:29: error: division by zero here causes undefined behavior
test/cases/compile_errors/error_not_handled_in_switch.zig created+21
...@@ -0,0 +1,21 @@
1export fn entry() void {
2 foo(452) catch |err| switch (err) {
3 error.Foo => {},
4 };
5}
6fn foo(x: i32) !void {
7 switch (x) {
8 0 ... 10 => return error.Foo,
9 11 ... 20 => return error.Bar,
10 21 ... 30 => return error.Baz,
11 else => {},
12 }
13}
14
15// error
16// backend=llvm
17// target=native
18//
19// :2:26: error: switch must handle all possibilities
20// :2:26: note: unhandled error value: 'error.Bar'
21// :2:26: note: unhandled error value: 'error.Baz'
test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig created+17
...@@ -0,0 +1,17 @@
1const Foo = struct {
2 a: i32,
3 b: i32,
4};
5const foo = Foo { .a = 1, .b = 2, };
6
7comptime {
8 const field_ptr = @intToPtr(*i32, 0x1234);
9 const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
10 _ = another_foo_ptr;
11}
12
13// error
14// backend=stage2
15// target=native
16//
17// :9:55: error: pointer value not based on parent struct
test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig created+17
...@@ -0,0 +1,17 @@
1const Foo = struct {
2 a: i32,
3 b: i32,
4};
5const foo = Foo { .a = 1, .b = 2, };
6
7comptime {
8 const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
9 _ = another_foo_ptr;
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :8:29: error: field 'b' has index '1' but pointer value is index '0' of struct 'tmp.Foo'
17// :1:13: note: struct declared here
test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig created+12
...@@ -0,0 +1,12 @@
1const Foo = extern struct {
2 a: i32,
3};
4export fn foo(a: i32) *Foo {
5 return @fieldParentPtr(Foo, "a", a);
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :5:38: error: expected pointer type, found 'i32'
test/cases/compile_errors/field_access_of_opaque_type.zig created+16
...@@ -0,0 +1,16 @@
1const MyType = opaque {};
2
3export fn entry() bool {
4 var x: i32 = 1;
5 return bar(@ptrCast(*MyType, &x));
6}
7
8fn bar(x: *MyType) bool {
9 return x.blah;
10}
11
12// error
13// backend=stage2
14// target=native
15//
16// :9:13: error: type '*tmp.MyType' does not support field access
test/cases/compile_errors/field_access_of_slices.zig created+12
...@@ -0,0 +1,12 @@
1export fn entry() void {
2 var slice: []i32 = undefined;
3 const info = @TypeOf(slice).unknown;
4 _ = info;
5}
6
7// error
8// backend=stage2
9// target=native
10//
11// :3:32: error: type '[]i32' has no members
12// :3:32: note: slice values have 'len' and 'ptr' members
test/cases/compile_errors/field_access_of_unknown_length_pointer.zig created+13
...@@ -0,0 +1,13 @@
1const Foo = extern struct {
2 a: i32,
3};
4
5export fn entry(foo: [*]Foo) void {
6 foo.a += 1;
7}
8
9// error
10// backend=stage2
11// target=native
12//
13// :6:8: error: type '[*]tmp.Foo' does not support field access
test/cases/compile_errors/stage1/error_equality_but_sets_have_no_common_members.zig created+16
...@@ -0,0 +1,16 @@
1const Set1 = error{A, C};
2const Set2 = error{B, D};
3export fn entry() void {
4 foo(Set1.A);
5}
6fn foo(x: Set1) void {
7 if (x == Set2.B) {
8
9 }
10}
11
12// error
13// backend=stage1
14// target=native
15//
16// tmp.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors
test/cases/compile_errors/stage1/obj/division_by_zero.zig deleted-18
...@@ -1,18 +0,0 @@
1const lit_int_x = 1 / 0;
2const lit_float_x = 1.0 / 0.0;
3const int_x = @as(u32, 1) / @as(u32, 0);
4const float_x = @as(f32, 1.0) / @as(f32, 0.0);
5
6export fn entry1() usize { return @sizeOf(@TypeOf(lit_int_x)); }
7export fn entry2() usize { return @sizeOf(@TypeOf(lit_float_x)); }
8export fn entry3() usize { return @sizeOf(@TypeOf(int_x)); }
9export fn entry4() usize { return @sizeOf(@TypeOf(float_x)); }
10
11// error
12// backend=stage1
13// target=native
14//
15// tmp.zig:1:21: error: division by zero
16// tmp.zig:2:25: error: division by zero
17// tmp.zig:3:27: error: division by zero
18// tmp.zig:4:31: error: division by zero
test/cases/compile_errors/stage1/obj/error_equality_but_sets_have_no_common_members.zig deleted-16
...@@ -1,16 +0,0 @@
1const Set1 = error{A, C};
2const Set2 = error{B, D};
3export fn entry() void {
4 foo(Set1.A);
5}
6fn foo(x: Set1) void {
7 if (x == Set2.B) {
8
9 }
10}
11
12// error
13// backend=stage1
14// target=native
15//
16// tmp.zig:7:11: error: error sets 'Set1' and 'Set2' have no common errors
test/cases/compile_errors/stage1/obj/error_not_handled_in_switch.zig deleted-20
...@@ -1,20 +0,0 @@
1export fn entry() void {
2 foo(452) catch |err| switch (err) {
3 error.Foo => {},
4 };
5}
6fn foo(x: i32) !void {
7 switch (x) {
8 0 ... 10 => return error.Foo,
9 11 ... 20 => return error.Bar,
10 21 ... 30 => return error.Baz,
11 else => {},
12 }
13}
14
15// error
16// backend=stage1
17// target=native
18//
19// tmp.zig:2:26: error: error.Baz not handled in switch
20// tmp.zig:2:26: error: error.Bar not handled in switch
test/cases/compile_errors/stage1/obj/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig deleted-17
...@@ -1,17 +0,0 @@
1const Foo = struct {
2 a: i32,
3 b: i32,
4};
5const foo = Foo { .a = 1, .b = 2, };
6
7comptime {
8 const field_ptr = @intToPtr(*i32, 0x1234);
9 const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
10 _ = another_foo_ptr;
11}
12
13// error
14// backend=stage1
15// target=native
16//
17// tmp.zig:9:55: error: pointer value not based on parent struct
test/cases/compile_errors/stage1/obj/fieldParentPtr-comptime_wrong_field_index.zig deleted-16
...@@ -1,16 +0,0 @@
1const Foo = struct {
2 a: i32,
3 b: i32,
4};
5const foo = Foo { .a = 1, .b = 2, };
6
7comptime {
8 const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
9 _ = another_foo_ptr;
10}
11
12// error
13// backend=stage1
14// target=native
15//
16// tmp.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'
test/cases/compile_errors/stage1/obj/fieldParentPtr-field_pointer_is_not_pointer.zig deleted-12
...@@ -1,12 +0,0 @@
1const Foo = extern struct {
2 a: i32,
3};
4export fn foo(a: i32) *Foo {
5 return @fieldParentPtr(Foo, "a", a);
6}
7
8// error
9// backend=stage1
10// target=native
11//
12// tmp.zig:5:38: error: expected pointer, found 'i32'
test/cases/compile_errors/stage1/obj/field_access_of_opaque_type.zig deleted-16
...@@ -1,16 +0,0 @@
1const MyType = opaque {};
2
3export fn entry() bool {
4 var x: i32 = 1;
5 return bar(@ptrCast(*MyType, &x));
6}
7
8fn bar(x: *MyType) bool {
9 return x.blah;
10}
11
12// error
13// backend=stage1
14// target=native
15//
16// tmp.zig:9:13: error: no member named 'blah' in opaque type 'MyType'
test/cases/compile_errors/stage1/obj/field_access_of_slices.zig deleted-11
...@@ -1,11 +0,0 @@
1export fn entry() void {
2 var slice: []i32 = undefined;
3 const info = @TypeOf(slice).unknown;
4 _ = info;
5}
6
7// error
8// backend=stage1
9// target=native
10//
11// tmp.zig:3:32: error: type 'type' does not support field access
test/cases/compile_errors/stage1/obj/field_access_of_unknown_length_pointer.zig deleted-13
...@@ -1,13 +0,0 @@
1const Foo = extern struct {
2 a: i32,
3};
4
5export fn entry(foo: [*]Foo) void {
6 foo.a += 1;
7}
8
9// error
10// backend=stage1
11// target=native
12//
13// tmp.zig:6:8: error: type '[*]Foo' does not support field access