Commit b8e6c42688

mlugg <mlugg@mlugg.co.uk>
2023-08-27 18:28:37
compiler: provide result type for @memset value
Resolves: #16986
1 parent 8d036d1
Changed files (5)
src/AstGen.zig
@@ -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);
         },
src/print_zir.zig
@@ -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,
src/Sema.zig
@@ -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;
src/Zir.zig
@@ -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,
test/behavior/memset.zig
@@ -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);
+}