diff --git a/lib/std/dwarf.zig b/lib/std/dwarf.zig index c5802240d4..085e394a8f 100644 --- a/lib/std/dwarf.zig +++ b/lib/std/dwarf.zig @@ -322,7 +322,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: anytype, form_id: u64, e FORM_block1 => parseFormValueBlock(allocator, in_stream, endian, 1), FORM_block2 => parseFormValueBlock(allocator, in_stream, endian, 2), FORM_block4 => parseFormValueBlock(allocator, in_stream, endian, 4), - FORM_block => x: { + FORM_block => { const block_len = try nosuspend leb.readULEB128(usize, in_stream); return parseFormValueBlockLen(allocator, in_stream, block_len); }, diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index c769bc358b..170bb98620 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -536,7 +536,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) T { // normalize x and y if (ex == 0) { i = ux << exp_bits; - while (i >> bits_minus_1 == 0) : (b: { + while (i >> bits_minus_1 == 0) : ({ ex -= 1; i <<= 1; }) {} @@ -547,7 +547,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) T { } if (ey == 0) { i = uy << exp_bits; - while (i >> bits_minus_1 == 0) : (b: { + while (i >> bits_minus_1 == 0) : ({ ey -= 1; i <<= 1; }) {} @@ -573,7 +573,7 @@ fn generic_fmod(comptime T: type, x: T, y: T) T { return 0 * x; ux = i; } - while (ux >> digits == 0) : (b: { + while (ux >> digits == 0) : ({ ux <<= 1; ex -= 1; }) {} diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 454ddde160..c516250a17 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -2385,7 +2385,7 @@ fn renderTokenOffset( } } - if (next_token_id != .LineComment) blk: { + if (next_token_id != .LineComment) { switch (space) { Space.None, Space.NoNewline => return, Space.Newline => { diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 5af9bbc3c4..8b1c6537f7 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -931,7 +931,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* else => |e| return e, }; - const align_expr = blk: { + const align_expr = blk_2: { const alignment = ZigClangFieldDecl_getAlignedAttribute(field_decl, rp.c.clang_context); if (alignment != 0) { _ = try appendToken(rp.c, .Keyword_align, "align"); @@ -940,9 +940,9 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?* const expr = try transCreateNodeInt(rp.c, alignment / 8); _ = try appendToken(rp.c, .RParen, ")"); - break :blk expr; + break :blk_2 expr; } - break :blk null; + break :blk_2 null; }; const field_node = try c.arena.create(ast.Node.ContainerField); @@ -1073,9 +1073,9 @@ fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.No const field_name_tok = try appendIdentifier(c, field_name); - const int_node = if (!pure_enum) blk: { + const int_node = if (!pure_enum) blk_2: { _ = try appendToken(c, .Colon, "="); - break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); + break :blk_2 try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); } else null; @@ -2388,7 +2388,7 @@ fn transZeroInitExpr( ty: *const ZigClangType, ) TransError!*ast.Node { switch (ZigClangType_getTypeClass(ty)) { - .Builtin => blk: { + .Builtin => { const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); switch (ZigClangBuiltinType_getKind(builtin_ty)) { .Bool => return try transCreateNodeBoolLiteral(rp.c, false), diff --git a/src/all_types.hpp b/src/all_types.hpp index 3939a8ac25..5f142e3dcb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2438,6 +2438,7 @@ struct ScopeBlock { LVal lval; bool safety_off; bool fast_math_on; + bool name_used; }; // This scope is created from every defer expression. @@ -2488,6 +2489,8 @@ struct ScopeLoop { ZigList *incoming_blocks; ResultLocPeerParent *peer_parent; ScopeExpr *spill_scope; + + bool name_used; }; // This scope blocks certain things from working such as comptime continue diff --git a/src/ir.cpp b/src/ir.cpp index 8934a20545..40be4e147b 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -5476,6 +5476,25 @@ static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { return result; } +static bool is_duplicate_label(CodeGen *g, Scope *scope, AstNode *node, Buf *name) { + if (name == nullptr) return false; + + for (;;) { + if (scope == nullptr || scope->id == ScopeIdFnDef) { + break; + } else if (scope->id == ScopeIdBlock || scope->id == ScopeIdLoop) { + Buf *this_block_name = scope->id == ScopeIdBlock ? ((ScopeBlock *)scope)->name : ((ScopeLoop *)scope)->name; + if (this_block_name != nullptr && buf_eql_buf(name, this_block_name)) { + ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redeclaration of label '%s'", buf_ptr(name))); + add_error_note(g, msg, scope->source_node, buf_sprintf("previous declaration is here")); + return true; + } + } + scope = scope->parent; + } + return false; +} + static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *block_node, LVal lval, ResultLoc *result_loc) { @@ -5484,6 +5503,9 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; + if (is_duplicate_label(irb->codegen, parent_scope, block_node, block_node->data.block.name)) + return irb->codegen->invalid_inst_src; + ScopeBlock *scope_block = create_block_scope(irb->codegen, block_node, parent_scope); Scope *outer_block_scope = &scope_block->base; @@ -5495,6 +5517,9 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * } if (block_node->data.block.statements.length == 0) { + if (scope_block->name != nullptr) { + add_node_error(irb->codegen, block_node, buf_sprintf("unused block label")); + } // {} return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc); } @@ -5552,6 +5577,10 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * } } + if (scope_block->name != nullptr && scope_block->name_used == false) { + add_node_error(irb->codegen, block_node, buf_sprintf("unused block label")); + } + if (found_invalid_inst) return irb->codegen->invalid_inst_src; @@ -8152,6 +8181,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; + if (is_duplicate_label(irb->codegen, payload_scope, node, node->data.while_expr.name)) + return irb->codegen->invalid_inst_src; + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, payload_scope); loop_scope->break_block = end_block; loop_scope->continue_block = continue_block; @@ -8169,6 +8201,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no if (body_result == irb->codegen->invalid_inst_src) return body_result; + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused while label")); + } + if (!instr_is_unreachable(body_result)) { ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result)); 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 ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; + if (is_duplicate_label(irb->codegen, child_scope, node, node->data.while_expr.name)) + return irb->codegen->invalid_inst_src; + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope); loop_scope->break_block = end_block; loop_scope->continue_block = continue_block; @@ -8280,6 +8319,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no if (body_result == irb->codegen->invalid_inst_src) return body_result; + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused while label")); + } + if (!instr_is_unreachable(body_result)) { ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result)); 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 Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); + if (is_duplicate_label(irb->codegen, subexpr_scope, node, node->data.while_expr.name)) + return irb->codegen->invalid_inst_src; + ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, subexpr_scope); loop_scope->break_block = end_block; loop_scope->continue_block = continue_block; @@ -8369,6 +8415,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no if (body_result == irb->codegen->invalid_inst_src) return body_result; + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused while label")); + } + if (!instr_is_unreachable(body_result)) { ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result)); 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 elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr); build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); + if (is_duplicate_label(irb->codegen, child_scope, node, node->data.for_expr.name)) + return irb->codegen->invalid_inst_src; + ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; 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 if (body_result == irb->codegen->invalid_inst_src) return irb->codegen->invalid_inst_src; + if (loop_scope->name != nullptr && loop_scope->name_used == false) { + add_node_error(irb->codegen, node, buf_sprintf("unused for label")); + } + if (!instr_is_unreachable(body_result)) { ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.for_expr.body, body_result)); 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 if (node->data.break_expr.name == nullptr || (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) { + this_loop_scope->name_used = true; loop_scope = this_loop_scope; break; } @@ -9473,6 +9531,7 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) { assert(this_block_scope->end_block != nullptr); + this_block_scope->name_used = true; return ir_gen_return_from_block(irb, break_scope, node, this_block_scope); } } else if (search_scope->id == ScopeIdSuspend) { @@ -9540,6 +9599,7 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN if (node->data.continue_expr.name == nullptr || (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) { + this_loop_scope->name_used = true; loop_scope = this_loop_scope; break; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 6b231a323d..4adc538602 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,29 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("duplicate/unused labels", + \\comptime { + \\ blk: { blk: while (false) {} } + \\ blk: while (false) { blk: for (@as([0]void, undefined)) |_| {} } + \\ blk: for (@as([0]void, undefined)) |_| { blk: {} } + \\} + \\comptime { + \\ blk: {} + \\ blk: while(false) {} + \\ blk: for(@as([0]void, undefined)) |_| {} + \\} + , &[_][]const u8{ + "tmp.zig:2:17: error: redeclaration of label 'blk'", + "tmp.zig:2:10: note: previous declaration is here", + "tmp.zig:3:31: error: redeclaration of label 'blk'", + "tmp.zig:3:10: note: previous declaration is here", + "tmp.zig:4:51: error: redeclaration of label 'blk'", + "tmp.zig:4:10: note: previous declaration is here", + "tmp.zig:7:10: error: unused block label", + "tmp.zig:8:10: error: unused while label", + "tmp.zig:9:10: error: unused for label", + }); + cases.addTest("@alignCast of zero sized types", \\export fn foo() void { \\ const a: *void = undefined;