Commit a50759325c

Veikka Tuominen <git@vexu.eu>
2020-12-26 01:36:12
stage2: add error for unused labels
1 parent 40aad4f
Changed files (3)
src/astgen.zig
@@ -348,8 +348,9 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr
 
                 const block_inst = blk: {
                     if (node.getLabel()) |break_label| {
-                        if (gen_zir.label) |label| {
+                        if (gen_zir.label) |*label| {
                             if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
+                                label.used = true;
                                 break :blk label.block_inst;
                             }
                         }
@@ -407,8 +408,9 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE
                     continue;
                 };
                 if (node.getLabel()) |break_label| blk: {
-                    if (gen_zir.label) |label| {
+                    if (gen_zir.label) |*label| {
                         if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
+                            label.used = true;
                             break :blk;
                         }
                     }
@@ -485,6 +487,9 @@ fn labeledBlockExpr(
     defer block_scope.instructions.deinit(mod.gpa);
 
     try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements());
+    if (!block_scope.label.?.used) {
+        return mod.fail(parent_scope, tree.token_locs[block_node.label].start, "unused block label", .{});
+    }
 
     block_inst.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items);
     try gen_zir.instructions.append(mod.gpa, &block_inst.base);
@@ -1398,7 +1403,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
     loop_scope.break_block = while_block;
     loop_scope.continue_block = cond_block;
     if (while_node.label) |some| {
-        loop_scope.label =  @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
+        loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
             .token = some,
             .block_inst = while_block,
         });
@@ -1465,6 +1470,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
     condbr.positionals.else_body = .{
         .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
     };
+    if (loop_scope.label) |some| {
+        if (!some.used) {
+            return mod.fail(scope, tree.token_locs[some.token].start, "unused while label", .{});
+        }
+    }
     return &while_block.base;
 }
 
@@ -1555,7 +1565,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
     loop_scope.break_block = for_block;
     loop_scope.continue_block = cond_block;
     if (for_node.label) |some| {
-        loop_scope.label =  @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
+        loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
             .token = some,
             .block_inst = for_block,
         });
@@ -1646,6 +1656,11 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
     condbr.positionals.else_body = .{
         .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
     };
+    if (loop_scope.label) |some| {
+        if (!some.used) {
+            return mod.fail(scope, tree.token_locs[some.token].start, "unused for label", .{});
+        }
+    }
     return &for_block.base;
 }
 
src/Module.zig
@@ -804,7 +804,7 @@ pub const Scope = struct {
         pub const Label = struct {
             token: ast.TokenIndex,
             block_inst: *zir.Inst.Block,
-            result_loc: astgen.ResultLoc,
+            used: bool = false,
         };
     };
 
test/stage2/test.zig
@@ -1207,7 +1207,7 @@ pub fn addCases(ctx: *TestContext) !void {
 
     {
         var case = ctx.exe("break/continue", linux_x64);
-        
+
         // Break out of loop
         case.addCompareOutput(
             \\export fn _start() noreturn {
@@ -1296,4 +1296,23 @@ pub fn addCases(ctx: *TestContext) !void {
             "",
         );
     }
+
+    {
+        var case = ctx.exe("unused labels", linux_x64);
+        case.addError(
+            \\comptime {
+            \\    foo: {}
+            \\}
+        , &[_][]const u8{":2:5: error: unused block label"});
+        case.addError(
+            \\comptime {
+            \\    foo: while (true) {}
+            \\}
+        , &[_][]const u8{":2:5: error: unused while label"});
+        case.addError(
+            \\comptime {
+            \\    foo: for ("foo") |_| {}
+            \\}
+        , &[_][]const u8{":2:5: error: unused for label"});
+    }
 }