| ... | ... | @@ -5476,6 +5476,25 @@ static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { |
| 5476 | 5476 | return result; |
| 5477 | 5477 | } |
| 5478 | 5478 | |
| 5479 | static 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 | |
| 5479 | 5498 | static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode *block_node, LVal lval, |
| 5480 | 5499 | ResultLoc *result_loc) |
| 5481 | 5500 | { |
| ... | ... | @@ -5484,6 +5503,9 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * |
| 5484 | 5503 | ZigList<IrInstSrc *> incoming_values = {0}; |
| 5485 | 5504 | ZigList<IrBasicBlockSrc *> incoming_blocks = {0}; |
| 5486 | 5505 | |
| 5506 | if (is_duplicate_label(irb->codegen, parent_scope, block_node, block_node->data.block.name)) |
| 5507 | return irb->codegen->invalid_inst_src; |
| 5508 | |
| 5487 | 5509 | ScopeBlock *scope_block = create_block_scope(irb->codegen, block_node, parent_scope); |
| 5488 | 5510 | |
| 5489 | 5511 | Scope *outer_block_scope = &scope_block->base; |
| ... | ... | @@ -5495,6 +5517,9 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * |
| 5495 | 5517 | } |
| 5496 | 5518 | |
| 5497 | 5519 | 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 | } |
| 5498 | 5523 | // {} |
| 5499 | 5524 | return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc); |
| 5500 | 5525 | } |
| ... | ... | @@ -5552,6 +5577,10 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * |
| 5552 | 5577 | } |
| 5553 | 5578 | } |
| 5554 | 5579 | |
| 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 | |
| 5555 | 5584 | if (found_invalid_inst) |
| 5556 | 5585 | return irb->codegen->invalid_inst_src; |
| 5557 | 5586 | |
| ... | ... | @@ -8152,6 +8181,9 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no |
| 8152 | 8181 | ZigList<IrInstSrc *> incoming_values = {0}; |
| 8153 | 8182 | ZigList<IrBasicBlockSrc *> incoming_blocks = {0}; |
| 8154 | 8183 | |
| 8184 | if (is_duplicate_label(irb->codegen, payload_scope, node, node->data.while_expr.name)) |
| 8185 | return irb->codegen->invalid_inst_src; |
| 8186 | |
| 8155 | 8187 | ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, payload_scope); |
| 8156 | 8188 | loop_scope->break_block = end_block; |
| 8157 | 8189 | loop_scope->continue_block = continue_block; |
| ... | ... | @@ -8169,6 +8201,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no |
| 8169 | 8201 | if (body_result == irb->codegen->invalid_inst_src) |
| 8170 | 8202 | return body_result; |
| 8171 | 8203 | |
| 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 | |
| 8172 | 8208 | if (!instr_is_unreachable(body_result)) { |
| 8173 | 8209 | ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result)); |
| 8174 | 8210 | 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 |
| 8263 | 8299 | ZigList<IrInstSrc *> incoming_values = {0}; |
| 8264 | 8300 | ZigList<IrBasicBlockSrc *> incoming_blocks = {0}; |
| 8265 | 8301 | |
| 8302 | if (is_duplicate_label(irb->codegen, child_scope, node, node->data.while_expr.name)) |
| 8303 | return irb->codegen->invalid_inst_src; |
| 8304 | |
| 8266 | 8305 | ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, child_scope); |
| 8267 | 8306 | loop_scope->break_block = end_block; |
| 8268 | 8307 | loop_scope->continue_block = continue_block; |
| ... | ... | @@ -8280,6 +8319,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no |
| 8280 | 8319 | if (body_result == irb->codegen->invalid_inst_src) |
| 8281 | 8320 | return body_result; |
| 8282 | 8321 | |
| 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 | |
| 8283 | 8326 | if (!instr_is_unreachable(body_result)) { |
| 8284 | 8327 | ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result)); |
| 8285 | 8328 | 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 |
| 8353 | 8396 | |
| 8354 | 8397 | Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); |
| 8355 | 8398 | |
| 8399 | if (is_duplicate_label(irb->codegen, subexpr_scope, node, node->data.while_expr.name)) |
| 8400 | return irb->codegen->invalid_inst_src; |
| 8401 | |
| 8356 | 8402 | ScopeLoop *loop_scope = create_loop_scope(irb->codegen, node, subexpr_scope); |
| 8357 | 8403 | loop_scope->break_block = end_block; |
| 8358 | 8404 | loop_scope->continue_block = continue_block; |
| ... | ... | @@ -8369,6 +8415,10 @@ static IrInstSrc *ir_gen_while_expr(IrBuilderSrc *irb, Scope *scope, AstNode *no |
| 8369 | 8415 | if (body_result == irb->codegen->invalid_inst_src) |
| 8370 | 8416 | return body_result; |
| 8371 | 8417 | |
| 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 | |
| 8372 | 8422 | if (!instr_is_unreachable(body_result)) { |
| 8373 | 8423 | ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result)); |
| 8374 | 8424 | 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 |
| 8501 | 8551 | elem_ptr : ir_build_load_ptr(irb, &spill_scope->base, elem_node, elem_ptr); |
| 8502 | 8552 | build_decl_var_and_init(irb, parent_scope, elem_node, elem_var, elem_value, buf_ptr(elem_var_name), is_comptime); |
| 8503 | 8553 | |
| 8554 | if (is_duplicate_label(irb->codegen, child_scope, node, node->data.for_expr.name)) |
| 8555 | return irb->codegen->invalid_inst_src; |
| 8556 | |
| 8504 | 8557 | ZigList<IrInstSrc *> incoming_values = {0}; |
| 8505 | 8558 | ZigList<IrBasicBlockSrc *> incoming_blocks = {0}; |
| 8506 | 8559 | 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 |
| 8520 | 8573 | if (body_result == irb->codegen->invalid_inst_src) |
| 8521 | 8574 | return irb->codegen->invalid_inst_src; |
| 8522 | 8575 | |
| 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 | |
| 8523 | 8580 | if (!instr_is_unreachable(body_result)) { |
| 8524 | 8581 | ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.for_expr.body, body_result)); |
| 8525 | 8582 | 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 |
| 9464 | 9521 | if (node->data.break_expr.name == nullptr || |
| 9465 | 9522 | (this_loop_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_loop_scope->name))) |
| 9466 | 9523 | { |
| 9524 | this_loop_scope->name_used = true; |
| 9467 | 9525 | loop_scope = this_loop_scope; |
| 9468 | 9526 | break; |
| 9469 | 9527 | } |
| ... | ... | @@ -9473,6 +9531,7 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n |
| 9473 | 9531 | (this_block_scope->name != nullptr && buf_eql_buf(node->data.break_expr.name, this_block_scope->name))) |
| 9474 | 9532 | { |
| 9475 | 9533 | assert(this_block_scope->end_block != nullptr); |
| 9534 | this_block_scope->name_used = true; |
| 9476 | 9535 | return ir_gen_return_from_block(irb, break_scope, node, this_block_scope); |
| 9477 | 9536 | } |
| 9478 | 9537 | } else if (search_scope->id == ScopeIdSuspend) { |
| ... | ... | @@ -9540,6 +9599,7 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN |
| 9540 | 9599 | if (node->data.continue_expr.name == nullptr || |
| 9541 | 9600 | (this_loop_scope->name != nullptr && buf_eql_buf(node->data.continue_expr.name, this_loop_scope->name))) |
| 9542 | 9601 | { |
| 9602 | this_loop_scope->name_used = true; |
| 9543 | 9603 | loop_scope = this_loop_scope; |
| 9544 | 9604 | break; |
| 9545 | 9605 | } |