mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
Sema: validate deref operator type and value
This commit is contained in:
parent
3c73f71177
commit
ae7b32eb62
20 changed files with 91 additions and 43 deletions
|
|
@ -82,7 +82,7 @@ fn memset(dest: ?[*]u8, c: u8, len: usize) callconv(.C) ?[*]u8 {
|
||||||
var d = dest.?;
|
var d = dest.?;
|
||||||
var n = len;
|
var n = len;
|
||||||
while (true) {
|
while (true) {
|
||||||
d.* = c;
|
d[0] = c;
|
||||||
n -= 1;
|
n -= 1;
|
||||||
if (n == 0) break;
|
if (n == 0) break;
|
||||||
d += 1;
|
d += 1;
|
||||||
|
|
|
||||||
|
|
@ -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.
|
// Search the entire `environ` because we don't have a null terminated pointer.
|
||||||
var ptr = std.c.environ;
|
var ptr = std.c.environ;
|
||||||
while (ptr.*) |line| : (ptr += 1) {
|
while (ptr[0]) |line| : (ptr += 1) {
|
||||||
var line_i: usize = 0;
|
var line_i: usize = 0;
|
||||||
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
|
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
|
||||||
const this_key = line[0..line_i];
|
const this_key = line[0..line_i];
|
||||||
|
|
|
||||||
|
|
@ -313,7 +313,7 @@ pub fn getEnvMap(allocator: Allocator) !EnvMap {
|
||||||
return result;
|
return result;
|
||||||
} else if (builtin.link_libc) {
|
} else if (builtin.link_libc) {
|
||||||
var ptr = std.c.environ;
|
var ptr = std.c.environ;
|
||||||
while (ptr.*) |line| : (ptr += 1) {
|
while (ptr[0]) |line| : (ptr += 1) {
|
||||||
var line_i: usize = 0;
|
var line_i: usize = 0;
|
||||||
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
|
while (line[line_i] != 0 and line[line_i] != '=') : (line_i += 1) {}
|
||||||
const key = line[0..line_i];
|
const key = line[0..line_i];
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
|
||||||
|
|
||||||
.deref => {
|
.deref => {
|
||||||
const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
|
const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
|
||||||
|
_ = try gz.addUnTok(.validate_deref, lhs, main_tokens[node]);
|
||||||
switch (rl) {
|
switch (rl) {
|
||||||
.ref => return lhs,
|
.ref => return lhs,
|
||||||
else => {
|
else => {
|
||||||
|
|
@ -2500,6 +2501,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
|
||||||
.memset,
|
.memset,
|
||||||
.validate_array_init_ty,
|
.validate_array_init_ty,
|
||||||
.validate_struct_init_ty,
|
.validate_struct_init_ty,
|
||||||
|
.validate_deref,
|
||||||
=> break :b true,
|
=> break :b true,
|
||||||
}
|
}
|
||||||
} else switch (maybe_unused_result) {
|
} else switch (maybe_unused_result) {
|
||||||
|
|
|
||||||
27
src/Sema.zig
27
src/Sema.zig
|
|
@ -1080,6 +1080,11 @@ fn analyzeBodyInner(
|
||||||
i += 1;
|
i += 1;
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
|
.validate_deref => {
|
||||||
|
try sema.zirValidateDeref(block, inst);
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
.@"export" => {
|
.@"export" => {
|
||||||
try sema.zirExport(block, inst);
|
try sema.zirExport(block, inst);
|
||||||
i += 1;
|
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(
|
fn failWithBadMemberAccess(
|
||||||
sema: *Sema,
|
sema: *Sema,
|
||||||
block: *Block,
|
block: *Block,
|
||||||
|
|
|
||||||
|
|
@ -729,6 +729,9 @@ pub const Inst = struct {
|
||||||
/// Same as `validate_array_init` but additionally communicates that the
|
/// Same as `validate_array_init` but additionally communicates that the
|
||||||
/// resulting array initialization value is within a comptime scope.
|
/// resulting array initialization value is within a comptime scope.
|
||||||
validate_array_init_comptime,
|
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.
|
/// A struct literal with a specified type, with no fields.
|
||||||
/// Uses the `un_node` field.
|
/// Uses the `un_node` field.
|
||||||
struct_init_empty,
|
struct_init_empty,
|
||||||
|
|
@ -1156,6 +1159,7 @@ pub const Inst = struct {
|
||||||
.validate_struct_init_comptime,
|
.validate_struct_init_comptime,
|
||||||
.validate_array_init,
|
.validate_array_init,
|
||||||
.validate_array_init_comptime,
|
.validate_array_init_comptime,
|
||||||
|
.validate_deref,
|
||||||
.struct_init_empty,
|
.struct_init_empty,
|
||||||
.struct_init,
|
.struct_init,
|
||||||
.struct_init_ref,
|
.struct_init_ref,
|
||||||
|
|
@ -1309,6 +1313,7 @@ pub const Inst = struct {
|
||||||
.validate_struct_init_comptime,
|
.validate_struct_init_comptime,
|
||||||
.validate_array_init,
|
.validate_array_init,
|
||||||
.validate_array_init_comptime,
|
.validate_array_init_comptime,
|
||||||
|
.validate_deref,
|
||||||
.@"export",
|
.@"export",
|
||||||
.export_value,
|
.export_value,
|
||||||
.set_cold,
|
.set_cold,
|
||||||
|
|
@ -1709,6 +1714,7 @@ pub const Inst = struct {
|
||||||
.validate_struct_init_comptime = .pl_node,
|
.validate_struct_init_comptime = .pl_node,
|
||||||
.validate_array_init = .pl_node,
|
.validate_array_init = .pl_node,
|
||||||
.validate_array_init_comptime = .pl_node,
|
.validate_array_init_comptime = .pl_node,
|
||||||
|
.validate_deref = .un_tok,
|
||||||
.struct_init_empty = .un_node,
|
.struct_init_empty = .un_node,
|
||||||
.field_type = .pl_node,
|
.field_type = .pl_node,
|
||||||
.field_type_ref = .pl_node,
|
.field_type_ref = .pl_node,
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,7 @@ const Writer = struct {
|
||||||
.ret_tok,
|
.ret_tok,
|
||||||
.ensure_err_payload_void,
|
.ensure_err_payload_void,
|
||||||
.closure_capture,
|
.closure_capture,
|
||||||
|
.validate_deref,
|
||||||
=> try self.writeUnTok(stream, inst),
|
=> try self.writeUnTok(stream, inst),
|
||||||
|
|
||||||
.bool_br_and,
|
.bool_br_and,
|
||||||
|
|
|
||||||
|
|
@ -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'
|
||||||
|
|
@ -4,7 +4,7 @@ comptime {
|
||||||
}
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// tmp.zig:3:9: error: attempt to dereference undefined value
|
// :3:10: error: cannot dereference undefined value
|
||||||
|
|
@ -4,7 +4,7 @@ export fn entry() void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// tmp.zig:3:10: error: attempt to dereference non-pointer type '[]u8'
|
// :3:10: error: index syntax required for slice type '[]u8'
|
||||||
|
|
@ -5,10 +5,10 @@ pub fn pass(in: []u8) []u8 {
|
||||||
return out.*[0..1];
|
return out.*[0..1];
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn entry() usize { return @sizeOf(@TypeOf(pass)); }
|
export fn entry() usize { return @sizeOf(@TypeOf(&pass)); }
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// tmp.zig:4:10: error: attempt to dereference non-pointer type '[10]u8'
|
// :4:10: error: cannot dereference non-pointer type '[10]u8'
|
||||||
12
test/cases/compile_errors/dereference_slice.zig
Normal file
12
test/cases/compile_errors/dereference_slice.zig
Normal file
|
|
@ -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'
|
||||||
|
|
@ -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'
|
||||||
|
|
@ -11,7 +11,7 @@ const Tile = enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// tmp.zig:3:17: error: attempt to dereference non-pointer type 'Tile'
|
// :3:17: error: cannot dereference non-pointer type 'tmp.Tile'
|
||||||
|
|
@ -12,8 +12,8 @@ pub const Box = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
// error
|
// error
|
||||||
// backend=stage1
|
// backend=stage2
|
||||||
// target=native
|
// target=native
|
||||||
//
|
//
|
||||||
// tmp.zig:3:8: error: attempt to dereference non-pointer type 'Box'
|
// :3:8: error: cannot dereference non-pointer type 'tmp.Box'
|
||||||
// tmp.zig:8:13: error: attempt to dereference non-pointer type 'Box'
|
// :8:13: error: cannot dereference non-pointer type 'tmp.Box'
|
||||||
|
|
@ -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'
|
|
||||||
|
|
@ -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'
|
|
||||||
|
|
@ -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'
|
|
||||||
|
|
@ -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'
|
||||||
Loading…
Add table
Reference in a new issue