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
83788378 block,
83798379 src,
83808380 msg,
8381 "unhandled error value: error.{s}",
8381 "unhandled error value: 'error.{s}'",
83828382 .{error_name},
83838383 );
83848384 }
83858385 }
83868386
83878387 if (maybe_msg) |msg| {
8388 try sema.mod.errNoteNonLazy(
8389 operand_ty.declSrcLoc(sema.mod),
8390 msg,
8391 "error set '{}' declared here",
8392 .{operand_ty.fmt(sema.mod)},
8393 );
8388 maybe_msg = null;
8389 try sema.addDeclaredHereNote(msg, operand_ty);
83948390 return sema.failWithOwnedErrorMsg(block, msg);
83958391 }
83968392
......@@ -17143,9 +17139,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
1714317139 const field_index = struct_obj.fields.getIndex(field_name) orelse
1714417140 return sema.failWithBadStructFieldAccess(block, struct_obj, name_src, field_name);
1714517141
17146 if (field_ptr_ty.zigTypeTag() != .Pointer) {
17147 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{field_ptr_ty.fmt(sema.mod)});
17148 }
17142 try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
1714917143 const field = struct_obj.fields.values()[field_index];
1715017144 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
1716817162 const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
1716917163
1717017164 if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
17171 const payload = field_ptr_val.castTag(.field_ptr).?.data;
17172 return sema.addConstant(result_ptr, payload.container_ptr);
17165 const payload = field_ptr_val.castTag(.field_ptr) orelse {
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);
1717317188 }
1717417189
1717517190 try sema.requireRuntimeBlock(block, src);
......@@ -18515,7 +18530,16 @@ fn fieldVal(
1851518530 kw_name, child_type.fmt(sema.mod), field_name,
1851618531 });
1851718532 },
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 },
1851918543 }
1852018544 },
1852118545 .Struct => if (is_pointer_to) {
......@@ -18739,7 +18763,7 @@ fn fieldPtr(
1873918763 },
1874018764 else => {},
1874118765 }
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)});
1874318767}
1874418768
1874518769fn 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