authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-14 01:04:05+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-08-14 01:04:05+03:00
logf5b99abc93b44239e95378d9958e72999abb6b44
treed18a9199d13c761b986d885dc7e4105559c13541
parent50139aa23245c7b6b6a5faff95f1a2c854051a38
parent13e472aa2a8113df6417c09727297a6106127f8e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6045 from Vexu/block

Add error for unused/duplicate labels.

11 files changed, 264 insertions(+), 102 deletions(-)

lib/std/dwarf.zig+1-1
......@@ -322,7 +322,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: anytype, form_id: u64, e
322322 FORM_block1 => parseFormValueBlock(allocator, in_stream, endian, 1),
323323 FORM_block2 => parseFormValueBlock(allocator, in_stream, endian, 2),
324324 FORM_block4 => parseFormValueBlock(allocator, in_stream, endian, 4),
325 FORM_block => x: {
325 FORM_block => {
326326 const block_len = try nosuspend leb.readULEB128(usize, in_stream);
327327 return parseFormValueBlockLen(allocator, in_stream, block_len);
328328 },
lib/std/hash/auto_hash.zig+1-1
......@@ -129,7 +129,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
129129 }
130130 },
131131
132 .Union => |info| blk: {
132 .Union => |info| {
133133 if (info.tag_type) |tag_type| {
134134 const tag = meta.activeTag(key);
135135 const s = hash(hasher, tag, strat);
lib/std/special/c.zig+3-3
......@@ -536,7 +536,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
536536 // normalize x and y
537537 if (ex == 0) {
538538 i = ux << exp_bits;
539 while (i >> bits_minus_1 == 0) : (b: {
539 while (i >> bits_minus_1 == 0) : ({
540540 ex -= 1;
541541 i <<= 1;
542542 }) {}
......@@ -547,7 +547,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
547547 }
548548 if (ey == 0) {
549549 i = uy << exp_bits;
550 while (i >> bits_minus_1 == 0) : (b: {
550 while (i >> bits_minus_1 == 0) : ({
551551 ey -= 1;
552552 i <<= 1;
553553 }) {}
......@@ -573,7 +573,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) T {
573573 return 0 * x;
574574 ux = i;
575575 }
576 while (ux >> digits == 0) : (b: {
576 while (ux >> digits == 0) : ({
577577 ux <<= 1;
578578 ex -= 1;
579579 }) {}
lib/std/zig/render.zig+1-1
......@@ -2385,7 +2385,7 @@ fn renderTokenOffset(
23852385 }
23862386 }
23872387
2388 if (next_token_id != .LineComment) blk: {
2388 if (next_token_id != .LineComment) {
23892389 switch (space) {
23902390 Space.None, Space.NoNewline => return,
23912391 Space.Newline => {
src-self-hosted/Module.zig+2-2
......@@ -2811,7 +2811,7 @@ pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
28112811 val_payload.* = .{ .val = lhs_val + rhs_val };
28122812 break :blk &val_payload.base;
28132813 },
2814 128 => blk: {
2814 128 => {
28152815 return self.fail(scope, src, "TODO Implement addition for big floats", .{});
28162816 },
28172817 else => unreachable,
......@@ -2845,7 +2845,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
28452845 val_payload.* = .{ .val = lhs_val - rhs_val };
28462846 break :blk &val_payload.base;
28472847 },
2848 128 => blk: {
2848 128 => {
28492849 return self.fail(scope, src, "TODO Implement substraction for big floats", .{});
28502850 },
28512851 else => unreachable,
src-self-hosted/translate_c.zig+114-62
......@@ -61,7 +61,8 @@ const Scope = struct {
6161 pending_block: Block,
6262 cases: []*ast.Node,
6363 case_index: usize,
64 has_default: bool = false,
64 switch_label: ?[]const u8,
65 default_label: ?[]const u8,
6566 };
6667
6768 /// Used for the scope of condition expressions, for example `if (cond)`.
......@@ -73,7 +74,7 @@ const Scope = struct {
7374
7475 fn getBlockScope(self: *Condition, c: *Context) !*Block {
7576 if (self.block) |*b| return b;
76 self.block = try Block.init(c, &self.base, "blk");
77 self.block = try Block.init(c, &self.base, true);
7778 return &self.block.?;
7879 }
7980
......@@ -93,21 +94,22 @@ const Scope = struct {
9394 mangle_count: u32 = 0,
9495 lbrace: ast.TokenIndex,
9596
96 fn init(c: *Context, parent: *Scope, label: ?[]const u8) !Block {
97 return Block{
97 fn init(c: *Context, parent: *Scope, labeled: bool) !Block {
98 var blk = Block{
9899 .base = .{
99100 .id = .Block,
100101 .parent = parent,
101102 },
102103 .statements = std.ArrayList(*ast.Node).init(c.gpa),
103104 .variables = AliasList.init(c.gpa),
104 .label = if (label) |l| blk: {
105 const ll = try appendIdentifier(c, l);
106 _ = try appendToken(c, .Colon, ":");
107 break :blk ll;
108 } else null,
105 .label = null,
109106 .lbrace = try appendToken(c, .LBrace, "{"),
110107 };
108 if (labeled) {
109 blk.label = try appendIdentifier(c, try blk.makeMangledName(c, "blk"));
110 _ = try appendToken(c, .Colon, ":");
111 }
112 return blk;
111113 }
112114
113115 fn deinit(self: *Block) void {
......@@ -577,7 +579,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
577579
578580 // actual function definition with body
579581 const body_stmt = ZigClangFunctionDecl_getBody(fn_decl);
580 var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, null);
582 var block_scope = try Scope.Block.init(rp.c, &c.global_scope.base, false);
581583 defer block_scope.deinit();
582584 var scope = &block_scope.base;
583585
......@@ -626,6 +628,46 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
626628 error.UnsupportedType,
627629 => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
628630 };
631 // add return statement if the function didn't have one
632 blk: {
633 const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_type);
634
635 if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) break :blk;
636 const return_qt = ZigClangFunctionType_getReturnType(fn_ty);
637 if (isCVoid(return_qt)) break :blk;
638
639 if (block_scope.statements.items.len > 0) {
640 var last = block_scope.statements.items[block_scope.statements.items.len - 1];
641 while (true) {
642 switch (last.tag) {
643 .Block => {
644 const stmts = last.castTag(.Block).?.statements();
645 if (stmts.len == 0) break;
646
647 last = stmts[stmts.len - 1];
648 },
649 // no extra return needed
650 .Return => break :blk,
651 else => break,
652 }
653 }
654 }
655
656 const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
657 .ltoken = try appendToken(rp.c, .Keyword_return, "return"),
658 .tag = .Return,
659 }, .{
660 .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, ZigClangQualType_getTypePtr(return_qt)) catch |err| switch (err) {
661 error.OutOfMemory => |e| return e,
662 error.UnsupportedTranslation,
663 error.UnsupportedType,
664 => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
665 },
666 });
667 _ = try appendToken(rp.c, .Semicolon, ";");
668 try block_scope.statements.append(&return_expr.base);
669 }
670
629671 const body_node = try block_scope.complete(rp.c);
630672 proto_node.setTrailer("body_node", &body_node.base);
631673 return addTopLevelDecl(c, fn_name, &proto_node.base);
......@@ -931,7 +973,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
931973 else => |e| return e,
932974 };
933975
934 const align_expr = blk: {
976 const align_expr = blk_2: {
935977 const alignment = ZigClangFieldDecl_getAlignedAttribute(field_decl, rp.c.clang_context);
936978 if (alignment != 0) {
937979 _ = try appendToken(rp.c, .Keyword_align, "align");
......@@ -940,9 +982,9 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*
940982 const expr = try transCreateNodeInt(rp.c, alignment / 8);
941983 _ = try appendToken(rp.c, .RParen, ")");
942984
943 break :blk expr;
985 break :blk_2 expr;
944986 }
945 break :blk null;
987 break :blk_2 null;
946988 };
947989
948990 const field_node = try c.arena.create(ast.Node.ContainerField);
......@@ -1073,9 +1115,9 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No
10731115
10741116 const field_name_tok = try appendIdentifier(c, field_name);
10751117
1076 const int_node = if (!pure_enum) blk: {
1118 const int_node = if (!pure_enum) blk_2: {
10771119 _ = try appendToken(c, .Colon, "=");
1078 break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
1120 break :blk_2 try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const));
10791121 } else
10801122 null;
10811123
......@@ -1307,7 +1349,7 @@ fn transBinaryOperator(
13071349 const rhs = try transExpr(rp, &block_scope.base, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
13081350 if (expr) {
13091351 _ = try appendToken(rp.c, .Semicolon, ";");
1310 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, rhs);
1352 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, rhs);
13111353 try block_scope.statements.append(&break_node.base);
13121354 const block_node = try block_scope.complete(rp.c);
13131355 const rparen = try appendToken(rp.c, .RParen, ")");
......@@ -1476,7 +1518,7 @@ fn transCompoundStmtInline(
14761518}
14771519
14781520fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangCompoundStmt) TransError!*ast.Node {
1479 var block_scope = try Scope.Block.init(rp.c, scope, null);
1521 var block_scope = try Scope.Block.init(rp.c, scope, false);
14801522 defer block_scope.deinit();
14811523 try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope);
14821524 const node = try block_scope.complete(rp.c);
......@@ -2388,7 +2430,7 @@ fn transZeroInitExpr(
23882430 ty: *const ZigClangType,
23892431) TransError!*ast.Node {
23902432 switch (ZigClangType_getTypeClass(ty)) {
2391 .Builtin => blk: {
2433 .Builtin => {
23922434 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
23932435 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
23942436 .Bool => return try transCreateNodeBoolLiteral(rp.c, false),
......@@ -2587,7 +2629,7 @@ fn transForLoop(
25872629 defer if (block_scope) |*bs| bs.deinit();
25882630
25892631 if (ZigClangForStmt_getInit(stmt)) |init| {
2590 block_scope = try Scope.Block.init(rp.c, scope, null);
2632 block_scope = try Scope.Block.init(rp.c, scope, false);
25912633 loop_scope.parent = &block_scope.?.base;
25922634 const init_node = try transStmt(rp, &block_scope.?.base, init, .unused, .r_value);
25932635 try block_scope.?.statements.append(init_node);
......@@ -2673,17 +2715,19 @@ fn transSwitch(
26732715 .cases = switch_node.cases(),
26742716 .case_index = 0,
26752717 .pending_block = undefined,
2718 .default_label = null,
2719 .switch_label = null,
26762720 };
26772721
26782722 // tmp block that all statements will go before being picked up by a case or default
2679 var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, null);
2723 var block_scope = try Scope.Block.init(rp.c, &switch_scope.base, false);
26802724 defer block_scope.deinit();
26812725
26822726 // Note that we do not defer a deinit here; the switch_scope.pending_block field
26832727 // has its own memory management. This resource is freed inside `transCase` and
26842728 // then the final pending_block is freed at the bottom of this function with
26852729 // pending_block.deinit().
2686 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null);
2730 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
26872731 try switch_scope.pending_block.statements.append(&switch_node.base);
26882732
26892733 const last = try transStmt(rp, &block_scope.base, ZigClangSwitchStmt_getBody(stmt), .unused, .r_value);
......@@ -2698,11 +2742,19 @@ fn transSwitch(
26982742 switch_scope.pending_block.statements.appendAssumeCapacity(n);
26992743 }
27002744
2701 switch_scope.pending_block.label = try appendIdentifier(rp.c, "__switch");
2702 _ = try appendToken(rp.c, .Colon, ":");
2703 if (!switch_scope.has_default) {
2745 if (switch_scope.default_label == null) {
2746 switch_scope.switch_label = try block_scope.makeMangledName(rp.c, "switch");
2747 }
2748 if (switch_scope.switch_label) |l| {
2749 switch_scope.pending_block.label = try appendIdentifier(rp.c, l);
2750 _ = try appendToken(rp.c, .Colon, ":");
2751 }
2752 if (switch_scope.default_label == null) {
27042753 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2705 else_prong.expr = &(try transCreateNodeBreak(rp.c, "__switch", null)).base;
2754 else_prong.expr = blk: {
2755 var br = try CtrlFlow.init(rp.c, .Break, switch_scope.switch_label.?);
2756 break :blk &(try br.finish(null)).base;
2757 };
27062758 _ = try appendToken(rp.c, .Comma, ",");
27072759
27082760 if (switch_scope.case_index >= switch_scope.cases.len)
......@@ -2726,7 +2778,7 @@ fn transCase(
27262778) TransError!*ast.Node {
27272779 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
27282780 const switch_scope = scope.getSwitch();
2729 const label = try std.fmt.allocPrint(rp.c.arena, "__case_{}", .{switch_scope.case_index - @boolToInt(switch_scope.has_default)});
2781 const label = try block_scope.makeMangledName(rp.c, "case");
27302782 _ = try appendToken(rp.c, .Semicolon, ";");
27312783
27322784 const expr = if (ZigClangCaseStmt_getRHS(stmt)) |rhs| blk: {
......@@ -2746,7 +2798,10 @@ fn transCase(
27462798 try transExpr(rp, scope, ZigClangCaseStmt_getLHS(stmt), .used, .r_value);
27472799
27482800 const switch_prong = try transCreateNodeSwitchCase(rp.c, expr);
2749 switch_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base;
2801 switch_prong.expr = blk: {
2802 var br = try CtrlFlow.init(rp.c, .Break, label);
2803 break :blk &(try br.finish(null)).base;
2804 };
27502805 _ = try appendToken(rp.c, .Comma, ",");
27512806
27522807 if (switch_scope.case_index >= switch_scope.cases.len)
......@@ -2763,7 +2818,7 @@ fn transCase(
27632818
27642819 const pending_node = try switch_scope.pending_block.complete(rp.c);
27652820 switch_scope.pending_block.deinit();
2766 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null);
2821 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
27672822
27682823 try switch_scope.pending_block.statements.append(&pending_node.base);
27692824
......@@ -2777,12 +2832,14 @@ fn transDefault(
27772832) TransError!*ast.Node {
27782833 const block_scope = scope.findBlockScope(rp.c) catch unreachable;
27792834 const switch_scope = scope.getSwitch();
2780 const label = "__default";
2781 switch_scope.has_default = true;
2835 switch_scope.default_label = try block_scope.makeMangledName(rp.c, "default");
27822836 _ = try appendToken(rp.c, .Semicolon, ";");
27832837
27842838 const else_prong = try transCreateNodeSwitchCase(rp.c, try transCreateNodeSwitchElse(rp.c));
2785 else_prong.expr = &(try transCreateNodeBreak(rp.c, label, null)).base;
2839 else_prong.expr = blk: {
2840 var br = try CtrlFlow.init(rp.c, .Break, switch_scope.default_label.?);
2841 break :blk &(try br.finish(null)).base;
2842 };
27862843 _ = try appendToken(rp.c, .Comma, ",");
27872844
27882845 if (switch_scope.case_index >= switch_scope.cases.len)
......@@ -2790,7 +2847,7 @@ fn transDefault(
27902847 switch_scope.cases[switch_scope.case_index] = &else_prong.base;
27912848 switch_scope.case_index += 1;
27922849
2793 switch_scope.pending_block.label = try appendIdentifier(rp.c, label);
2850 switch_scope.pending_block.label = try appendIdentifier(rp.c, switch_scope.default_label.?);
27942851 _ = try appendToken(rp.c, .Colon, ":");
27952852
27962853 // take all pending statements
......@@ -2799,7 +2856,7 @@ fn transDefault(
27992856
28002857 const pending_node = try switch_scope.pending_block.complete(rp.c);
28012858 switch_scope.pending_block.deinit();
2802 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, null);
2859 switch_scope.pending_block = try Scope.Block.init(rp.c, scope, false);
28032860 try switch_scope.pending_block.statements.append(&pending_node.base);
28042861
28052862 return transStmt(rp, scope, ZigClangDefaultStmt_getSubStmt(stmt), .unused, .r_value);
......@@ -2894,7 +2951,7 @@ fn transStmtExpr(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangStmtExpr,
28942951 return transCompoundStmt(rp, scope, comp);
28952952 }
28962953 const lparen = try appendToken(rp.c, .LParen, "(");
2897 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
2954 var block_scope = try Scope.Block.init(rp.c, scope, true);
28982955 defer block_scope.deinit();
28992956
29002957 var it = ZigClangCompoundStmt_body_begin(comp);
......@@ -3209,7 +3266,7 @@ fn transCreatePreCrement(
32093266 // zig: _ref.* += 1;
32103267 // zig: break :blk _ref.*
32113268 // zig: })
3212 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3269 var block_scope = try Scope.Block.init(rp.c, scope, true);
32133270 defer block_scope.deinit();
32143271 const ref = try block_scope.makeMangledName(rp.c, "ref");
32153272
......@@ -3239,7 +3296,7 @@ fn transCreatePreCrement(
32393296 const assign = try transCreateNodeInfixOp(rp, scope, ref_node, op, token, one, .used, false);
32403297 try block_scope.statements.append(assign);
32413298
3242 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node);
3299 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);
32433300 try block_scope.statements.append(&break_node.base);
32443301 const block_node = try block_scope.complete(rp.c);
32453302 // semicolon must immediately follow rbrace because it is the last token in a block
......@@ -3283,7 +3340,7 @@ fn transCreatePostCrement(
32833340 // zig: _ref.* += 1;
32843341 // zig: break :blk _tmp
32853342 // zig: })
3286 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3343 var block_scope = try Scope.Block.init(rp.c, scope, true);
32873344 defer block_scope.deinit();
32883345 const ref = try block_scope.makeMangledName(rp.c, "ref");
32893346
......@@ -3458,7 +3515,7 @@ fn transCreateCompoundAssign(
34583515 // zig: _ref.* = _ref.* + rhs;
34593516 // zig: break :blk _ref.*
34603517 // zig: })
3461 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3518 var block_scope = try Scope.Block.init(rp.c, scope, true);
34623519 defer block_scope.deinit();
34633520 const ref = try block_scope.makeMangledName(rp.c, "ref");
34643521
......@@ -3526,7 +3583,7 @@ fn transCreateCompoundAssign(
35263583 try block_scope.statements.append(assign);
35273584 }
35283585
3529 const break_node = try transCreateNodeBreakToken(rp.c, block_scope.label, ref_node);
3586 const break_node = try transCreateNodeBreak(rp.c, block_scope.label, ref_node);
35303587 try block_scope.statements.append(&break_node.base);
35313588 const block_node = try block_scope.complete(rp.c);
35323589 const grouped_expr = try rp.c.arena.create(ast.Node.GroupedExpression);
......@@ -3602,8 +3659,16 @@ fn transCPtrCast(
36023659
36033660fn transBreak(rp: RestorePoint, scope: *Scope) TransError!*ast.Node {
36043661 const break_scope = scope.getBreakableScope();
3605 const label_text: ?[]const u8 = if (break_scope.id == .Switch) "__switch" else null;
3606 const br = try transCreateNodeBreak(rp.c, label_text, null);
3662 const label_text: ?[]const u8 = if (break_scope.id == .Switch) blk: {
3663 const swtch = @fieldParentPtr(Scope.Switch, "base", break_scope);
3664 const block_scope = try scope.findBlockScope(rp.c);
3665 swtch.switch_label = try block_scope.makeMangledName(rp.c, "switch");
3666 break :blk swtch.switch_label;
3667 } else
3668 null;
3669
3670 var cf = try CtrlFlow.init(rp.c, .Break, label_text);
3671 const br = try cf.finish(null);
36073672 _ = try appendToken(rp.c, .Semicolon, ";");
36083673 return &br.base;
36093674}
......@@ -3634,7 +3699,7 @@ fn transBinaryConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const
36343699 // })
36353700 const lparen = try appendToken(rp.c, .LParen, "(");
36363701
3637 var block_scope = try Scope.Block.init(rp.c, scope, "blk");
3702 var block_scope = try Scope.Block.init(rp.c, scope, true);
36383703 defer block_scope.deinit();
36393704
36403705 const mangled_name = try block_scope.makeMangledName(rp.c, "cond_temp");
......@@ -4082,8 +4147,7 @@ fn transCreateNodeAssign(
40824147 // zig: lhs = _tmp;
40834148 // zig: break :blk _tmp
40844149 // zig: })
4085 const label_name = "blk";
4086 var block_scope = try Scope.Block.init(rp.c, scope, label_name);
4150 var block_scope = try Scope.Block.init(rp.c, scope, true);
40874151 defer block_scope.deinit();
40884152
40894153 const tmp = try block_scope.makeMangledName(rp.c, "tmp");
......@@ -4118,7 +4182,7 @@ fn transCreateNodeAssign(
41184182 try block_scope.statements.append(assign);
41194183
41204184 const break_node = blk: {
4121 var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, label_name);
4185 var tmp_ctrl_flow = try CtrlFlow.init(rp.c, .Break, tokenSlice(rp.c, block_scope.label.?));
41224186 const rhs_expr = try transCreateNodeIdentifier(rp.c, tmp);
41234187 break :blk try tmp_ctrl_flow.finish(rhs_expr);
41244188 };
......@@ -4495,23 +4559,12 @@ fn transCreateNodeElse(c: *Context) !*ast.Node.Else {
44954559 return node;
44964560}
44974561
4498fn transCreateNodeBreakToken(
4499 c: *Context,
4500 label: ?ast.TokenIndex,
4501 rhs: ?*ast.Node,
4502) !*ast.Node.ControlFlowExpression {
4503 const other_token = label orelse return transCreateNodeBreak(c, null, rhs);
4504 const loc = c.token_locs.items[other_token];
4505 const label_name = c.source_buffer.items[loc.start..loc.end];
4506 return transCreateNodeBreak(c, label_name, rhs);
4507}
4508
45094562fn transCreateNodeBreak(
45104563 c: *Context,
4511 label: ?[]const u8,
4564 label: ?ast.TokenIndex,
45124565 rhs: ?*ast.Node,
45134566) !*ast.Node.ControlFlowExpression {
4514 var ctrl_flow = try CtrlFlow.init(c, .Break, label);
4567 var ctrl_flow = try CtrlFlow.init(c, .Break, if (label) |l| tokenSlice(c, l) else null);
45154568 return ctrl_flow.finish(rhs);
45164569}
45174570
......@@ -5362,7 +5415,7 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
53625415}
53635416
53645417fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5365 var block_scope = try Scope.Block.init(c, &c.global_scope.base, null);
5418 var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
53665419 defer block_scope.deinit();
53675420 const scope = &block_scope.base;
53685421
......@@ -5475,8 +5528,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
54755528 },
54765529 .Comma => {
54775530 _ = try appendToken(c, .Semicolon, ";");
5478 const label_name = "blk";
5479 var block_scope = try Scope.Block.init(c, scope, label_name);
5531 var block_scope = try Scope.Block.init(c, scope, true);
54805532 defer block_scope.deinit();
54815533
54825534 var last = node;
......@@ -5501,7 +5553,7 @@ fn parseCExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!*ast.Node {
55015553 }
55025554 }
55035555
5504 const break_node = try transCreateNodeBreak(c, label_name, last);
5556 const break_node = try transCreateNodeBreak(c, block_scope.label, last);
55055557 try block_scope.statements.append(&break_node.base);
55065558 const block_node = try block_scope.complete(c);
55075559 return &block_node.base;
src/all_types.hpp+3
......@@ -2438,6 +2438,7 @@ struct ScopeBlock {
24382438 LVal lval;
24392439 bool safety_off;
24402440 bool fast_math_on;
2441 bool name_used;
24412442};
24422443
24432444// This scope is created from every defer expression.
......@@ -2488,6 +2489,8 @@ struct ScopeLoop {
24882489 ZigList<IrBasicBlockSrc *> *incoming_blocks;
24892490 ResultLocPeerParent *peer_parent;
24902491 ScopeExpr *spill_scope;
2492
2493 bool name_used;
24912494};
24922495
24932496// This scope blocks certain things from working such as comptime continue
src/ir.cpp+60
......@@ -5476,6 +5476,25 @@ static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
54765476 return result;
54775477}
54785478
5479static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *name) {
5480 if (name == nullptr) return false;
5481
5482 for (;;) {
5483 if (scope == nullptr || scope->id == ScopeIdFnDef) {
5484 break;
5485 } else if (scope->id == ScopeIdBlock || scope->id == ScopeIdLoop) {
5486 Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name;
5487 if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) {
5488 ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name)));
5489 add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration is here"));
5490 return true;
5491 }
5492 }
5493 scope = scope->parent;
5494 }
5495 return false;
5496}
5497
54795498static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *block_node, LVal lval,
54805499 ResultLoc *result_loc)
54815500{
......@@ -5484,6 +5503,9 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
54845503 ZigList<IrInstSrc *> incoming_values = {0};
54855504 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
54865505
5506 if (is_duplicate_label(irb->codegen, parent_scope, block_node, block_node->data.block.name))
5507 return irb->codegen->invalid_inst_src;
5508
54875509 ScopeBlock *scope_block = create_block_scope(irb->codegen, block_node, parent_scope);
54885510
54895511 Scope *outer_block_scope = &scope_block->base;
......@@ -5495,6 +5517,9 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
54955517 }
54965518
54975519 if (block_node->data.block.statements.length == 0) {
5520 if (scope_block->name != nullptr) {
5521 add_node_error(irb->codegen, block_node, buf_sprintf("unused block label"));
5522 }
54985523 // {}
54995524 return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc);
55005525 }
......@@ -5552,6 +5577,10 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *
55525577 }
55535578 }
55545579
5580 if (scope_block->name != nullptr && scope_block->name_used == false) {
5581 add_node_error(irb->codegen, block_node, buf_sprintf("unused block label"));
5582 }
5583
55555584 if (found_invalid_inst)
55565585 return irb->codegen->invalid_inst_src;
55575586
......@@ -8152,6 +8181,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81528181 ZigList<IrInstSrc *> incoming_values = {0};
81538182 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
81548183
8184 if (is_duplicate_label(irb->codegen, payload_scope, node, node->data.while_expr.name))
8185 return irb->codegen->invalid_inst_src;
8186
81558187 ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, payload_scope);
81568188 loop_scope->break_block = end_block;
81578189 loop_scope->continue_block = continue_block;
......@@ -8169,6 +8201,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
81698201 if (body_result == irb->codegen->invalid_inst_src)
81708202 return body_result;
81718203
8204 if (loop_scope->name != nullptr && loop_scope->name_used == false) {
8205 add_node_error(irb->codegen, node, buf_sprintf("unused while label"));
8206 }
8207
81728208 if (!instr_is_unreachable(body_result)) {
81738209 ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result));
81748210 ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime));
......@@ -8263,6 +8299,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82638299 ZigList<IrInstSrc *> incoming_values = {0};
82648300 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
82658301
8302 if (is_duplicate_label(irb->codegen, child_scope, node, node->data.while_expr.name))
8303 return irb->codegen->invalid_inst_src;
8304
82668305 ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope);
82678306 loop_scope->break_block = end_block;
82688307 loop_scope->continue_block = continue_block;
......@@ -8280,6 +8319,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
82808319 if (body_result == irb->codegen->invalid_inst_src)
82818320 return body_result;
82828321
8322 if (loop_scope->name != nullptr && loop_scope->name_used == false) {
8323 add_node_error(irb->codegen, node, buf_sprintf("unused while label"));
8324 }
8325
82838326 if (!instr_is_unreachable(body_result)) {
82848327 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result));
82858328 ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
......@@ -8353,6 +8396,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
83538396
83548397 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime);
83558398
8399 if (is_duplicate_label(irb->codegen, subexpr_scope, node, node->data.while_expr.name))
8400 return irb->codegen->invalid_inst_src;
8401
83568402 ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, subexpr_scope);
83578403 loop_scope->break_block = end_block;
83588404 loop_scope->continue_block = continue_block;
......@@ -8369,6 +8415,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no
83698415 if (body_result == irb->codegen->invalid_inst_src)
83708416 return body_result;
83718417
8418 if (loop_scope->name != nullptr && loop_scope->name_used == false) {
8419 add_node_error(irb->codegen, node, buf_sprintf("unused while label"));
8420 }
8421
83728422 if (!instr_is_unreachable(body_result)) {
83738423 ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result));
83748424 ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
......@@ -8501,6 +8551,9 @@ static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNod
85018551 elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr);
85028552 build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime);
85038553
8554 if (is_duplicate_label(irb->codegen, child_scope, node, node->data.for_expr.name))
8555 return irb->codegen->invalid_inst_src;
8556
85048557 ZigList<IrInstSrc *> incoming_values = {0};
85058558 ZigList<IrBasicBlockSrc *> incoming_blocks = {0};
85068559 ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope);
......@@ -8520,6 +8573,10 @@ static IrInstSrc *ir_gen_for_expr(IrBuilderSrc *irb, Scope *parent_scope, AstNod
85208573 if (body_result == irb->codegen->invalid_inst_src)
85218574 return irb->codegen->invalid_inst_src;
85228575
8576 if (loop_scope->name != nullptr && loop_scope->name_used == false) {
8577 add_node_error(irb->codegen, node, buf_sprintf("unused for label"));
8578 }
8579
85238580 if (!instr_is_unreachable(body_result)) {
85248581 ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.for_expr.body, body_result));
85258582 ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
......@@ -9464,6 +9521,7 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n
94649521 if (node->data.break_expr.name == nullptr ||
94659522 (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name)))
94669523 {
9524 this_loop_scope->name_used = true;
94679525 loop_scope = this_loop_scope;
94689526 break;
94699527 }
......@@ -9473,6 +9531,7 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n
94739531 (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name)))
94749532 {
94759533 assert(this_block_scope->end_block != nullptr);
9534 this_block_scope->name_used = true;
94769535 return ir_gen_return_from_block(irb, break_scope, node, this_block_scope);
94779536 }
94789537 } else if (search_scope->id == ScopeIdSuspend) {
......@@ -9540,6 +9599,7 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN
95409599 if (node->data.continue_expr.name == nullptr ||
95419600 (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name)))
95429601 {
9602 this_loop_scope->name_used = true;
95439603 loop_scope = this_loop_scope;
95449604 break;
95459605 }
test/compile_errors.zig+23
......@@ -2,6 +2,29 @@ const tests = @import("tests.zig");
22const std = @import("std");
33
44pub fn addCases(cases: *tests.CompileErrorContext) void {
5 cases.addTest("duplicate/unused labels",
6 \\comptime {
7 \\ blk: { blk: while (false) {} }
8 \\ blk: while (false) { blk: for (@as([0]void, undefined)) |_| {} }
9 \\ blk: for (@as([0]void, undefined)) |_| { blk: {} }
10 \\}
11 \\comptime {
12 \\ blk: {}
13 \\ blk: while(false) {}
14 \\ blk: for(@as([0]void, undefined)) |_| {}
15 \\}
16 , &[_][]const u8{
17 "tmp.zig:2:17: error: redeclaration of label 'blk'",
18 "tmp.zig:2:10: note: previous declaration is here",
19 "tmp.zig:3:31: error: redeclaration of label 'blk'",
20 "tmp.zig:3:10: note: previous declaration is here",
21 "tmp.zig:4:51: error: redeclaration of label 'blk'",
22 "tmp.zig:4:10: note: previous declaration is here",
23 "tmp.zig:7:10: error: unused block label",
24 "tmp.zig:8:10: error: unused while label",
25 "tmp.zig:9:10: error: unused for label",
26 });
27
528 cases.addTest("@alignCast of zero sized types",
629 \\export fn foo() void {
730 \\ const a: *void = undefined;
test/run_translated_c.zig-1
......@@ -15,7 +15,6 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1515 \\ }
1616 \\ if (s0 != 1) abort();
1717 \\ if (s1 != 10) abort();
18 \\ return 0;
1918 \\}
2019 , "");
2120
test/translate_c.zig+56-31
......@@ -3,12 +3,33 @@ const std = @import("std");
33const CrossTarget = std.zig.CrossTarget;
44
55pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("missing return stmt",
7 \\int foo() {}
8 \\int bar() {
9 \\ int a = 2;
10 \\}
11 \\int baz() {
12 \\ return 0;
13 \\}
14 , &[_][]const u8{
15 \\pub export fn foo() c_int {
16 \\ return 0;
17 \\}
18 \\pub export fn bar() c_int {
19 \\ var a: c_int = 2;
20 \\ return 0;
21 \\}
22 \\pub export fn baz() c_int {
23 \\ return 0;
24 \\}
25 });
26
627 cases.add("alignof",
7 \\int main() {
28 \\void main() {
829 \\ int a = _Alignof(int);
930 \\}
1031 , &[_][]const u8{
11 \\pub export fn main() c_int {
32 \\pub export fn main() void {
1233 \\ var a: c_int = @bitCast(c_int, @truncate(c_uint, @alignOf(c_int)));
1334 \\}
1435 });
......@@ -539,6 +560,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
539560 \\ c = (a * b);
540561 \\ c = @divTrunc(a, b);
541562 \\ c = @rem(a, b);
563 \\ return 0;
542564 \\}
543565 \\pub export fn u() c_uint {
544566 \\ var a: c_uint = undefined;
......@@ -549,6 +571,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
549571 \\ c = (a *% b);
550572 \\ c = (a / b);
551573 \\ c = (a % b);
574 \\ return 0;
552575 \\}
553576 });
554577
......@@ -1596,13 +1619,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
15961619 });
15971620
15981621 cases.add("worst-case assign",
1599 \\int foo() {
1622 \\void foo() {
16001623 \\ int a;
16011624 \\ int b;
16021625 \\ a = b = 2;
16031626 \\}
16041627 , &[_][]const u8{
1605 \\pub export fn foo() c_int {
1628 \\pub export fn foo() void {
16061629 \\ var a: c_int = undefined;
16071630 \\ var b: c_int = undefined;
16081631 \\ a = blk: {
......@@ -1650,11 +1673,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16501673 \\ a = 7;
16511674 \\ if (!true) break;
16521675 \\ }
1676 \\ return 0;
16531677 \\}
16541678 });
16551679
16561680 cases.add("for loops",
1657 \\int foo() {
1681 \\void foo() {
16581682 \\ for (int i = 2, b = 4; i + 2; i = 2) {
16591683 \\ int a = 2;
16601684 \\ a = 6, 5, 7;
......@@ -1662,7 +1686,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16621686 \\ char i = 2;
16631687 \\}
16641688 , &[_][]const u8{
1665 \\pub export fn foo() c_int {
1689 \\pub export fn foo() void {
16661690 \\ {
16671691 \\ var i: c_int = 2;
16681692 \\ var b: c_int = 4;
......@@ -1712,7 +1736,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17121736 });
17131737
17141738 cases.add("switch on int",
1715 \\int switch_fn(int i) {
1739 \\void switch_fn(int i) {
17161740 \\ int res = 0;
17171741 \\ switch (i) {
17181742 \\ case 0:
......@@ -1727,19 +1751,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17271751 \\ }
17281752 \\}
17291753 , &[_][]const u8{
1730 \\pub export fn switch_fn(arg_i: c_int) c_int {
1754 \\pub export fn switch_fn(arg_i: c_int) void {
17311755 \\ var i = arg_i;
17321756 \\ var res: c_int = 0;
1733 \\ __switch: {
1734 \\ __case_2: {
1735 \\ __default: {
1736 \\ __case_1: {
1737 \\ __case_0: {
1757 \\ @"switch": {
1758 \\ case_2: {
1759 \\ default: {
1760 \\ case_1: {
1761 \\ case: {
17381762 \\ switch (i) {
1739 \\ @as(c_int, 0) => break :__case_0,
1740 \\ @as(c_int, 1)...@as(c_int, 3) => break :__case_1,
1741 \\ else => break :__default,
1742 \\ @as(c_int, 4) => break :__case_2,
1763 \\ @as(c_int, 0) => break :case,
1764 \\ @as(c_int, 1)...@as(c_int, 3) => break :case_1,
1765 \\ else => break :default,
1766 \\ @as(c_int, 4) => break :case_2,
17431767 \\ }
17441768 \\ }
17451769 \\ res = 1;
......@@ -1747,7 +1771,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17471771 \\ res = 2;
17481772 \\ }
17491773 \\ res = (@as(c_int, 3) * i);
1750 \\ break :__switch;
1774 \\ break :@"switch";
17511775 \\ }
17521776 \\ res = 5;
17531777 \\ }
......@@ -1787,13 +1811,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
17871811 });
17881812
17891813 cases.add("assign",
1790 \\int max(int a) {
1814 \\void max(int a) {
17911815 \\ int tmp;
17921816 \\ tmp = a;
17931817 \\ a = tmp;
17941818 \\}
17951819 , &[_][]const u8{
1796 \\pub export fn max(arg_a: c_int) c_int {
1820 \\pub export fn max(arg_a: c_int) void {
17971821 \\ var a = arg_a;
17981822 \\ var tmp: c_int = undefined;
17991823 \\ tmp = a;
......@@ -2082,7 +2106,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
20822106 \\ int b;
20832107 \\}a;
20842108 \\float b = 2.0f;
2085 \\int foo(void) {
2109 \\void foo(void) {
20862110 \\ struct Foo *c;
20872111 \\ a.b;
20882112 \\ c->b;
......@@ -2093,7 +2117,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
20932117 \\};
20942118 \\pub extern var a: struct_Foo;
20952119 \\pub export var b: f32 = 2;
2096 \\pub export fn foo() c_int {
2120 \\pub export fn foo() void {
20972121 \\ var c: [*c]struct_Foo = undefined;
20982122 \\ _ = a.b;
20992123 \\ _ = c.*.b;
......@@ -2204,11 +2228,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22042228 \\ if (a < b) return b;
22052229 \\ if (a < b) return b else return a;
22062230 \\ if (a < b) {} else {}
2231 \\ return 0;
22072232 \\}
22082233 });
22092234
22102235 cases.add("if statements",
2211 \\int foo() {
2236 \\void foo() {
22122237 \\ if (2) {
22132238 \\ int a = 2;
22142239 \\ }
......@@ -2217,7 +2242,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
22172242 \\ }
22182243 \\}
22192244 , &[_][]const u8{
2220 \\pub export fn foo() c_int {
2245 \\pub export fn foo() void {
22212246 \\ if (true) {
22222247 \\ var a: c_int = 2;
22232248 \\ }
......@@ -2782,11 +2807,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
27822807 \\ var x = arg_x;
27832808 \\ return blk: {
27842809 \\ const tmp = x;
2785 \\ (blk: {
2810 \\ (blk_1: {
27862811 \\ const ref = &p;
2787 \\ const tmp_1 = ref.*;
2812 \\ const tmp_2 = ref.*;
27882813 \\ ref.* += 1;
2789 \\ break :blk tmp_1;
2814 \\ break :blk_1 tmp_2;
27902815 \\ }).?.* = tmp;
27912816 \\ break :blk tmp;
27922817 \\ };
......@@ -2811,12 +2836,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
28112836 });
28122837
28132838 cases.add("arg name aliasing decl which comes after",
2814 \\int foo(int bar) {
2839 \\void foo(int bar) {
28152840 \\ bar = 2;
28162841 \\}
28172842 \\int bar = 4;
28182843 , &[_][]const u8{
2819 \\pub export fn foo(arg_bar_1: c_int) c_int {
2844 \\pub export fn foo(arg_bar_1: c_int) void {
28202845 \\ var bar_1 = arg_bar_1;
28212846 \\ bar_1 = 2;
28222847 \\}
......@@ -2824,12 +2849,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
28242849 });
28252850
28262851 cases.add("arg name aliasing macro which comes after",
2827 \\int foo(int bar) {
2852 \\void foo(int bar) {
28282853 \\ bar = 2;
28292854 \\}
28302855 \\#define bar 4
28312856 , &[_][]const u8{
2832 \\pub export fn foo(arg_bar_1: c_int) c_int {
2857 \\pub export fn foo(arg_bar_1: c_int) void {
28332858 \\ var bar_1 = arg_bar_1;
28342859 \\ bar_1 = 2;
28352860 \\}