Commit 93e53d1e00

mlugg <mlugg@mlugg.co.uk>
2023-07-29 07:22:29
compiler: fix crash on invalid result type for `@splat`
This introduces a new ZIR instruction, `vec_elem_type`. Co-Authored-By: Ali Chraghi <alichraghi@proton.me> Resolves: #16567
1 parent 6917a8c
Changed files (5)
src/AstGen.zig
@@ -2569,6 +2569,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
             .array_type_sentinel,
             .elem_type_index,
             .elem_type,
+            .vector_elem_type,
             .vector_type,
             .indexable_ptr_len,
             .anyframe_type,
@@ -8624,13 +8625,7 @@ fn builtinCall(
 
         .splat => {
             const result_type = try ri.rl.resultType(gz, node, "@splat");
-            const elem_type = try gz.add(.{
-                .tag = .elem_type_index,
-                .data = .{ .bin = .{
-                    .lhs = result_type,
-                    .rhs = @as(Zir.Inst.Ref, @enumFromInt(0)),
-                } },
-            });
+            const elem_type = try gz.addUnNode(.vector_elem_type, result_type, node);
             const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
             const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
                 .lhs = result_type,
src/print_zir.zig
@@ -155,6 +155,7 @@ const Writer = struct {
             .alloc_mut,
             .alloc_comptime_mut,
             .elem_type,
+            .vector_elem_type,
             .indexable_ptr_len,
             .anyframe_type,
             .bit_not,
src/Sema.zig
@@ -1022,6 +1022,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),
+            .vector_elem_type             => try sema.zirVectorElemType(block, inst),
             .enum_literal                 => try sema.zirEnumLiteral(block, inst),
             .int_from_enum                => try sema.zirIntFromEnum(block, inst),
             .enum_from_int                => try sema.zirEnumFromInt(block, inst),
@@ -7804,6 +7805,23 @@ fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
     return sema.addType(ptr_ty.childType(mod));
 }
 
+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;
+    const vec_ty = sema.resolveType(block, .unneeded, un_node.operand) catch |err| switch (err) {
+        // Since this is a ZIR instruction that returns a type, encountering
+        // generic poison should not result in a failed compilation, but the
+        // generic poison type. This prevents unnecessary failures when
+        // constructing types at compile-time.
+        error.GenericPoison => return .generic_poison_type,
+        else => |e| return e,
+    };
+    if (!vec_ty.isVector(mod)) {
+        return sema.fail(block, un_node.src(), "expected vector type, found '{}'", .{vec_ty.fmt(mod)});
+    }
+    return sema.addType(vec_ty.childType(mod));
+}
+
 fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
     const mod = sema.mod;
     const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
src/Zir.zig
@@ -248,6 +248,9 @@ pub const Inst = struct {
         /// Given a pointer type, returns its element type.
         /// Uses the `un_node` field.
         elem_type,
+        /// Given a vector type, returns its element type.
+        /// Uses the `un_node` field.
+        vector_elem_type,
         /// Given a pointer to an indexable object, returns the len property. This is
         /// used by for loops. This instruction also emits a for-loop specific compile
         /// error if the indexable object is not indexable.
@@ -1029,6 +1032,7 @@ pub const Inst = struct {
                 .vector_type,
                 .elem_type_index,
                 .elem_type,
+                .vector_elem_type,
                 .indexable_ptr_len,
                 .anyframe_type,
                 .as,
@@ -1334,6 +1338,7 @@ pub const Inst = struct {
                 .vector_type,
                 .elem_type_index,
                 .elem_type,
+                .vector_elem_type,
                 .indexable_ptr_len,
                 .anyframe_type,
                 .as,
@@ -1565,6 +1570,7 @@ pub const Inst = struct {
                 .vector_type = .pl_node,
                 .elem_type_index = .bin,
                 .elem_type = .un_node,
+                .vector_elem_type = .un_node,
                 .indexable_ptr_len = .un_node,
                 .anyframe_type = .un_node,
                 .as = .bin,
test/cases/compile_errors/splat_result_type_non_vector.zig
@@ -0,0 +1,9 @@
+export fn f() void {
+    _ = @as(u32, @splat(5));
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:18: error: expected vector type, found 'u32'