diff --git a/lib/c.zig b/lib/c.zig index 30c6e0cd76e6b30c553d37a90cb8eb26451b8722..9df1b3fb01044bab1fcbf417ed406f75f47dd3b4 100644 --- a/lib/c.zig +++ b/lib/c.zig @@ -82,7 +82,7 @@ fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 { var d = dest.?; var n = len; while (true) { - d.* = c; + d[0] = c; n -= 1; if (n == 0) break; d += 1; diff --git a/lib/std/os.zig b/lib/std/os.zig index 578a8ddcbc8340d3ae13dbb130bae1fcc3e7f490..02ed710dd310de0fc91e5cec224c748dba646bf1 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1868,7 +1868,7 @@ pub fn getenv(key: []const u8) ?[]const u8 { } // Search the entire `environ` because we don't have a null terminated pointer. var ptr = std.c.environ; - while (ptr.*) |line| : (ptr += 1) { + while (ptr[0]) |line| : (ptr += 1) { var line_i: usize = 0; while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} const this_key = line[0..line_i]; diff --git a/lib/std/process.zig b/lib/std/process.zig index 0b64b5910d8664d3b125b22f99e89d1277b279ba..dffd6b1701a262207edb4baa5298bda29fc6bd2e 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -313,7 +313,7 @@ pub fn getEnvMap(allocator: Allocator) !EnvMap { return result; } else if (builtin.link_libc) { var ptr = std.c.environ; - while (ptr.*) |line| : (ptr += 1) { + while (ptr[0]) |line| : (ptr += 1) { var line_i: usize = 0; while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {} const key = line[0..line_i]; diff --git a/src/AstGen.zig b/src/AstGen.zig index c9abb1859ba9f5f2f6b25501bddd580848a9c6f8..870772831335e158a047f988269feca7c61a3f3e 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -812,6 +812,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr .deref => { const lhs = try expr(gz, scope, .none, node_datas[node].lhs); + _ = try gz.addUnTok(.validate_deref, lhs, main_tokens[node]); switch (rl) { .ref => return lhs, else => { @@ -2500,6 +2501,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner .memset, .validate_array_init_ty, .validate_struct_init_ty, + .validate_deref, => break :b true, } } else switch (maybe_unused_result) { diff --git a/src/Sema.zig b/src/Sema.zig index 30cebe18b339ff593f8965c5500cf4988d41aa0f..0e7188a6c9a5f1d7f41c5be3a035999968effae5 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1080,6 +1080,11 @@ fn analyzeBodyInner( i += 1; continue; }, + .validate_deref => { + try sema.zirValidateDeref(block, inst); + i += 1; + continue; + }, .@"export" => { try sema.zirExport(block, inst); i += 1; @@ -3849,6 +3854,28 @@ fn zirValidateArrayInit( } } +fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { + const inst_data = sema.code.instructions.items(.data)[inst].un_tok; + const src = inst_data.src(); + const operand_src: LazySrcLoc = .{ .token_offset = inst_data.src_tok + 1 }; + const operand = try sema.resolveInst(inst_data.operand); + const operand_ty = sema.typeOf(operand); + + if (operand_ty.zigTypeTag() != .Pointer) { + return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)}); + } else switch (operand_ty.ptrSize()) { + .One, .C => {}, + .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}), + .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}), + } + + if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| { + if (val.isUndef()) { + return sema.fail(block, src, "cannot dereference undefined value", .{}); + } + } +} + fn failWithBadMemberAccess( sema: *Sema, block: *Block, diff --git a/src/Zir.zig b/src/Zir.zig index e6acfe8ed2aac7135fb630650decbac52226a4fe..26bb09860d8f0ad2f5ec1a01137b6cb3eb7626a9 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -729,6 +729,9 @@ pub const Inst = struct { /// Same as `validate_array_init` but additionally communicates that the /// resulting array initialization value is within a comptime scope. validate_array_init_comptime, + /// Check that operand type supports the dereference operand (.*). + /// Uses the `un_tok` field. + validate_deref, /// A struct literal with a specified type, with no fields. /// Uses the `un_node` field. struct_init_empty, @@ -1156,6 +1159,7 @@ pub const Inst = struct { .validate_struct_init_comptime, .validate_array_init, .validate_array_init_comptime, + .validate_deref, .struct_init_empty, .struct_init, .struct_init_ref, @@ -1309,6 +1313,7 @@ pub const Inst = struct { .validate_struct_init_comptime, .validate_array_init, .validate_array_init_comptime, + .validate_deref, .@"export", .export_value, .set_cold, @@ -1709,6 +1714,7 @@ pub const Inst = struct { .validate_struct_init_comptime = .pl_node, .validate_array_init = .pl_node, .validate_array_init_comptime = .pl_node, + .validate_deref = .un_tok, .struct_init_empty = .un_node, .field_type = .pl_node, .field_type_ref = .pl_node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 480a3e2a4fa19f02a2c492983480e684beb42b53..fe8446b34acf7feb5563bed168ba0a298ac16f5d 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -242,6 +242,7 @@ const Writer = struct { .ret_tok, .ensure_err_payload_void, .closure_capture, + .validate_deref, => try self.writeUnTok(stream, inst), .bool_br_and, diff --git a/test/cases/compile_errors/assign_to_invalid_dereference.zig b/test/cases/compile_errors/assign_to_invalid_dereference.zig new file mode 100644 index 0000000000000000000000000000000000000000..cb35004034d7dbc2f9145782758cb157937bea47 --- /dev/null +++ b/test/cases/compile_errors/assign_to_invalid_dereference.zig @@ -0,0 +1,9 @@ +export fn entry() void { + 'a'.* = 1; +} + +// error +// backend=stage2 +// target=native +// +// :2:8: error: cannot dereference non-pointer type 'comptime_int' diff --git a/test/cases/compile_errors/deref_on_undefined_value.zig b/test/cases/compile_errors/deref_on_undefined_value.zig new file mode 100644 index 0000000000000000000000000000000000000000..fa12e2824cad3e1794a6d1bad893d4d8f8198af6 --- /dev/null +++ b/test/cases/compile_errors/deref_on_undefined_value.zig @@ -0,0 +1,10 @@ +comptime { + var a: *u8 = undefined; + _ = a.*; +} + +// error +// backend=stage2 +// target=native +// +// :3:10: error: cannot dereference undefined value diff --git a/test/cases/compile_errors/deref_slice_and_get_len_field.zig b/test/cases/compile_errors/deref_slice_and_get_len_field.zig new file mode 100644 index 0000000000000000000000000000000000000000..1ba03c6d50cf90ad0c647ec3552f24fb0d5bcc5e --- /dev/null +++ b/test/cases/compile_errors/deref_slice_and_get_len_field.zig @@ -0,0 +1,10 @@ +export fn entry() void { + var a: []u8 = undefined; + _ = a.*.len; +} + +// error +// backend=stage2 +// target=native +// +// :3:10: error: index syntax required for slice type '[]u8' diff --git a/test/cases/compile_errors/dereference_an_array.zig b/test/cases/compile_errors/dereference_an_array.zig new file mode 100644 index 0000000000000000000000000000000000000000..f5aabf081c5a6c6d59668ff2d65362244f179d10 --- /dev/null +++ b/test/cases/compile_errors/dereference_an_array.zig @@ -0,0 +1,14 @@ +var s_buffer: [10]u8 = undefined; +pub fn pass(in: []u8) []u8 { + var out = &s_buffer; + out.*.* = in[0]; + return out.*[0..1]; +} + +export fn entry() usize { return @sizeOf(@TypeOf(&pass)); } + +// error +// backend=stage2 +// target=native +// +// :4:10: error: cannot dereference non-pointer type '[10]u8' diff --git a/test/cases/compile_errors/dereference_slice.zig b/test/cases/compile_errors/dereference_slice.zig new file mode 100644 index 0000000000000000000000000000000000000000..7dba3b55d82272bfddc925ca0dbfa586f1952f1e --- /dev/null +++ b/test/cases/compile_errors/dereference_slice.zig @@ -0,0 +1,12 @@ +fn entry(x: []i32) i32 { + return x.*; +} +comptime { + _ = entry; +} + +// error +// backend=stage2 +// target=native +// +// :2:13: error: index syntax required for slice type '[]i32' diff --git a/test/cases/compile_errors/dereference_unknown_length_pointer.zig b/test/cases/compile_errors/dereference_unknown_length_pointer.zig new file mode 100644 index 0000000000000000000000000000000000000000..353f94b8d9cb682a55e3b7d2ac72da2201737928 --- /dev/null +++ b/test/cases/compile_errors/dereference_unknown_length_pointer.zig @@ -0,0 +1,9 @@ +export fn entry(x: [*]i32) i32 { + return x.*; +} + +// error +// backend=stage2 +// target=native +// +// :2:13: error: index syntax required for unknown-length pointer type '[*]i32' diff --git a/test/cases/compile_errors/invalid_deref_on_switch_target.zig b/test/cases/compile_errors/invalid_deref_on_switch_target.zig new file mode 100644 index 0000000000000000000000000000000000000000..a880b16fca8579d4cf982582834aa3c349a31857 --- /dev/null +++ b/test/cases/compile_errors/invalid_deref_on_switch_target.zig @@ -0,0 +1,17 @@ +comptime { + var tile = Tile.Empty; + switch (tile.*) { + Tile.Empty => {}, + Tile.Filled => {}, + } +} +const Tile = enum { + Empty, + Filled, +}; + +// error +// backend=stage2 +// target=native +// +// :3:17: error: cannot dereference non-pointer type 'tmp.Tile' diff --git a/test/cases/compile_errors/invalid_multiple_dereferences.zig b/test/cases/compile_errors/invalid_multiple_dereferences.zig new file mode 100644 index 0000000000000000000000000000000000000000..3edebf7b1f79383e73e669bae0f1f82ccc13a00c --- /dev/null +++ b/test/cases/compile_errors/invalid_multiple_dereferences.zig @@ -0,0 +1,19 @@ +export fn a() void { + var box = Box{ .field = 0 }; + box.*.field = 1; +} +export fn b() void { + var box = Box{ .field = 0 }; + var boxPtr = &box; + boxPtr.*.*.field = 1; +} +pub const Box = struct { + field: i32, +}; + +// error +// backend=stage2 +// target=native +// +// :3:8: error: cannot dereference non-pointer type 'tmp.Box' +// :8:13: error: cannot dereference non-pointer type 'tmp.Box' diff --git a/test/cases/compile_errors/stage1/comptime_ptrcast_of_zero-sized_type.zig b/test/cases/compile_errors/stage1/comptime_ptrcast_of_zero-sized_type.zig new file mode 100644 index 0000000000000000000000000000000000000000..231e735cfa4d58e356123505bb6c8f7134146963 --- /dev/null +++ b/test/cases/compile_errors/stage1/comptime_ptrcast_of_zero-sized_type.zig @@ -0,0 +1,12 @@ +fn foo() void { + const node: struct {} = undefined; + const vla_ptr = @ptrCast([*]const u8, &node); + _ = vla_ptr; +} +comptime { foo(); } + +// error +// backend=stage1 +// target=native +// +// tmp.zig:3:21: error: '*const struct:2:17' and '[*]const u8' do not have the same in-memory representation diff --git a/test/cases/compile_errors/stage1/deref_on_undefined_value.zig b/test/cases/compile_errors/stage1/deref_on_undefined_value.zig deleted file mode 100644 index f64d567a26c242685a23f91fb3752134f97b4940..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/deref_on_undefined_value.zig +++ /dev/null @@ -1,10 +0,0 @@ -comptime { - var a: *u8 = undefined; - _ = a.*; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:9: error: attempt to dereference undefined value diff --git a/test/cases/compile_errors/stage1/obj/assign_to_invalid_dereference.zig b/test/cases/compile_errors/stage1/obj/assign_to_invalid_dereference.zig deleted file mode 100644 index 7fef5db83c33e930d40686158e122b081a9c9121..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/assign_to_invalid_dereference.zig +++ /dev/null @@ -1,9 +0,0 @@ -export fn entry() void { - 'a'.* = 1; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int' diff --git a/test/cases/compile_errors/stage1/obj/comptime_ptrcast_of_zero-sized_type.zig b/test/cases/compile_errors/stage1/obj/comptime_ptrcast_of_zero-sized_type.zig deleted file mode 100644 index 231e735cfa4d58e356123505bb6c8f7134146963..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/comptime_ptrcast_of_zero-sized_type.zig +++ /dev/null @@ -1,12 +0,0 @@ -fn foo() void { - const node: struct {} = undefined; - const vla_ptr = @ptrCast([*]const u8, &node); - _ = vla_ptr; -} -comptime { foo(); } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:21: error: '*const struct:2:17' and '[*]const u8' do not have the same in-memory representation diff --git a/test/cases/compile_errors/stage1/obj/deref_slice_and_get_len_field.zig b/test/cases/compile_errors/stage1/obj/deref_slice_and_get_len_field.zig deleted file mode 100644 index 98097597cc8f4db61359dd8b2751a63edd4c3dd0..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/deref_slice_and_get_len_field.zig +++ /dev/null @@ -1,10 +0,0 @@ -export fn entry() void { - var a: []u8 = undefined; - _ = a.*.len; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8' diff --git a/test/cases/compile_errors/stage1/obj/dereference_an_array.zig b/test/cases/compile_errors/stage1/obj/dereference_an_array.zig deleted file mode 100644 index 0dd91f70e53aa347ea69ddd58c570dc119e0aa65..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/dereference_an_array.zig +++ /dev/null @@ -1,14 +0,0 @@ -var s_buffer: [10]u8 = undefined; -pub fn pass(in: []u8) []u8 { - var out = &s_buffer; - out.*.* = in[0]; - return out.*[0..1]; -} - -export fn entry() usize { return @sizeOf(@TypeOf(pass)); } - -// error -// backend=stage1 -// target=native -// -// tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8' diff --git a/test/cases/compile_errors/stage1/obj/dereference_unknown_length_pointer.zig b/test/cases/compile_errors/stage1/obj/dereference_unknown_length_pointer.zig deleted file mode 100644 index c305e4bc98abcae6029bd64f708e8ecf2b022a5b..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/dereference_unknown_length_pointer.zig +++ /dev/null @@ -1,9 +0,0 @@ -export fn entry(x: [*]i32) i32 { - return x.*; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:13: error: index syntax required for unknown-length pointer type '[*]i32' diff --git a/test/cases/compile_errors/stage1/obj/invalid_deref_on_switch_target.zig b/test/cases/compile_errors/stage1/obj/invalid_deref_on_switch_target.zig deleted file mode 100644 index 966a881543304a501d5a9f5b0db62d93e9caa65d..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/invalid_deref_on_switch_target.zig +++ /dev/null @@ -1,17 +0,0 @@ -comptime { - var tile = Tile.Empty; - switch (tile.*) { - Tile.Empty => {}, - Tile.Filled => {}, - } -} -const Tile = enum { - Empty, - Filled, -}; - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile' diff --git a/test/cases/compile_errors/stage1/obj/invalid_multiple_dereferences.zig b/test/cases/compile_errors/stage1/obj/invalid_multiple_dereferences.zig deleted file mode 100644 index f8a0b8013f0ccbaa8e1519cf013932b0ce607a18..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/invalid_multiple_dereferences.zig +++ /dev/null @@ -1,19 +0,0 @@ -export fn a() void { - var box = Box{ .field = 0 }; - box.*.field = 1; -} -export fn b() void { - var box = Box{ .field = 0 }; - var boxPtr = &box; - boxPtr.*.*.field = 1; -} -pub const Box = struct { - field: i32, -}; - -// error -// backend=stage1 -// target=native -// -// tmp.zig:3:8: error: attempt to dereference non-pointer type 'Box' -// tmp.zig:8:13: error: attempt to dereference non-pointer type 'Box' diff --git a/test/cases/compile_errors/stage1/obj/take_slice_of_invalid_dereference.zig b/test/cases/compile_errors/stage1/obj/take_slice_of_invalid_dereference.zig deleted file mode 100644 index c039be373778354fee485a624a66d1e34aade8c6..0000000000000000000000000000000000000000 --- a/test/cases/compile_errors/stage1/obj/take_slice_of_invalid_dereference.zig +++ /dev/null @@ -1,10 +0,0 @@ -export fn entry() void { - const x = 'a'.*[0..]; - _ = x; -} - -// error -// backend=stage1 -// target=native -// -// tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int' diff --git a/test/cases/compile_errors/take_slice_of_invalid_dereference.zig b/test/cases/compile_errors/take_slice_of_invalid_dereference.zig new file mode 100644 index 0000000000000000000000000000000000000000..35c1b2de0da4822b4ac2111251aab21cdf4bd256 --- /dev/null +++ b/test/cases/compile_errors/take_slice_of_invalid_dereference.zig @@ -0,0 +1,10 @@ +export fn entry() void { + const x = 'a'.*[0..]; + _ = x; +} + +// error +// backend=stage2 +// target=native +// +// :2:18: error: cannot dereference non-pointer type 'comptime_int'