mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
Sema: Prevent coercion from tuple pointer to mutable slice.
Also fix some stdlib code affected by this. Co-authored by: topolarity <topolarity@tapscott.me>
This commit is contained in:
parent
1d1c7ae5de
commit
bc72ae5e4e
@ -201,7 +201,7 @@ pub const PreopenList = struct {
|
||||
// If we were provided a CWD root to resolve against, we try to treat Preopen dirs as
|
||||
// POSIX paths, relative to "/" or `cwd_root` depending on whether they start with "."
|
||||
const path = if (cwd_root) |cwd| blk: {
|
||||
const resolve_paths: [][]const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path };
|
||||
const resolve_paths: []const []const u8 = if (raw_path[0] == '.') &.{ cwd, raw_path } else &.{ "/", raw_path };
|
||||
break :blk fs.path.resolve(self.buffer.allocator, resolve_paths) catch |err| switch (err) {
|
||||
error.CurrentWorkingDirectoryUnlinked => unreachable, // root is absolute, so CWD not queried
|
||||
else => |e| return e,
|
||||
|
||||
@ -691,14 +691,14 @@ test "tcpdump filter" {
|
||||
);
|
||||
}
|
||||
|
||||
fn expectPass(data: anytype, filter: []Insn) !void {
|
||||
fn expectPass(data: anytype, filter: []const Insn) !void {
|
||||
try expectEqual(
|
||||
@as(u32, 0),
|
||||
try simulate(mem.asBytes(data), filter, .Big),
|
||||
);
|
||||
}
|
||||
|
||||
fn expectFail(expected_error: anyerror, data: anytype, filter: []Insn) !void {
|
||||
fn expectFail(expected_error: anyerror, data: anytype, filter: []const Insn) !void {
|
||||
try expectError(
|
||||
expected_error,
|
||||
simulate(mem.asBytes(data), filter, native_endian),
|
||||
|
||||
63
src/Sema.zig
63
src/Sema.zig
@ -18208,7 +18208,7 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
|
||||
return sema.analyzeDeclVal(block, src, new_decl_index);
|
||||
},
|
||||
.Fn => {
|
||||
const struct_val = union_val.val.castTag(.aggregate).?.data;
|
||||
const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
|
||||
// TODO use reflection instead of magic numbers here
|
||||
// calling_convention: CallingConvention,
|
||||
const cc = struct_val[0].toEnum(std.builtin.CallingConvention);
|
||||
@ -18242,12 +18242,17 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
|
||||
break :alignment alignment;
|
||||
}
|
||||
};
|
||||
const return_type = return_type_val.optionalValue() orelse
|
||||
return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
|
||||
|
||||
var buf: Value.ToTypeBuffer = undefined;
|
||||
|
||||
const args_slice_val = args_val.castTag(.slice).?.data;
|
||||
const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget()));
|
||||
var param_types = try sema.arena.alloc(Type, args_len);
|
||||
var comptime_params = try sema.arena.alloc(bool, args_len);
|
||||
|
||||
const param_types = try sema.arena.alloc(Type, args_len);
|
||||
const comptime_params = try sema.arena.alloc(bool, args_len);
|
||||
|
||||
var noalias_bits: u32 = 0;
|
||||
var i: usize = 0;
|
||||
while (i < args_len) : (i += 1) {
|
||||
@ -18275,11 +18280,9 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
|
||||
return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
|
||||
|
||||
param_types[i] = try param_type.toType(&buf).copy(sema.arena);
|
||||
comptime_params[i] = false;
|
||||
}
|
||||
|
||||
const return_type = return_type_val.optionalValue() orelse
|
||||
return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
|
||||
|
||||
var fn_info = Type.Payload.Function.Data{
|
||||
.param_types = param_types,
|
||||
.comptime_params = comptime_params.ptr,
|
||||
@ -24075,27 +24078,7 @@ fn coerceExtra(
|
||||
},
|
||||
else => {},
|
||||
},
|
||||
.Slice => {
|
||||
// pointer to tuple to slice
|
||||
if (inst_ty.isSinglePointer() and inst_ty.childType().isTuple() and dest_info.size == .Slice and
|
||||
sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
|
||||
{
|
||||
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
}
|
||||
|
||||
// empty tuple to zero-length slice
|
||||
// note that this allows coercing to a mutable slice.
|
||||
if (inst_ty.isSinglePointer() and
|
||||
inst_ty.childType().tag() == .empty_struct_literal and
|
||||
dest_info.size == .Slice)
|
||||
{
|
||||
const slice_val = try Value.Tag.slice.create(sema.arena, .{
|
||||
.ptr = Value.undef,
|
||||
.len = Value.zero,
|
||||
});
|
||||
return sema.addConstant(dest_ty, slice_val);
|
||||
}
|
||||
|
||||
.Slice => to_slice: {
|
||||
if (inst_ty.zigTypeTag() == .Array) {
|
||||
return sema.fail(
|
||||
block,
|
||||
@ -24104,6 +24087,32 @@ fn coerceExtra(
|
||||
.{dest_ty.fmt(sema.mod)},
|
||||
);
|
||||
}
|
||||
|
||||
if (!inst_ty.isSinglePointer()) break :to_slice;
|
||||
const inst_child_ty = inst_ty.childType();
|
||||
if (!inst_child_ty.isTuple()) break :to_slice;
|
||||
|
||||
// empty tuple to zero-length slice
|
||||
// note that this allows coercing to a mutable slice.
|
||||
if (inst_child_ty.tupleFields().types.len == 0) {
|
||||
const slice_val = try Value.Tag.slice.create(sema.arena, .{
|
||||
.ptr = Value.undef,
|
||||
.len = Value.zero,
|
||||
});
|
||||
return sema.addConstant(dest_ty, slice_val);
|
||||
}
|
||||
|
||||
// pointer to tuple to slice
|
||||
if (dest_info.mutable) {
|
||||
const err_msg = err_msg: {
|
||||
const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(sema.mod)});
|
||||
errdefer err_msg.deinit(sema.gpa);
|
||||
try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
|
||||
break :err_msg err_msg;
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(err_msg);
|
||||
}
|
||||
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
|
||||
},
|
||||
.Many => p: {
|
||||
if (!inst_ty.isSlice()) break :p;
|
||||
|
||||
@ -410,7 +410,7 @@ test "load pointer from packed struct" {
|
||||
y: u32,
|
||||
};
|
||||
var a: A = .{ .index = 123 };
|
||||
var b_list: []B = &.{.{ .x = &a, .y = 99 }};
|
||||
var b_list: []const B = &.{.{ .x = &a, .y = 99 }};
|
||||
for (b_list) |b| {
|
||||
var i = b.x.index;
|
||||
try expect(i == 123);
|
||||
|
||||
32
test/cases/compile_errors/stage2/tuple_ptr_to_mut_slice.zig
Normal file
32
test/cases/compile_errors/stage2/tuple_ptr_to_mut_slice.zig
Normal file
@ -0,0 +1,32 @@
|
||||
export fn entry1() void {
|
||||
var a = .{ 1, 2, 3 };
|
||||
_ = @as([]u8, &a);
|
||||
}
|
||||
export fn entry2() void {
|
||||
var a = .{ @as(u8, 1), @as(u8, 2), @as(u8, 3) };
|
||||
_ = @as([]u8, &a);
|
||||
}
|
||||
|
||||
// runtime values
|
||||
var vals = [_]u7{ 4, 5, 6 };
|
||||
export fn entry3() void {
|
||||
var a = .{ vals[0], vals[1], vals[2] };
|
||||
_ = @as([]u8, &a);
|
||||
}
|
||||
export fn entry4() void {
|
||||
var a = .{ @as(u8, vals[0]), @as(u8, vals[1]), @as(u8, vals[2]) };
|
||||
_ = @as([]u8, &a);
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :3:19: error: cannot cast pointer to tuple to '[]u8'
|
||||
// :3:19: note: pointers to tuples can only coerce to constant pointers
|
||||
// :7:19: error: cannot cast pointer to tuple to '[]u8'
|
||||
// :7:19: note: pointers to tuples can only coerce to constant pointers
|
||||
// :14:19: error: cannot cast pointer to tuple to '[]u8'
|
||||
// :14:19: note: pointers to tuples can only coerce to constant pointers
|
||||
// :18:19: error: cannot cast pointer to tuple to '[]u8'
|
||||
// :18:19: note: pointers to tuples can only coerce to constant pointers
|
||||
Loading…
x
Reference in New Issue
Block a user