Commit ce7acf1296

Jacob Young <jacobly0@users.noreply.github.com>
2023-08-12 05:54:54
AstGen: fix src loc for invalid coercion in breaks
1 parent 2b5bd56
Changed files (3)
src/AstGen.zig
@@ -2373,8 +2373,8 @@ fn labeledBlockExpr(
         try astgen.appendErrorTok(label_token, "unused block label", .{});
     }
 
-    const zir_datas = gz.astgen.instructions.items(.data);
-    const zir_tags = gz.astgen.instructions.items(.tag);
+    const zir_datas = astgen.instructions.items(.data);
+    const zir_tags = astgen.instructions.items(.tag);
     const strat = ri.rl.strategy(&block_scope);
     switch (strat.tag) {
         .break_void => {
@@ -2396,6 +2396,10 @@ fn labeledBlockExpr(
             // it as the break operand.
             // This corresponds to similar code in `setCondBrPayloadElideBlockStorePtr`.
             if (block_scope.rl_ty_inst != .none) {
+                try astgen.extra.ensureUnusedCapacity(
+                    astgen.gpa,
+                    @typeInfo(Zir.Inst.As).Struct.fields.len * block_scope.labeled_breaks.items.len,
+                );
                 for (block_scope.labeled_breaks.items) |br| {
                     // We expect the `store_to_block_ptr` to be created between 1-3 instructions
                     // prior to the break.
@@ -2404,12 +2408,28 @@ fn labeledBlockExpr(
                         if (zir_tags[search_index] == .store_to_block_ptr and
                             zir_datas[search_index].bin.lhs == block_scope.rl_ptr)
                         {
-                            zir_tags[search_index] = .as;
-                            zir_datas[search_index].bin = .{
-                                .lhs = block_scope.rl_ty_inst,
-                                .rhs = zir_datas[br.br].@"break".operand,
-                            };
-                            zir_datas[br.br].@"break".operand = indexToRef(search_index);
+                            const break_data = &zir_datas[br.br].@"break";
+                            const break_src: i32 = @bitCast(astgen.extra.items[
+                                break_data.payload_index +
+                                    std.meta.fieldIndex(Zir.Inst.Break, "operand_src_node").?
+                            ]);
+                            if (break_src == Zir.Inst.Break.no_src_node) {
+                                zir_tags[search_index] = .as;
+                                zir_datas[search_index].bin = .{
+                                    .lhs = block_scope.rl_ty_inst,
+                                    .rhs = break_data.operand,
+                                };
+                            } else {
+                                zir_tags[search_index] = .as_node;
+                                zir_datas[search_index] = .{ .pl_node = .{
+                                    .src_node = break_src,
+                                    .payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.As{
+                                        .dest_type = block_scope.rl_ty_inst,
+                                        .operand = break_data.operand,
+                                    }),
+                                } };
+                            }
+                            break_data.operand = indexToRef(search_index);
                             break;
                         }
                     } else unreachable;
@@ -2530,19 +2550,21 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
             // For some instructions, modify the zir data
             // so we can avoid a separate ensure_result_used instruction.
             .call, .field_call => {
-                const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
-                const slot = &gz.astgen.extra.items[extra_index];
-                var flags = @as(Zir.Inst.Call.Flags, @bitCast(slot.*));
+                const break_extra = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
+                comptime assert(std.meta.fieldIndex(Zir.Inst.Call, "flags") ==
+                    std.meta.fieldIndex(Zir.Inst.FieldCall, "flags"));
+                const flags: *Zir.Inst.Call.Flags = @ptrCast(&gz.astgen.extra.items[
+                    break_extra + std.meta.fieldIndex(Zir.Inst.Call, "flags").?
+                ]);
                 flags.ensure_result_used = true;
-                slot.* = @as(u32, @bitCast(flags));
                 break :b true;
             },
             .builtin_call => {
-                const extra_index = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
-                const slot = &gz.astgen.extra.items[extra_index];
-                var flags = @as(Zir.Inst.BuiltinCall.Flags, @bitCast(slot.*));
+                const break_extra = gz.astgen.instructions.items(.data)[inst].pl_node.payload_index;
+                const flags: *Zir.Inst.BuiltinCall.Flags = @ptrCast(&gz.astgen.extra.items[
+                    break_extra + std.meta.fieldIndex(Zir.Inst.BuiltinCall, "flags").?
+                ]);
                 flags.ensure_result_used = true;
-                slot.* = @as(u32, @bitCast(flags));
                 break :b true;
             },
 
@@ -6106,14 +6128,12 @@ fn setCondBrPayloadElideBlockStorePtr(
     const zir_tags = astgen.instructions.items(.tag);
     const zir_datas = astgen.instructions.items(.data);
 
-    const condbr_pl = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
+    const condbr_extra = astgen.addExtraAssumeCapacity(Zir.Inst.CondBr{
         .condition = cond,
         .then_body_len = then_body_len,
         .else_body_len = else_body_len,
     });
-    zir_datas[condbr].pl_node.payload_index = condbr_pl;
-    const then_body_len_index = condbr_pl + 1;
-    const else_body_len_index = condbr_pl + 2;
+    zir_datas[condbr].pl_node.payload_index = condbr_extra;
 
     // The break instructions need to have their operands coerced if the
     // switch's result location is a `ty`. In this case we overwrite the
@@ -6128,7 +6148,9 @@ fn setCondBrPayloadElideBlockStorePtr(
             if (then_scope.rl_ty_inst != .none and has_then_break) {
                 then_as_inst = src_inst;
             } else {
-                astgen.extra.items[then_body_len_index] -= 1;
+                astgen.extra.items[
+                    condbr_extra + std.meta.fieldIndex(Zir.Inst.CondBr, "then_body_len").?
+                ] -= 1;
                 continue;
             }
         }
@@ -6144,7 +6166,9 @@ fn setCondBrPayloadElideBlockStorePtr(
             if (else_scope.rl_ty_inst != .none and has_else_break) {
                 else_as_inst = src_inst;
             } else {
-                astgen.extra.items[else_body_len_index] -= 1;
+                astgen.extra.items[
+                    condbr_extra + std.meta.fieldIndex(Zir.Inst.CondBr, "else_body_len").?
+                ] -= 1;
                 continue;
             }
         }
@@ -7247,11 +7271,11 @@ fn switchExpr(
                 assert(!strat.elide_store_to_block_ptr_instructions);
                 const last_inst = payloads.items[end_index - 1];
                 if (zir_tags[last_inst] == .@"break") {
-                    const inst_data = zir_datas[last_inst].@"break";
-                    const block_inst = astgen.extra.items[inst_data.payload_index];
-                    if (block_inst == switch_block) {
-                        zir_datas[last_inst].@"break".operand = .void_value;
-                    }
+                    const break_data = &zir_datas[last_inst].@"break";
+                    const block_inst = astgen.extra.items[
+                        break_data.payload_index + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?
+                    ];
+                    if (block_inst == switch_block) break_data.operand = .void_value;
                 }
             },
         }
@@ -11648,40 +11672,47 @@ const GenZir = struct {
             if (align_body.len != 0) {
                 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, align_body));
                 astgen.appendBodyWithFixups(align_body);
-                const inst_data = zir_datas[align_body[align_body.len - 1]].@"break";
-                astgen.extra.items[inst_data.payload_index] = new_index;
+                const break_extra = zir_datas[align_body[align_body.len - 1]].@"break".payload_index;
+                astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
+                    new_index;
             } else if (args.align_ref != .none) {
                 astgen.extra.appendAssumeCapacity(@intFromEnum(args.align_ref));
             }
             if (addrspace_body.len != 0) {
                 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, addrspace_body));
                 astgen.appendBodyWithFixups(addrspace_body);
-                const inst_data = zir_datas[addrspace_body[addrspace_body.len - 1]].@"break";
-                astgen.extra.items[inst_data.payload_index] = new_index;
+                const break_extra =
+                    zir_datas[addrspace_body[addrspace_body.len - 1]].@"break".payload_index;
+                astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
+                    new_index;
             } else if (args.addrspace_ref != .none) {
                 astgen.extra.appendAssumeCapacity(@intFromEnum(args.addrspace_ref));
             }
             if (section_body.len != 0) {
                 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, section_body));
                 astgen.appendBodyWithFixups(section_body);
-                const inst_data = zir_datas[section_body[section_body.len - 1]].@"break";
-                astgen.extra.items[inst_data.payload_index] = new_index;
+                const break_extra =
+                    zir_datas[section_body[section_body.len - 1]].@"break".payload_index;
+                astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
+                    new_index;
             } else if (args.section_ref != .none) {
                 astgen.extra.appendAssumeCapacity(@intFromEnum(args.section_ref));
             }
             if (cc_body.len != 0) {
                 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, cc_body));
                 astgen.appendBodyWithFixups(cc_body);
-                const inst_data = zir_datas[cc_body[cc_body.len - 1]].@"break";
-                astgen.extra.items[inst_data.payload_index] = new_index;
+                const break_extra = zir_datas[cc_body[cc_body.len - 1]].@"break".payload_index;
+                astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
+                    new_index;
             } else if (args.cc_ref != .none) {
                 astgen.extra.appendAssumeCapacity(@intFromEnum(args.cc_ref));
             }
             if (ret_body.len != 0) {
                 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, ret_body));
                 astgen.appendBodyWithFixups(ret_body);
-                const inst_data = zir_datas[ret_body[ret_body.len - 1]].@"break";
-                astgen.extra.items[inst_data.payload_index] = new_index;
+                const break_extra = zir_datas[ret_body[ret_body.len - 1]].@"break".payload_index;
+                astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
+                    new_index;
             } else if (ret_ref != .none) {
                 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));
             }
@@ -11736,8 +11767,9 @@ const GenZir = struct {
             if (ret_body.len != 0) {
                 astgen.appendBodyWithFixups(ret_body);
 
-                const inst_data = zir_datas[ret_body[ret_body.len - 1]].@"break";
-                astgen.extra.items[inst_data.payload_index] = new_index;
+                const break_extra = zir_datas[ret_body[ret_body.len - 1]].@"break".payload_index;
+                astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
+                    new_index;
             } else if (ret_ref != .none) {
                 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));
             }
@@ -12191,21 +12223,8 @@ const GenZir = struct {
     ) !Zir.Inst.Index {
         const gpa = gz.astgen.gpa;
         try gz.instructions.ensureUnusedCapacity(gpa, 1);
-        try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
 
-        const extra: Zir.Inst.Break = .{
-            .block_inst = block_inst,
-            .operand_src_node = Zir.Inst.Break.no_src_node,
-        };
-        const payload_index = try gz.astgen.addExtra(extra);
-        const new_index = @as(Zir.Inst.Index, @intCast(gz.astgen.instructions.len));
-        gz.astgen.instructions.appendAssumeCapacity(.{
-            .tag = tag,
-            .data = .{ .@"break" = .{
-                .operand = operand,
-                .payload_index = payload_index,
-            } },
-        });
+        const new_index = try gz.makeBreak(tag, block_inst, operand);
         gz.instructions.appendAssumeCapacity(new_index);
         return new_index;
     }
@@ -12216,23 +12235,7 @@ const GenZir = struct {
         block_inst: Zir.Inst.Index,
         operand: Zir.Inst.Ref,
     ) !Zir.Inst.Index {
-        const gpa = gz.astgen.gpa;
-        try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
-
-        const extra: Zir.Inst.Break = .{
-            .block_inst = block_inst,
-            .operand_src_node = Zir.Inst.Break.no_src_node,
-        };
-        const payload_index = try gz.astgen.addExtra(extra);
-        const new_index = @as(Zir.Inst.Index, @intCast(gz.astgen.instructions.len));
-        gz.astgen.instructions.appendAssumeCapacity(.{
-            .tag = tag,
-            .data = .{ .@"break" = .{
-                .operand = operand,
-                .payload_index = payload_index,
-            } },
-        });
-        return new_index;
+        return gz.makeBreakCommon(tag, block_inst, operand, null);
     }
 
     fn addBreakWithSrcNode(
@@ -12244,21 +12247,8 @@ const GenZir = struct {
     ) !Zir.Inst.Index {
         const gpa = gz.astgen.gpa;
         try gz.instructions.ensureUnusedCapacity(gpa, 1);
-        try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
 
-        const extra: Zir.Inst.Break = .{
-            .block_inst = block_inst,
-            .operand_src_node = gz.nodeIndexToRelative(operand_src_node),
-        };
-        const payload_index = try gz.astgen.addExtra(extra);
-        const new_index = @as(Zir.Inst.Index, @intCast(gz.astgen.instructions.len));
-        gz.astgen.instructions.appendAssumeCapacity(.{
-            .tag = tag,
-            .data = .{ .@"break" = .{
-                .operand = operand,
-                .payload_index = payload_index,
-            } },
-        });
+        const new_index = try gz.makeBreakWithSrcNode(tag, block_inst, operand, operand_src_node);
         gz.instructions.appendAssumeCapacity(new_index);
         return new_index;
     }
@@ -12269,21 +12259,33 @@ const GenZir = struct {
         block_inst: Zir.Inst.Index,
         operand: Zir.Inst.Ref,
         operand_src_node: Ast.Node.Index,
+    ) !Zir.Inst.Index {
+        return gz.makeBreakCommon(tag, block_inst, operand, operand_src_node);
+    }
+
+    fn makeBreakCommon(
+        gz: *GenZir,
+        tag: Zir.Inst.Tag,
+        block_inst: Zir.Inst.Index,
+        operand: Zir.Inst.Ref,
+        operand_src_node: ?Ast.Node.Index,
     ) !Zir.Inst.Index {
         const gpa = gz.astgen.gpa;
         try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
+        try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Break).Struct.fields.len);
 
-        const extra: Zir.Inst.Break = .{
-            .block_inst = block_inst,
-            .operand_src_node = gz.nodeIndexToRelative(operand_src_node),
-        };
-        const payload_index = try gz.astgen.addExtra(extra);
-        const new_index = @as(Zir.Inst.Index, @intCast(gz.astgen.instructions.len));
+        const new_index: Zir.Inst.Index = @intCast(gz.astgen.instructions.len);
         gz.astgen.instructions.appendAssumeCapacity(.{
             .tag = tag,
             .data = .{ .@"break" = .{
                 .operand = operand,
-                .payload_index = payload_index,
+                .payload_index = gz.astgen.addExtraAssumeCapacity(Zir.Inst.Break{
+                    .operand_src_node = if (operand_src_node) |src_node|
+                        gz.nodeIndexToRelative(src_node)
+                    else
+                        Zir.Inst.Break.no_src_node,
+                    .block_inst = block_inst,
+                }),
             } },
         });
         return new_index;
src/Zir.zig
@@ -2347,8 +2347,8 @@ pub const Inst = struct {
     pub const Break = struct {
         pub const no_src_node = std.math.maxInt(i32);
 
-        block_inst: Index,
         operand_src_node: i32,
+        block_inst: Index,
     };
 
     /// Trailing:
test/cases/compile_errors/invalid_coercion_in_labeled_break.zig
@@ -0,0 +1,12 @@
+export fn invalidBreak() u8 {
+    const result: u8 = label: {
+        break :label 256;
+    };
+    return result;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :3:22: error: type 'u8' cannot represent integer value '256'