compiler: provide result type for @memset value

Resolves: #16986
This commit is contained in:
mlugg 2023-08-27 17:28:37 +01:00 committed by Andrew Kelley
parent 8d036d1d78
commit b8e6c42688
5 changed files with 49 additions and 2 deletions

View File

@ -2441,6 +2441,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.array_type_sentinel,
.elem_type_index,
.elem_type,
.indexable_ptr_elem_type,
.vector_elem_type,
.vector_type,
.indexable_ptr_len,
@ -8302,9 +8303,12 @@ fn builtinCall(
return rvalue(gz, ri, .void_value, node);
},
.memset => {
const lhs = try expr(gz, scope, .{ .rl = .none }, params[0]);
const lhs_ty = try gz.addUnNode(.typeof, lhs, params[0]);
const elem_ty = try gz.addUnNode(.indexable_ptr_elem_type, lhs_ty, params[0]);
_ = try gz.addPlNode(.memset, node, Zir.Inst.Bin{
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),
.lhs = lhs,
.rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = elem_ty } }, params[1]),
});
return rvalue(gz, ri, .void_value, node);
},

View File

@ -1023,6 +1023,7 @@ fn analyzeBodyInner(
.elem_val_node => try sema.zirElemValNode(block, inst),
.elem_type_index => try sema.zirElemTypeIndex(block, inst),
.elem_type => try sema.zirElemType(block, inst),
.indexable_ptr_elem_type => try sema.zirIndexablePtrElemType(block, inst),
.vector_elem_type => try sema.zirVectorElemType(block, inst),
.enum_literal => try sema.zirEnumLiteral(block, inst),
.int_from_enum => try sema.zirIntFromEnum(block, inst),
@ -8106,6 +8107,22 @@ fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
return Air.internedToRef(ptr_ty.childType(mod).toIntern());
}
fn zirIndexablePtrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const un_node = sema.code.instructions.items(.data)[inst].un_node;
const src = un_node.src();
const ptr_ty = sema.resolveType(block, src, un_node.operand) catch |err| switch (err) {
error.GenericPoison => return .generic_poison_type,
else => |e| return e,
};
try sema.checkMemOperand(block, src, ptr_ty);
const elem_ty = switch (ptr_ty.ptrSize(mod)) {
.Slice, .Many, .C => ptr_ty.childType(mod),
.One => ptr_ty.childType(mod).childType(mod),
};
return Air.internedToRef(elem_ty.toIntern());
}
fn zirVectorElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const un_node = sema.code.instructions.items(.data)[inst].un_node;

View File

@ -248,6 +248,10 @@ pub const Inst = struct {
/// Given a pointer type, returns its element type.
/// Uses the `un_node` field.
elem_type,
/// Given an indexable pointer (slice, many-ptr, single-ptr-to-array), returns its
/// element type. Emits a compile error if the type is not an indexable pointer.
/// Uses the `un_node` field.
indexable_ptr_elem_type,
/// Given a vector type, returns its element type.
/// Uses the `un_node` field.
vector_elem_type,
@ -1021,6 +1025,7 @@ pub const Inst = struct {
.vector_type,
.elem_type_index,
.elem_type,
.indexable_ptr_elem_type,
.vector_elem_type,
.indexable_ptr_len,
.anyframe_type,
@ -1325,6 +1330,7 @@ pub const Inst = struct {
.vector_type,
.elem_type_index,
.elem_type,
.indexable_ptr_elem_type,
.vector_elem_type,
.indexable_ptr_len,
.anyframe_type,
@ -1557,6 +1563,7 @@ pub const Inst = struct {
.vector_type = .pl_node,
.elem_type_index = .bin,
.elem_type = .un_node,
.indexable_ptr_elem_type = .un_node,
.vector_elem_type = .un_node,
.indexable_ptr_len = .un_node,
.anyframe_type = .un_node,

View File

@ -154,6 +154,7 @@ const Writer = struct {
.alloc_mut,
.alloc_comptime_mut,
.elem_type,
.indexable_ptr_elem_type,
.vector_elem_type,
.indexable_ptr_len,
.anyframe_type,

View File

@ -135,3 +135,21 @@ test "memset with large array element, comptime known" {
for (buf[3]) |elem| try expect(elem == 0);
for (buf[4]) |elem| try expect(elem == 0);
}
test "@memset provides result type" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
const S = struct { x: u32 };
var buf1: [5]S = undefined;
@memset(&buf1, .{ .x = @intCast(12) });
var buf2: [5]S = undefined;
@memset(@as([]S, &buf2), .{ .x = @intCast(34) });
for (buf1) |s| try expect(s.x == 12);
for (buf2) |s| try expect(s.x == 34);
}