diff --git a/lib/std/fs/wasi.zig b/lib/std/fs/wasi.zig index 81a43062dc..522731ef02 100644 --- a/lib/std/fs/wasi.zig +++ b/lib/std/fs/wasi.zig @@ -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, diff --git a/lib/std/x/net/bpf.zig b/lib/std/x/net/bpf.zig index e8db9a3e0e..8fd318b03b 100644 --- a/lib/std/x/net/bpf.zig +++ b/lib/std/x/net/bpf.zig @@ -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), diff --git a/src/Sema.zig b/src/Sema.zig index 931e06724b..608d6d986a 100644 --- a/src/Sema.zig +++ b/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; diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index 5a878112b5..b3ed2af536 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -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); diff --git a/test/cases/compile_errors/stage2/tuple_ptr_to_mut_slice.zig b/test/cases/compile_errors/stage2/tuple_ptr_to_mut_slice.zig new file mode 100644 index 0000000000..24e4753563 --- /dev/null +++ b/test/cases/compile_errors/stage2/tuple_ptr_to_mut_slice.zig @@ -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