From 40aad4f47e1ab02a1ff6109f4b6f06af00d1f503 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 26 Dec 2020 02:17:36 +0200 Subject: stage2: break and continue out of loops --- src/Module.zig | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 20cb7bf195..3806c0dea8 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -796,6 +796,10 @@ pub const Scope = struct { /// The first N instructions in a function body ZIR are arg instructions. instructions: std.ArrayListUnmanaged(*zir.Inst) = .{}, label: ?Label = null, + break_block: ?*zir.Inst.Block = null, + continue_block: ?*zir.Inst.Block = null, + /// only valid if label != null or (continue_block and break_block) != null + break_result_loc: astgen.ResultLoc = undefined, pub const Label = struct { token: ast.TokenIndex, -- cgit v1.2.3 From a50759325c95ad7dfd1fbf029759cf0a2608b3ab Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Sat, 26 Dec 2020 02:36:12 +0200 Subject: stage2: add error for unused labels --- src/Module.zig | 2 +- src/astgen.zig | 23 +++++++++++++++++++---- test/stage2/test.zig | 21 ++++++++++++++++++++- 3 files changed, 40 insertions(+), 6 deletions(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 3806c0dea8..c0b7011f43 100644 --- a/src/Module.zig +++ b/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, }; }; diff --git a/src/astgen.zig b/src/astgen.zig index c4ac5b5fc9..7b6349d4a8 100644 --- a/src/astgen.zig +++ b/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; } diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 46e35186da..200b1c5166 100644 --- a/test/stage2/test.zig +++ b/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"}); + } } -- cgit v1.2.3