authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-12-26 02:36:12+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-12-26 02:36:12+02:00
loga50759325c95ad7dfd1fbf029759cf0a2608b3ab
tree8bdf7813a7b82e743ffc3dbc589314c94ba9473d
parent40aad4f47e1ab02a1ff6109f4b6f06af00d1f503
signaturelock-open Commit is signed but in an unrecognized format.

stage2: add error for unused labels


3 files changed, 40 insertions(+), 6 deletions(-)

src/Module.zig+1-1
...@@ -804,7 +804,7 @@ pub const Scope = struct {...@@ -804,7 +804,7 @@ pub const Scope = struct {
804 pub const Label = struct {804 pub const Label = struct {
805 token: ast.TokenIndex,805 token: ast.TokenIndex,
806 block_inst: *zir.Inst.Block,806 block_inst: *zir.Inst.Block,
807 result_loc: astgen.ResultLoc,807 used: bool = false,
808 };808 };
809 };809 };
810810
src/astgen.zig+19-4
...@@ -348,8 +348,9 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr...@@ -348,8 +348,9 @@ fn breakExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpr
348348
349 const block_inst = blk: {349 const block_inst = blk: {
350 if (node.getLabel()) |break_label| {350 if (node.getLabel()) |break_label| {
351 if (gen_zir.label) |label| {351 if (gen_zir.label) |*label| {
352 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {352 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
353 label.used = true;
353 break :blk label.block_inst;354 break :blk label.block_inst;
354 }355 }
355 }356 }
...@@ -407,8 +408,9 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE...@@ -407,8 +408,9 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE
407 continue;408 continue;
408 };409 };
409 if (node.getLabel()) |break_label| blk: {410 if (node.getLabel()) |break_label| blk: {
410 if (gen_zir.label) |label| {411 if (gen_zir.label) |*label| {
411 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {412 if (try tokenIdentEql(mod, parent_scope, label.token, break_label)) {
413 label.used = true;
412 break :blk;414 break :blk;
413 }415 }
414 }416 }
...@@ -485,6 +487,9 @@ fn labeledBlockExpr(...@@ -485,6 +487,9 @@ fn labeledBlockExpr(
485 defer block_scope.instructions.deinit(mod.gpa);487 defer block_scope.instructions.deinit(mod.gpa);
486488
487 try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements());489 try blockExprStmts(mod, &block_scope.base, &block_node.base, block_node.statements());
490 if (!block_scope.label.?.used) {
491 return mod.fail(parent_scope, tree.token_locs[block_node.label].start, "unused block label", .{});
492 }
488493
489 block_inst.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items);494 block_inst.positionals.body.instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items);
490 try gen_zir.instructions.append(mod.gpa, &block_inst.base);495 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...@@ -1398,7 +1403,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
1398 loop_scope.break_block = while_block;1403 loop_scope.break_block = while_block;
1399 loop_scope.continue_block = cond_block;1404 loop_scope.continue_block = cond_block;
1400 if (while_node.label) |some| {1405 if (while_node.label) |some| {
1401 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{1406 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
1402 .token = some,1407 .token = some,
1403 .block_inst = while_block,1408 .block_inst = while_block,
1404 });1409 });
...@@ -1465,6 +1470,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -1465,6 +1470,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
1465 condbr.positionals.else_body = .{1470 condbr.positionals.else_body = .{
1466 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),1471 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
1467 };1472 };
1473 if (loop_scope.label) |some| {
1474 if (!some.used) {
1475 return mod.fail(scope, tree.token_locs[some.token].start, "unused while label", .{});
1476 }
1477 }
1468 return &while_block.base;1478 return &while_block.base;
1469}1479}
14701480
...@@ -1555,7 +1565,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)...@@ -1555,7 +1565,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
1555 loop_scope.break_block = for_block;1565 loop_scope.break_block = for_block;
1556 loop_scope.continue_block = cond_block;1566 loop_scope.continue_block = cond_block;
1557 if (for_node.label) |some| {1567 if (for_node.label) |some| {
1558 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{1568 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
1559 .token = some,1569 .token = some,
1560 .block_inst = for_block,1570 .block_inst = for_block,
1561 });1571 });
...@@ -1646,6 +1656,11 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)...@@ -1646,6 +1656,11 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
1646 condbr.positionals.else_body = .{1656 condbr.positionals.else_body = .{
1647 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),1657 .instructions = try else_scope.arena.dupe(*zir.Inst, else_scope.instructions.items),
1648 };1658 };
1659 if (loop_scope.label) |some| {
1660 if (!some.used) {
1661 return mod.fail(scope, tree.token_locs[some.token].start, "unused for label", .{});
1662 }
1663 }
1649 return &for_block.base;1664 return &for_block.base;
1650}1665}
16511666
test/stage2/test.zig+20-1
...@@ -1207,7 +1207,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1207,7 +1207,7 @@ pub fn addCases(ctx: *TestContext) !void {
12071207
1208 {1208 {
1209 var case = ctx.exe("break/continue", linux_x64);1209 var case = ctx.exe("break/continue", linux_x64);
1210 1210
1211 // Break out of loop1211 // Break out of loop
1212 case.addCompareOutput(1212 case.addCompareOutput(
1213 \\export fn _start() noreturn {1213 \\export fn _start() noreturn {
...@@ -1296,4 +1296,23 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1296,4 +1296,23 @@ pub fn addCases(ctx: *TestContext) !void {
1296 "",1296 "",
1297 );1297 );
1298 }1298 }
1299
1300 {
1301 var case = ctx.exe("unused labels", linux_x64);
1302 case.addError(
1303 \\comptime {
1304 \\ foo: {}
1305 \\}
1306 , &[_][]const u8{":2:5: error: unused block label"});
1307 case.addError(
1308 \\comptime {
1309 \\ foo: while (true) {}
1310 \\}
1311 , &[_][]const u8{":2:5: error: unused while label"});
1312 case.addError(
1313 \\comptime {
1314 \\ foo: for ("foo") |_| {}
1315 \\}
1316 , &[_][]const u8{":2:5: error: unused for label"});
1317 }
1299}1318}