| ... | ... | @@ -14492,6 +14492,20 @@ fn zirBoolBr( |
| 14492 | 14492 | const rhs_result = try sema.resolveBody(rhs_block, body, inst); |
| 14493 | 14493 | _ = try rhs_block.addBr(block_inst, rhs_result); |
| 14494 | 14494 | |
| 14495 | return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst); |
| 14496 | } |
| 14497 | |
| 14498 | fn finishCondBr( |
| 14499 | sema: *Sema, |
| 14500 | parent_block: *Block, |
| 14501 | child_block: *Block, |
| 14502 | then_block: *Block, |
| 14503 | else_block: *Block, |
| 14504 | cond: Air.Inst.Ref, |
| 14505 | block_inst: Air.Inst.Index, |
| 14506 | ) !Air.Inst.Ref { |
| 14507 | const gpa = sema.gpa; |
| 14508 | |
| 14495 | 14509 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 14496 | 14510 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 14497 | 14511 | @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1); |
| ... | ... | @@ -14504,7 +14518,7 @@ fn zirBoolBr( |
| 14504 | 14518 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); |
| 14505 | 14519 | |
| 14506 | 14520 | _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 14507 | | .operand = lhs, |
| 14521 | .operand = cond, |
| 14508 | 14522 | .payload = cond_br_payload, |
| 14509 | 14523 | } } }); |
| 14510 | 14524 | |
| ... | ... | @@ -14901,6 +14915,8 @@ fn analyzeRet( |
| 14901 | 14915 | uncasted_operand: Air.Inst.Ref, |
| 14902 | 14916 | src: LazySrcLoc, |
| 14903 | 14917 | ) CompileError!Zir.Inst.Index { |
| 14918 | const gpa = sema.gpa; |
| 14919 | |
| 14904 | 14920 | // Special case for returning an error to an inferred error set; we need to |
| 14905 | 14921 | // add the error tag to the inferred error set of the in-scope function, so |
| 14906 | 14922 | // that the coercion below works correctly. |
| ... | ... | @@ -14918,11 +14934,13 @@ fn analyzeRet( |
| 14918 | 14934 | return error.ComptimeReturn; |
| 14919 | 14935 | } |
| 14920 | 14936 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 14921 | | try inlining.merges.results.append(sema.gpa, operand); |
| 14937 | try inlining.merges.results.append(gpa, operand); |
| 14922 | 14938 | _ = try block.addBr(inlining.merges.block_inst, operand); |
| 14923 | 14939 | return always_noreturn; |
| 14924 | 14940 | } |
| 14925 | 14941 | |
| 14942 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 14943 | |
| 14926 | 14944 | // TODO implement this feature in all the backends and then delete this check. |
| 14927 | 14945 | const backend_supports_error_return_tracing = |
| 14928 | 14946 | sema.mod.comp.bin_file.options.use_llvm; |
| ... | ... | @@ -14931,19 +14949,52 @@ fn analyzeRet( |
| 14931 | 14949 | sema.mod.comp.bin_file.options.error_return_tracing and |
| 14932 | 14950 | backend_supports_error_return_tracing) |
| 14933 | 14951 | ret_err: { |
| 14934 | | if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| { |
| 14935 | | if (ret_val.tag() != .@"error") break :ret_err; |
| 14936 | | } |
| 14937 | | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); |
| 14952 | // Avoid adding a frame to the error return trace in case the value is comptime-known |
| 14953 | // to be not an error. |
| 14954 | const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, src, operand); |
| 14955 | const need_check = switch (is_non_err) { |
| 14956 | .bool_true => break :ret_err, |
| 14957 | .bool_false => false, |
| 14958 | else => true, |
| 14959 | }; |
| 14960 | |
| 14938 | 14961 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 14939 | 14962 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); |
| 14940 | | const ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 14963 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 14941 | 14964 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 14965 | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); |
| 14942 | 14966 | const args: [1]Air.Inst.Ref = .{err_return_trace}; |
| 14967 | |
| 14968 | if (!need_check) { |
| 14969 | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 14970 | break :ret_err; |
| 14971 | } |
| 14972 | |
| 14973 | const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); |
| 14974 | try sema.air_instructions.append(gpa, .{ |
| 14975 | .tag = .block, |
| 14976 | .data = .{ .ty_pl = .{ |
| 14977 | .ty = .void_type, |
| 14978 | .payload = undefined, |
| 14979 | } }, |
| 14980 | }); |
| 14981 | |
| 14982 | var child_block = block.makeSubBlock(); |
| 14983 | defer child_block.instructions.deinit(gpa); |
| 14984 | |
| 14985 | var then_block = child_block.makeSubBlock(); |
| 14986 | defer then_block.instructions.deinit(gpa); |
| 14987 | _ = try then_block.addUnOp(.ret, operand); |
| 14988 | |
| 14989 | var else_block = child_block.makeSubBlock(); |
| 14990 | defer else_block.instructions.deinit(gpa); |
| 14943 | 14991 | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 14992 | _ = try else_block.addUnOp(.ret, operand); |
| 14993 | |
| 14994 | _ = try finishCondBr(sema, block, &child_block, &then_block, &else_block, is_non_err, block_inst); |
| 14995 | return always_noreturn; |
| 14944 | 14996 | } |
| 14945 | 14997 | |
| 14946 | | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 14947 | 14998 | _ = try block.addUnOp(.ret, operand); |
| 14948 | 14999 | return always_noreturn; |
| 14949 | 15000 | } |
| ... | ... | @@ -25436,10 +25487,16 @@ fn analyzeIsNonErrComptimeOnly( |
| 25436 | 25487 | assert(ot == .ErrorUnion); |
| 25437 | 25488 | |
| 25438 | 25489 | if (Air.refToIndex(operand)) |operand_inst| { |
| 25439 | | const air_tags = sema.air_instructions.items(.tag); |
| 25440 | | if (air_tags[operand_inst] == .wrap_errunion_payload) { |
| 25441 | | return Air.Inst.Ref.bool_true; |
| 25490 | switch (sema.air_instructions.items(.tag)[operand_inst]) { |
| 25491 | .wrap_errunion_payload => return Air.Inst.Ref.bool_true, |
| 25492 | .wrap_errunion_err => return Air.Inst.Ref.bool_false, |
| 25493 | else => {}, |
| 25442 | 25494 | } |
| 25495 | } else if (operand == .undef) { |
| 25496 | return sema.addConstUndef(Type.bool); |
| 25497 | } else { |
| 25498 | // None of the ref tags can be errors. |
| 25499 | return Air.Inst.Ref.bool_true; |
| 25443 | 25500 | } |
| 25444 | 25501 | |
| 25445 | 25502 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand); |