| ... | @@ -272,6 +272,10 @@ static ResultLoc *no_result_loc(void); | ... | @@ -272,6 +272,10 @@ static ResultLoc *no_result_loc(void); |
| 272 | static IrInstGen *ir_analyze_test_non_null(IrAnalyze *ira, IrInst *source_inst, IrInstGen *value); | 272 | static IrInstGen *ir_analyze_test_non_null(IrAnalyze *ira, IrInst *source_inst, IrInstGen *value); |
| 273 | static IrInstGen *ir_error_dependency_loop(IrAnalyze *ira, IrInst *source_instr); | 273 | static IrInstGen *ir_error_dependency_loop(IrAnalyze *ira, IrInst *source_instr); |
| 274 | static IrInstGen *ir_const_undef(IrAnalyze *ira, IrInst *source_instruction, ZigType *ty); | 274 | static IrInstGen *ir_const_undef(IrAnalyze *ira, IrInst *source_instruction, ZigType *ty); |
| | 275 | static ZigVar *ir_create_var(IrBuilderSrc *irb, AstNode *node, Scope *scope, Buf *name, |
| | 276 | bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstSrc *is_comptime); |
| | 277 | static void build_decl_var_and_init(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, ZigVar *var, |
| | 278 | IrInstSrc *init, const char *name_hint, IrInstSrc *is_comptime); |
| 275 | | 279 | |
| 276 | static void destroy_instruction_src(IrInstSrc *inst) { | 280 | static void destroy_instruction_src(IrInstSrc *inst) { |
| 277 | switch (inst->id) { | 281 | switch (inst->id) { |
| ... | @@ -5011,39 +5015,73 @@ static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) { | ... | @@ -5011,39 +5015,73 @@ static IrInstSrc *ir_mark_gen(IrInstSrc *instruction) { |
| 5011 | return instruction; | 5015 | return instruction; |
| 5012 | } | 5016 | } |
| 5013 | | 5017 | |
| 5014 | static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) { | 5018 | static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope *outer_scope, bool *is_noreturn, IrInstSrc *err_value) { |
| 5015 | Scope *scope = inner_scope; | 5019 | Scope *scope = inner_scope; |
| 5016 | bool is_noreturn = false; | 5020 | if (is_noreturn != nullptr) *is_noreturn = false; |
| 5017 | while (scope != outer_scope) { | 5021 | while (scope != outer_scope) { |
| 5018 | if (!scope) | 5022 | if (!scope) |
| 5019 | return is_noreturn; | 5023 | return true; |
| 5020 | | 5024 | |
| 5021 | switch (scope->id) { | 5025 | switch (scope->id) { |
| 5022 | case ScopeIdDefer: { | 5026 | case ScopeIdDefer: { |
| 5023 | AstNode *defer_node = scope->source_node; | 5027 | AstNode *defer_node = scope->source_node; |
| 5024 | assert(defer_node->type == NodeTypeDefer); | 5028 | assert(defer_node->type == NodeTypeDefer); |
| 5025 | ReturnKind defer_kind = defer_node->data.defer.kind; | 5029 | ReturnKind defer_kind = defer_node->data.defer.kind; |
| 5026 | if (defer_kind == ReturnKindUnconditional || | 5030 | AstNode *defer_expr_node = defer_node->data.defer.expr; |
| 5027 | (gen_error_defers && defer_kind == ReturnKindError)) | 5031 | AstNode *defer_var_node = defer_node->data.defer.err_payload; |
| 5028 | { | 5032 | |
| 5029 | AstNode *defer_expr_node = defer_node->data.defer.expr; | 5033 | if (defer_kind == ReturnKindError && err_value == nullptr) { |
| 5030 | Scope *defer_expr_scope = defer_node->data.defer.expr_scope; | 5034 | // This is an `errdefer` but we're generating code for a |
| 5031 | IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); | 5035 | // `return` that doesn't return an error, skip it |
| 5032 | if (defer_expr_value != irb->codegen->invalid_inst_src) { | 5036 | scope = scope->parent; |
| 5033 | if (defer_expr_value->is_noreturn) { | 5037 | continue; |
| 5034 | is_noreturn = true; | 5038 | } |
| 5035 | } else { | 5039 | |
| 5036 | ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, | 5040 | Scope *defer_expr_scope = defer_node->data.defer.expr_scope; |
| 5037 | defer_expr_value)); | 5041 | if (defer_var_node != nullptr) { |
| 5038 | } | 5042 | assert(defer_kind == ReturnKindError); |
| | 5043 | assert(defer_var_node->type == NodeTypeSymbol); |
| | 5044 | Buf *var_name = defer_var_node->data.symbol_expr.symbol; |
| | 5045 | |
| | 5046 | if (defer_expr_node->type == NodeTypeUnreachable) { |
| | 5047 | add_node_error(irb->codegen, defer_var_node, |
| | 5048 | buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); |
| | 5049 | return false; |
| | 5050 | } |
| | 5051 | |
| | 5052 | IrInstSrc *is_comptime; |
| | 5053 | if (ir_should_inline(irb->exec, defer_expr_scope)) { |
| | 5054 | is_comptime = ir_build_const_bool(irb, defer_expr_scope, |
| | 5055 | defer_expr_node, true); |
| | 5056 | } else { |
| | 5057 | is_comptime = ir_build_test_comptime(irb, defer_expr_scope, |
| | 5058 | defer_expr_node, err_value); |
| 5039 | } | 5059 | } |
| | 5060 | |
| | 5061 | ZigVar *err_var = ir_create_var(irb, defer_var_node, defer_expr_scope, |
| | 5062 | var_name, true, true, false, is_comptime); |
| | 5063 | build_decl_var_and_init(irb, defer_expr_scope, defer_var_node, err_var, err_value, |
| | 5064 | buf_ptr(var_name), is_comptime); |
| | 5065 | |
| | 5066 | defer_expr_scope = err_var->child_scope; |
| | 5067 | } |
| | 5068 | |
| | 5069 | IrInstSrc *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope); |
| | 5070 | if (defer_expr_value == irb->codegen->invalid_inst_src) |
| | 5071 | return irb->codegen->invalid_inst_src; |
| | 5072 | |
| | 5073 | if (defer_expr_value->is_noreturn) { |
| | 5074 | if (is_noreturn != nullptr) *is_noreturn = true; |
| | 5075 | } else { |
| | 5076 | ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, |
| | 5077 | defer_expr_value)); |
| 5040 | } | 5078 | } |
| 5041 | scope = scope->parent; | 5079 | scope = scope->parent; |
| 5042 | continue; | 5080 | continue; |
| 5043 | } | 5081 | } |
| 5044 | case ScopeIdDecls: | 5082 | case ScopeIdDecls: |
| 5045 | case ScopeIdFnDef: | 5083 | case ScopeIdFnDef: |
| 5046 | return is_noreturn; | 5084 | return true; |
| 5047 | case ScopeIdBlock: | 5085 | case ScopeIdBlock: |
| 5048 | case ScopeIdVarDecl: | 5086 | case ScopeIdVarDecl: |
| 5049 | case ScopeIdLoop: | 5087 | case ScopeIdLoop: |
| ... | @@ -5060,7 +5098,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope | ... | @@ -5060,7 +5098,7 @@ static bool ir_gen_defers_for_block(IrBuilderSrc *irb, Scope *inner_scope, Scope |
| 5060 | zig_unreachable(); | 5098 | zig_unreachable(); |
| 5061 | } | 5099 | } |
| 5062 | } | 5100 | } |
| 5063 | return is_noreturn; | 5101 | return true; |
| 5064 | } | 5102 | } |
| 5065 | | 5103 | |
| 5066 | static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { | 5104 | static void ir_set_cursor_at_end_gen(IrBuilderGen *irb, IrBasicBlockGen *basic_block) { |
| ... | @@ -5146,7 +5184,8 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, | ... | @@ -5146,7 +5184,8 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, |
| 5146 | bool have_err_defers = defer_counts[ReturnKindError] > 0; | 5184 | bool have_err_defers = defer_counts[ReturnKindError] > 0; |
| 5147 | if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { | 5185 | if (!have_err_defers && !irb->codegen->have_err_ret_tracing) { |
| 5148 | // only generate unconditional defers | 5186 | // only generate unconditional defers |
| 5149 | ir_gen_defers_for_block(irb, scope, outer_scope, false); | 5187 | if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) |
| | 5188 | return irb->codegen->invalid_inst_src; |
| 5150 | IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); | 5189 | IrInstSrc *result = ir_build_return_src(irb, scope, node, nullptr); |
| 5151 | result_loc_ret->base.source_instruction = result; | 5190 | result_loc_ret->base.source_instruction = result; |
| 5152 | return result; | 5191 | return result; |
| ... | @@ -5169,14 +5208,16 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, | ... | @@ -5169,14 +5208,16 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, |
| 5169 | IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); | 5208 | IrBasicBlockSrc *ret_stmt_block = ir_create_basic_block(irb, scope, "RetStmt"); |
| 5170 | | 5209 | |
| 5171 | ir_set_cursor_at_end_and_append_block(irb, err_block); | 5210 | ir_set_cursor_at_end_and_append_block(irb, err_block); |
| 5172 | ir_gen_defers_for_block(irb, scope, outer_scope, true); | 5211 | if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, return_value)) |
| | 5212 | return irb->codegen->invalid_inst_src; |
| 5173 | if (irb->codegen->have_err_ret_tracing && !should_inline) { | 5213 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 5174 | ir_build_save_err_ret_addr_src(irb, scope, node); | 5214 | ir_build_save_err_ret_addr_src(irb, scope, node); |
| 5175 | } | 5215 | } |
| 5176 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); | 5216 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 5177 | | 5217 | |
| 5178 | ir_set_cursor_at_end_and_append_block(irb, ok_block); | 5218 | ir_set_cursor_at_end_and_append_block(irb, ok_block); |
| 5179 | ir_gen_defers_for_block(irb, scope, outer_scope, false); | 5219 | if (!ir_gen_defers_for_block(irb, scope, outer_scope, nullptr, nullptr)) |
| | 5220 | return irb->codegen->invalid_inst_src; |
| 5180 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); | 5221 | ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); |
| 5181 | | 5222 | |
| 5182 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); | 5223 | ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); |
| ... | @@ -5213,7 +5254,12 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, | ... | @@ -5213,7 +5254,12 @@ static IrInstSrc *ir_gen_return(IrBuilderSrc *irb, Scope *scope, AstNode *node, |
| 5213 | result_loc_ret->base.id = ResultLocIdReturn; | 5254 | result_loc_ret->base.id = ResultLocIdReturn; |
| 5214 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); | 5255 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| 5215 | ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); | 5256 | ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); |
| 5216 | if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) { | 5257 | |
| | 5258 | bool is_noreturn = false; |
| | 5259 | if (!ir_gen_defers_for_block(irb, scope, outer_scope, &is_noreturn, err_val)) { |
| | 5260 | return irb->codegen->invalid_inst_src; |
| | 5261 | } |
| | 5262 | if (!is_noreturn) { |
| 5217 | if (irb->codegen->have_err_ret_tracing && !should_inline) { | 5263 | if (irb->codegen->have_err_ret_tracing && !should_inline) { |
| 5218 | ir_build_save_err_ret_addr_src(irb, scope, node); | 5264 | ir_build_save_err_ret_addr_src(irb, scope, node); |
| 5219 | } | 5265 | } |
| ... | @@ -5415,7 +5461,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * | ... | @@ -5415,7 +5461,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * |
| 5415 | | 5461 | |
| 5416 | bool is_return_from_fn = block_node == irb->main_block_node; | 5462 | bool is_return_from_fn = block_node == irb->main_block_node; |
| 5417 | if (!is_return_from_fn) { | 5463 | if (!is_return_from_fn) { |
| 5418 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | 5464 | if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) |
| | 5465 | return irb->codegen->invalid_inst_src; |
| 5419 | } | 5466 | } |
| 5420 | | 5467 | |
| 5421 | IrInstSrc *result; | 5468 | IrInstSrc *result; |
| ... | @@ -5440,7 +5487,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * | ... | @@ -5440,7 +5487,8 @@ static IrInstSrc *ir_gen_block(IrBuilderSrc *irb, Scope *parent_scope, AstNode * |
| 5440 | result_loc_ret->base.id = ResultLocIdReturn; | 5487 | result_loc_ret->base.id = ResultLocIdReturn; |
| 5441 | ir_build_reset_result(irb, parent_scope, block_node, &result_loc_ret->base); | 5488 | ir_build_reset_result(irb, parent_scope, block_node, &result_loc_ret->base); |
| 5442 | ir_mark_gen(ir_build_end_expr(irb, parent_scope, block_node, result, &result_loc_ret->base)); | 5489 | ir_mark_gen(ir_build_end_expr(irb, parent_scope, block_node, result, &result_loc_ret->base)); |
| 5443 | ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); | 5490 | if (!ir_gen_defers_for_block(irb, child_scope, outer_block_scope, nullptr, nullptr)) |
| | 5491 | return irb->codegen->invalid_inst_src; |
| 5444 | return ir_mark_gen(ir_build_return_src(irb, child_scope, result->base.source_node, result)); | 5492 | return ir_mark_gen(ir_build_return_src(irb, child_scope, result->base.source_node, result)); |
| 5445 | } | 5493 | } |
| 5446 | | 5494 | |
| ... | @@ -9240,7 +9288,8 @@ static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope | ... | @@ -9240,7 +9288,8 @@ static IrInstSrc *ir_gen_return_from_block(IrBuilderSrc *irb, Scope *break_scope |
| 9240 | } | 9288 | } |
| 9241 | | 9289 | |
| 9242 | IrBasicBlockSrc *dest_block = block_scope->end_block; | 9290 | IrBasicBlockSrc *dest_block = block_scope->end_block; |
| 9243 | ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); | 9291 | if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) |
| | 9292 | return irb->codegen->invalid_inst_src; |
| 9244 | | 9293 | |
| 9245 | block_scope->incoming_blocks->append(irb->current_basic_block); | 9294 | block_scope->incoming_blocks->append(irb->current_basic_block); |
| 9246 | block_scope->incoming_values->append(result_value); | 9295 | block_scope->incoming_values->append(result_value); |
| ... | @@ -9314,7 +9363,8 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n | ... | @@ -9314,7 +9363,8 @@ static IrInstSrc *ir_gen_break(IrBuilderSrc *irb, Scope *break_scope, AstNode *n |
| 9314 | } | 9363 | } |
| 9315 | | 9364 | |
| 9316 | IrBasicBlockSrc *dest_block = loop_scope->break_block; | 9365 | IrBasicBlockSrc *dest_block = loop_scope->break_block; |
| 9317 | ir_gen_defers_for_block(irb, break_scope, dest_block->scope, false); | 9366 | if (!ir_gen_defers_for_block(irb, break_scope, dest_block->scope, nullptr, nullptr)) |
| | 9367 | return irb->codegen->invalid_inst_src; |
| 9318 | | 9368 | |
| 9319 | loop_scope->incoming_blocks->append(irb->current_basic_block); | 9369 | loop_scope->incoming_blocks->append(irb->current_basic_block); |
| 9320 | loop_scope->incoming_values->append(result_value); | 9370 | loop_scope->incoming_values->append(result_value); |
| ... | @@ -9373,7 +9423,8 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN | ... | @@ -9373,7 +9423,8 @@ static IrInstSrc *ir_gen_continue(IrBuilderSrc *irb, Scope *continue_scope, AstN |
| 9373 | } | 9423 | } |
| 9374 | | 9424 | |
| 9375 | IrBasicBlockSrc *dest_block = loop_scope->continue_block; | 9425 | IrBasicBlockSrc *dest_block = loop_scope->continue_block; |
| 9376 | ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false); | 9426 | if (!ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, nullptr, nullptr)) |
| | 9427 | return irb->codegen->invalid_inst_src; |
| 9377 | return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); | 9428 | return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime)); |
| 9378 | } | 9429 | } |
| 9379 | | 9430 | |