| ... | ... | @@ -14888,10 +14888,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir |
| 14888 | 14888 | const operand = try sema.analyzeLoad(block, src, ret_ptr, src); |
| 14889 | 14889 | return sema.analyzeRet(block, operand, src); |
| 14890 | 14890 | } |
| 14891 | |
| 14892 | if (sema.wantErrorReturnTracing()) { |
| 14893 | const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); |
| 14894 | return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr); |
| 14895 | } |
| 14896 | |
| 14891 | 14897 | _ = try block.addUnOp(.ret_load, ret_ptr); |
| 14892 | 14898 | return always_noreturn; |
| 14893 | 14899 | } |
| 14894 | 14900 | |
| 14901 | fn retWithErrTracing( |
| 14902 | sema: *Sema, |
| 14903 | block: *Block, |
| 14904 | src: LazySrcLoc, |
| 14905 | is_non_err: Air.Inst.Ref, |
| 14906 | ret_tag: Air.Inst.Tag, |
| 14907 | operand: Air.Inst.Ref, |
| 14908 | ) CompileError!Zir.Inst.Index { |
| 14909 | const need_check = switch (is_non_err) { |
| 14910 | .bool_true => { |
| 14911 | _ = try block.addUnOp(ret_tag, operand); |
| 14912 | return always_noreturn; |
| 14913 | }, |
| 14914 | .bool_false => false, |
| 14915 | else => true, |
| 14916 | }; |
| 14917 | const gpa = sema.gpa; |
| 14918 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 14919 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); |
| 14920 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 14921 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); |
| 14922 | const return_err_fn = try sema.getBuiltin(block, src, "returnError"); |
| 14923 | const args: [1]Air.Inst.Ref = .{err_return_trace}; |
| 14924 | |
| 14925 | if (!need_check) { |
| 14926 | _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 14927 | _ = try block.addUnOp(ret_tag, operand); |
| 14928 | return always_noreturn; |
| 14929 | } |
| 14930 | |
| 14931 | var then_block = block.makeSubBlock(); |
| 14932 | defer then_block.instructions.deinit(gpa); |
| 14933 | _ = try then_block.addUnOp(ret_tag, operand); |
| 14934 | |
| 14935 | var else_block = block.makeSubBlock(); |
| 14936 | defer else_block.instructions.deinit(gpa); |
| 14937 | _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null); |
| 14938 | _ = try else_block.addUnOp(ret_tag, operand); |
| 14939 | |
| 14940 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 14941 | then_block.instructions.items.len + else_block.instructions.items.len + |
| 14942 | @typeInfo(Air.Block).Struct.fields.len + 1); |
| 14943 | |
| 14944 | const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ |
| 14945 | .then_body_len = @intCast(u32, then_block.instructions.items.len), |
| 14946 | .else_body_len = @intCast(u32, else_block.instructions.items.len), |
| 14947 | }); |
| 14948 | sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items); |
| 14949 | sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items); |
| 14950 | |
| 14951 | _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 14952 | .operand = is_non_err, |
| 14953 | .payload = cond_br_payload, |
| 14954 | } } }); |
| 14955 | |
| 14956 | return always_noreturn; |
| 14957 | } |
| 14958 | |
| 14959 | fn wantErrorReturnTracing(sema: *Sema) bool { |
| 14960 | // TODO implement this feature in all the backends and then delete this check. |
| 14961 | const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; |
| 14962 | |
| 14963 | return sema.fn_ret_ty.isError() and |
| 14964 | sema.mod.comp.bin_file.options.error_return_tracing and |
| 14965 | backend_supports_error_return_tracing; |
| 14966 | } |
| 14967 | |
| 14895 | 14968 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { |
| 14896 | 14969 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); |
| 14897 | 14970 | |
| ... | ... | @@ -14915,8 +14988,6 @@ fn analyzeRet( |
| 14915 | 14988 | uncasted_operand: Air.Inst.Ref, |
| 14916 | 14989 | src: LazySrcLoc, |
| 14917 | 14990 | ) CompileError!Zir.Inst.Index { |
| 14918 | | const gpa = sema.gpa; |
| 14919 | | |
| 14920 | 14991 | // Special case for returning an error to an inferred error set; we need to |
| 14921 | 14992 | // add the error tag to the inferred error set of the in-scope function, so |
| 14922 | 14993 | // that the coercion below works correctly. |
| ... | ... | @@ -14934,65 +15005,18 @@ fn analyzeRet( |
| 14934 | 15005 | return error.ComptimeReturn; |
| 14935 | 15006 | } |
| 14936 | 15007 | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 14937 | | try inlining.merges.results.append(gpa, operand); |
| 15008 | try inlining.merges.results.append(sema.gpa, operand); |
| 14938 | 15009 | _ = try block.addBr(inlining.merges.block_inst, operand); |
| 14939 | 15010 | return always_noreturn; |
| 14940 | 15011 | } |
| 14941 | 15012 | |
| 14942 | 15013 | try sema.resolveTypeLayout(block, src, sema.fn_ret_ty); |
| 14943 | 15014 | |
| 14944 | | // TODO implement this feature in all the backends and then delete this check. |
| 14945 | | const backend_supports_error_return_tracing = |
| 14946 | | sema.mod.comp.bin_file.options.use_llvm; |
| 14947 | | |
| 14948 | | if (sema.fn_ret_ty.isError() and |
| 14949 | | sema.mod.comp.bin_file.options.error_return_tracing and |
| 14950 | | backend_supports_error_return_tracing) |
| 14951 | | ret_err: { |
| 15015 | if (sema.wantErrorReturnTracing()) { |
| 14952 | 15016 | // Avoid adding a frame to the error return trace in case the value is comptime-known |
| 14953 | 15017 | // 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 | | |
| 14961 | | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); |
| 14962 | | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); |
| 14963 | | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); |
| 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"); |
| 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); |
| 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; |
| 15018 | const is_non_err = try sema.analyzeIsNonErr(block, src, operand); |
| 15019 | return retWithErrTracing(sema, block, src, is_non_err, .ret, operand); |
| 14996 | 15020 | } |
| 14997 | 15021 | |
| 14998 | 15022 | _ = try block.addUnOp(.ret, operand); |
| ... | ... | @@ -25474,6 +25498,27 @@ fn analyzeIsNull( |
| 25474 | 25498 | return block.addUnOp(air_tag, operand); |
| 25475 | 25499 | } |
| 25476 | 25500 | |
| 25501 | fn analyzePtrIsNonErrComptimeOnly( |
| 25502 | sema: *Sema, |
| 25503 | block: *Block, |
| 25504 | src: LazySrcLoc, |
| 25505 | operand: Air.Inst.Ref, |
| 25506 | ) CompileError!Air.Inst.Ref { |
| 25507 | const ptr_ty = sema.typeOf(operand); |
| 25508 | assert(ptr_ty.zigTypeTag() == .Pointer); |
| 25509 | const child_ty = ptr_ty.childType(); |
| 25510 | |
| 25511 | const child_tag = child_ty.zigTypeTag(); |
| 25512 | if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true; |
| 25513 | if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false; |
| 25514 | assert(child_tag == .ErrorUnion); |
| 25515 | |
| 25516 | _ = block; |
| 25517 | _ = src; |
| 25518 | |
| 25519 | return Air.Inst.Ref.none; |
| 25520 | } |
| 25521 | |
| 25477 | 25522 | fn analyzeIsNonErrComptimeOnly( |
| 25478 | 25523 | sema: *Sema, |
| 25479 | 25524 | block: *Block, |
| ... | ... | @@ -25572,6 +25617,21 @@ fn analyzeIsNonErr( |
| 25572 | 25617 | } |
| 25573 | 25618 | } |
| 25574 | 25619 | |
| 25620 | fn analyzePtrIsNonErr( |
| 25621 | sema: *Sema, |
| 25622 | block: *Block, |
| 25623 | src: LazySrcLoc, |
| 25624 | operand: Air.Inst.Ref, |
| 25625 | ) CompileError!Air.Inst.Ref { |
| 25626 | const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand); |
| 25627 | if (result == .none) { |
| 25628 | try sema.requireRuntimeBlock(block, src, null); |
| 25629 | return block.addUnOp(.is_non_err_ptr, operand); |
| 25630 | } else { |
| 25631 | return result; |
| 25632 | } |
| 25633 | } |
| 25634 | |
| 25575 | 25635 | fn analyzeSlice( |
| 25576 | 25636 | sema: *Sema, |
| 25577 | 25637 | block: *Block, |