Commit 7e0c6d7edc

Jacob Young <jacobly0@users.noreply.github.com>
2023-04-15 08:48:35
Sema: fix empty infinite loops
Closes #15284
1 parent 7fad555
Changed files (4)
src
test
standalone
strip_empty_loop
src/Sema.zig
@@ -5225,17 +5225,17 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
 
     try sema.analyzeBody(&loop_block, body);
 
-    if (sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block.instructions.items.len - 1])).isNoReturn()) {
+    const loop_block_len = loop_block.instructions.items.len;
+    if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn()) {
         // If the loop ended with a noreturn terminator, then there is no way for it to loop,
         // so we can just use the block instead.
         try child_block.instructions.appendSlice(gpa, loop_block.instructions.items);
     } else {
         try child_block.instructions.append(gpa, loop_inst);
 
-        try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
-            loop_block.instructions.items.len);
+        try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + loop_block_len);
         sema.air_instructions.items(.data)[loop_inst].ty_pl.payload = sema.addExtraAssumeCapacity(
-            Air.Block{ .body_len = @intCast(u32, loop_block.instructions.items.len) },
+            Air.Block{ .body_len = @intCast(u32, loop_block_len) },
         );
         sema.air_extra.appendSliceAssumeCapacity(loop_block.instructions.items);
     }
test/standalone/strip_empty_loop/build.zig
@@ -0,0 +1,18 @@
+const std = @import("std");
+
+pub fn build(b: *std.Build) void {
+    const test_step = b.step("test", "Test the program");
+    b.default_step = test_step;
+
+    const optimize = std.builtin.OptimizeMode.Debug;
+    const target = std.zig.CrossTarget{};
+
+    const main = b.addExecutable(.{
+        .name = "main",
+        .root_source_file = .{ .path = "main.zig" },
+        .optimize = optimize,
+        .target = target,
+    });
+    main.strip = true;
+    test_step.dependOn(&main.step);
+}
test/standalone/strip_empty_loop/main.zig
@@ -0,0 +1,3 @@
+pub fn main() noreturn {
+    while (true) {} // When built without debug info, this produces an Air loop with no instructions
+}
test/standalone.zig
@@ -218,6 +218,10 @@ pub const build_cases = [_]BuildCase{
     //    .build_root = "test/standalone/options",
     //    .import = @import("standalone/options/build.zig"),
     //},
+    .{
+        .build_root = "test/standalone/strip_empty_loop",
+        .import = @import("standalone/strip_empty_loop/build.zig"),
+    },
 };
 
 const std = @import("std");