| ... | ... | @@ -14489,6 +14489,20 @@ fn zirBoolBr( |
| 14489 | 14489 | const rhs_result = try sema.resolveBody(rhs_block, body, inst); |
| 14490 | 14490 | _ = try rhs_block.addBr(block_inst, rhs_result); |
| 14491 | 14491 | |
| 14492 | return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst); |
| 14493 | } |
| 14494 | |
| 14495 | fn finishCondBr( |
| 14496 | sema: *Sema, |
| 14497 | parent_block: *Block, |
| 14498 | child_block: *Block, |
| 14499 | then_block: *Block, |
| 14500 | else_block: *Block, |
| 14501 | cond: Air.Inst.Ref, |
| 14502 | block_inst: Air.Inst.Index, |
| 14503 | ) !Air.Inst.Ref { |
| 14504 | const gpa = sema.gpa; |
| 14505 | |
| 14492 | 14506 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 14493 | 14507 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 14494 | 14508 | @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1); |
| ... | ... | @@ -14501,7 +14515,7 @@ fn zirBoolBr( |
| 14501 | 14515 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); |
| 14502 | 14516 | |
| 14503 | 14517 | _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 14504 | | .operand = lhs, |
| 14518 | .operand = cond, |
| 14505 | 14519 | .payload = cond_br_payload, |
| 14506 | 14520 | } } }); |
| 14507 | 14521 | |
| ... | ... | @@ -14871,10 +14885,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir |
| 14871 | 14885 | const operand = try sema.analyzeLoad(block, src, ret_ptr, src); |
| 14872 | 14886 | return sema.analyzeRet(block, operand, src); |
| 14873 | 14887 | } |
| 14888 | |
| 14889 | if (sema.wantErrorReturnTracing()) { |
| 14890 | const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); |
| 14891 | return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr); |
| 14892 | } |
| 14893 | |
| 14874 | 14894 | _ = try block.addUnOp(.ret_load, ret_ptr); |
| 14875 | 14895 | return always_noreturn; |
| 14876 | 14896 | } |
| 14877 | 14897 | |
| 14898 | fn retWithErrTracing( |
| 14899 | sema: *Sema, |
| 14900 | block: *Block, |
| 14901 | src: LazySrcLoc, |
| 14902 | is_non_err: Air.Inst.Ref, |
| 14903 | ret_tag: Air.Inst.Tag, |
| 14904 | operand: Air.Inst.Ref, |
| 14905 | ) CompileError!Zir.Inst.Index { |
| 14906 | const need_check = switch (is_non_err) { |
| 14907 | .bool_true => { |
| 14908 | _ = try block.addUnOp(ret_tag, operand); |
| 14909 | return always_noreturn; |
| 14910 | }, |
| 14911 | .bool_false => false, |
| 14912 | else => true, |
| 14913 | }; |
| 14914 | const gpa = sema.gpa; |
| 14915 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 14916 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); |
| 14917 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 14918 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 14919 | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); |
| 14920 | const args: [1]Air.Inst.Ref = .{err_return_trace}; |
| 14921 | |
| 14922 | if (!need_check) { |
| 14923 | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 14924 | _ = try block.addUnOp(ret_tag, operand); |
| 14925 | return always_noreturn; |
| 14926 | } |
| 14927 | |
| 14928 | var then_block = block.makeSubBlock(); |
| 14929 | defer then_block.instructions.deinit(gpa); |
| 14930 | _ = try then_block.addUnOp(ret_tag, operand); |
| 14931 | |
| 14932 | var else_block = block.makeSubBlock(); |
| 14933 | defer else_block.instructions.deinit(gpa); |
| 14934 | _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 14935 | _ = try else_block.addUnOp(ret_tag, operand); |
| 14936 | |
| 14937 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 14938 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 14939 | @typeInfo(Air.Block).Struct.fields.len + 1); |
| 14940 | |
| 14941 | const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ |
| 14942 | .then_body_len = @intCast(u32, then_block.instructions.items.len), |
| 14943 | .else_body_len = @intCast(u32, else_block.instructions.items.len), |
| 14944 | }); |
| 14945 | sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); |
| 14946 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); |
| 14947 | |
| 14948 | _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 14949 | .operand = is_non_err, |
| 14950 | .payload = cond_br_payload, |
| 14951 | } } }); |
| 14952 | |
| 14953 | return always_noreturn; |
| 14954 | } |
| 14955 | |
| 14956 | fn wantErrorReturnTracing(sema: *Sema) bool { |
| 14957 | // TODO implement this feature in all the backends and then delete this check. |
| 14958 | const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; |
| 14959 | |
| 14960 | return sema.fn_ret_ty.isError() and |
| 14961 | sema.mod.comp.bin_file.options.error_return_tracing and |
| 14962 | backend_supports_error_return_tracing; |
| 14963 | } |
| 14964 | |
| 14878 | 14965 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { |
| 14879 | 14966 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); |
| 14880 | 14967 | |
| ... | ... | @@ -14920,27 +15007,15 @@ fn analyzeRet( |
| 14920 | 15007 | return always_noreturn; |
| 14921 | 15008 | } |
| 14922 | 15009 | |
| 14923 | | // TODO implement this feature in all the backends and then delete this check. |
| 14924 | | const backend_supports_error_return_tracing = |
| 14925 | | sema.mod.comp.bin_file.options.use_llvm; |
| 15010 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 14926 | 15011 | |
| 14927 | | if (sema.fn_ret_ty.isError() and |
| 14928 | | sema.mod.comp.bin_file.options.error_return_tracing and |
| 14929 | | backend_supports_error_return_tracing) |
| 14930 | | ret_err: { |
| 14931 | | if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| { |
| 14932 | | if (ret_val.tag() != .@"error") break :ret_err; |
| 14933 | | } |
| 14934 | | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); |
| 14935 | | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 14936 | | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); |
| 14937 | | const ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 14938 | | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 14939 | | const args: [1]Air.Inst.Ref = .{err_return_trace}; |
| 14940 | | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 15012 | if (sema.wantErrorReturnTracing()) { |
| 15013 | // Avoid adding a frame to the error return trace in case the value is comptime-known |
| 15014 | // to be not an error. |
| 15015 | const is_non_err = try sema.analyzeIsNonErr(block, src, operand); |
| 15016 | return retWithErrTracing(sema, block, src, is_non_err, .ret, operand); |
| 14941 | 15017 | } |
| 14942 | 15018 | |
| 14943 | | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 14944 | 15019 | _ = try block.addUnOp(.ret, operand); |
| 14945 | 15020 | return always_noreturn; |
| 14946 | 15021 | } |
| ... | ... | @@ -25418,6 +25493,27 @@ fn analyzeIsNull( |
| 25418 | 25493 | return block.addUnOp(air_tag, operand); |
| 25419 | 25494 | } |
| 25420 | 25495 | |
| 25496 | fn analyzePtrIsNonErrComptimeOnly( |
| 25497 | sema: *Sema, |
| 25498 | block: *Block, |
| 25499 | src: LazySrcLoc, |
| 25500 | operand: Air.Inst.Ref, |
| 25501 | ) CompileError!Air.Inst.Ref { |
| 25502 | const ptr_ty = sema.typeOf(operand); |
| 25503 | assert(ptr_ty.zigTypeTag() == .Pointer); |
| 25504 | const child_ty = ptr_ty.childType(); |
| 25505 | |
| 25506 | const child_tag = child_ty.zigTypeTag(); |
| 25507 | if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; |
| 25508 | if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 25509 | assert(child_tag == .ErrorUnion); |
| 25510 | |
| 25511 | _ = block; |
| 25512 | _ = src; |
| 25513 | |
| 25514 | return Air.Inst.Ref.none; |
| 25515 | } |
| 25516 | |
| 25421 | 25517 | fn analyzeIsNonErrComptimeOnly( |
| 25422 | 25518 | sema: *Sema, |
| 25423 | 25519 | block: *Block, |
| ... | ... | @@ -25431,10 +25527,16 @@ fn analyzeIsNonErrComptimeOnly( |
| 25431 | 25527 | assert(ot == .ErrorUnion); |
| 25432 | 25528 | |
| 25433 | 25529 | if (Air.refToIndex(operand)) |operand_inst| { |
| 25434 | | const air_tags = sema.air_instructions.items(.tag); |
| 25435 | | if (air_tags[operand_inst] == .wrap_errunion_payload) { |
| 25436 | | return Air.Inst.Ref.bool_true; |
| 25530 | switch (sema.air_instructions.items(.tag)[operand_inst]) { |
| 25531 | .wrap_errunion_payload => return Air.Inst.Ref.bool_true, |
| 25532 | .wrap_errunion_err => return Air.Inst.Ref.bool_false, |
| 25533 | else => {}, |
| 25437 | 25534 | } |
| 25535 | } else if (operand == .undef) { |
| 25536 | return sema.addConstUndef(Type.bool); |
| 25537 | } else { |
| 25538 | // None of the ref tags can be errors. |
| 25539 | return Air.Inst.Ref.bool_true; |
| 25438 | 25540 | } |
| 25439 | 25541 | |
| 25440 | 25542 | const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand); |
| ... | ... | @@ -25510,6 +25612,21 @@ fn analyzeIsNonErr( |
| 25510 | 25612 | } |
| 25511 | 25613 | } |
| 25512 | 25614 | |
| 25615 | fn analyzePtrIsNonErr( |
| 25616 | sema: *Sema, |
| 25617 | block: *Block, |
| 25618 | src: LazySrcLoc, |
| 25619 | operand: Air.Inst.Ref, |
| 25620 | ) CompileError!Air.Inst.Ref { |
| 25621 | const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand); |
| 25622 | if (result == .none) { |
| 25623 | try sema.requireRuntimeBlock(block, src, null); |
| 25624 | return block.addUnOp(.is_non_err_ptr, operand); |
| 25625 | } else { |
| 25626 | return result; |
| 25627 | } |
| 25628 | } |
| 25629 | |
| 25513 | 25630 | fn analyzeSlice( |
| 25514 | 25631 | sema: *Sema, |
| 25515 | 25632 | block: *Block, |