| ... | ... | @@ -18034,28 +18034,24 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi |
| 18034 | 18034 | return sema.analyzeRet(block, operand, src, block.src(.{ .node_offset_return_operand = inst_data.src_node })); |
| 18035 | 18035 | } |
| 18036 | 18036 | |
| 18037 | | if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) { |
| 18037 | if (sema.wantErrorReturnTracing()) { |
| 18038 | 18038 | const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); |
| 18039 | | return sema.retWithErrTracing(block, src, is_non_err, .ret_load, ret_ptr); |
| 18039 | try sema.maybePushErrorTrace(block, src, is_non_err); |
| 18040 | 18040 | } |
| 18041 | 18041 | |
| 18042 | 18042 | _ = try block.addUnOp(.ret_load, ret_ptr); |
| 18043 | 18043 | } |
| 18044 | 18044 | |
| 18045 | | fn retWithErrTracing( |
| 18045 | fn maybePushErrorTrace( |
| 18046 | 18046 | sema: *Sema, |
| 18047 | | block: *Block, |
| 18047 | parent_block: *Block, |
| 18048 | 18048 | src: LazySrcLoc, |
| 18049 | 18049 | is_non_err: Air.Inst.Ref, |
| 18050 | | ret_tag: Air.Inst.Tag, |
| 18051 | | operand: Air.Inst.Ref, |
| 18052 | 18050 | ) CompileError!void { |
| 18053 | 18051 | const pt = sema.pt; |
| 18052 | |
| 18054 | 18053 | const need_check = switch (is_non_err) { |
| 18055 | | .bool_true => { |
| 18056 | | _ = try block.addUnOp(ret_tag, operand); |
| 18057 | | return; |
| 18058 | | }, |
| 18054 | .bool_true => return, |
| 18059 | 18055 | .bool_false => false, |
| 18060 | 18056 | else => true, |
| 18061 | 18057 | }; |
| ... | ... | @@ -18068,27 +18064,44 @@ fn retWithErrTracing( |
| 18068 | 18064 | const return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError)); |
| 18069 | 18065 | |
| 18070 | 18066 | if (!need_check) { |
| 18071 | | try sema.callBuiltin(block, src, return_err_fn, .never_tail, &.{}, .@"error return"); |
| 18072 | | _ = try block.addUnOp(ret_tag, operand); |
| 18067 | try sema.callBuiltin(parent_block, src, return_err_fn, .never_tail, &.{}, .@"error return"); |
| 18073 | 18068 | return; |
| 18074 | 18069 | } |
| 18075 | 18070 | |
| 18076 | | var then_block = block.makeSubBlock(); |
| 18077 | | defer then_block.instructions.deinit(gpa); |
| 18078 | | _ = try then_block.addUnOp(ret_tag, operand); |
| 18071 | var err_block = parent_block.makeSubBlock(); |
| 18072 | defer err_block.instructions.deinit(gpa); |
| 18073 | try sema.callBuiltin(&err_block, src, return_err_fn, .never_tail, &.{}, .@"error return"); |
| 18079 | 18074 | |
| 18080 | | var else_block = block.makeSubBlock(); |
| 18081 | | defer else_block.instructions.deinit(gpa); |
| 18082 | | try sema.callBuiltin(&else_block, src, return_err_fn, .never_tail, &.{}, .@"error return"); |
| 18083 | | _ = try else_block.addUnOp(ret_tag, operand); |
| 18075 | try parent_block.instructions.ensureUnusedCapacity(gpa, 1); |
| 18084 | 18076 | |
| 18085 | | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len + |
| 18086 | | then_block.instructions.items.len + else_block.instructions.items.len + |
| 18087 | | @typeInfo(Air.Block).@"struct".fields.len + 1); |
| 18077 | try sema.air_instructions.ensureUnusedCapacity(gpa, 4); |
| 18078 | try sema.air_extra.ensureUnusedCapacity( |
| 18079 | gpa, |
| 18080 | @typeInfo(Air.Block).@"struct".fields.len + |
| 18081 | 1 + // the main block contains only the `cond_br` |
| 18082 | @typeInfo(Air.CondBr).@"struct".fields.len + |
| 18083 | 1 + // the non-error branch contains only a `br` |
| 18084 | err_block.instructions.items.len + 1, // the error branch contains the `returnError` call and a `br` |
| 18085 | ); |
| 18086 | |
| 18087 | const block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len); |
| 18088 | const cond_br_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len + 1); |
| 18089 | const then_br_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len + 2); |
| 18090 | const else_br_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len + 3); |
| 18091 | |
| 18092 | const block_payload = sema.addExtraAssumeCapacity(Air.Block{ .body_len = 1 }); |
| 18093 | sema.air_extra.appendAssumeCapacity(@intFromEnum(cond_br_inst)); |
| 18094 | sema.air_instructions.appendAssumeCapacity(.{ |
| 18095 | .tag = .block, |
| 18096 | .data = .{ .ty_pl = .{ |
| 18097 | .ty = .void_type, |
| 18098 | .payload = block_payload, |
| 18099 | } }, |
| 18100 | }); |
| 18088 | 18101 | |
| 18089 | 18102 | const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ |
| 18090 | | .then_body_len = @intCast(then_block.instructions.items.len), |
| 18091 | | .else_body_len = @intCast(else_block.instructions.items.len), |
| 18103 | .then_body_len = 1, |
| 18104 | .else_body_len = @intCast(err_block.instructions.items.len + 1), |
| 18092 | 18105 | .branch_hints = .{ |
| 18093 | 18106 | // Weight against error branch. |
| 18094 | 18107 | .true = .likely, |
| ... | ... | @@ -18098,19 +18111,33 @@ fn retWithErrTracing( |
| 18098 | 18111 | .else_cov = .none, |
| 18099 | 18112 | }, |
| 18100 | 18113 | }); |
| 18101 | | sema.air_extra.appendSliceAssumeCapacity(@ptrCast(then_block.instructions.items)); |
| 18102 | | sema.air_extra.appendSliceAssumeCapacity(@ptrCast(else_block.instructions.items)); |
| 18114 | sema.air_extra.appendAssumeCapacity(@intFromEnum(then_br_inst)); |
| 18115 | sema.air_extra.appendSliceAssumeCapacity(@ptrCast(err_block.instructions.items)); |
| 18116 | sema.air_extra.appendAssumeCapacity(@intFromEnum(else_br_inst)); |
| 18117 | sema.air_instructions.appendAssumeCapacity(.{ |
| 18118 | .tag = .cond_br, |
| 18119 | .data = .{ .pl_op = .{ |
| 18120 | .operand = is_non_err, |
| 18121 | .payload = cond_br_payload, |
| 18122 | } }, |
| 18123 | }); |
| 18103 | 18124 | |
| 18104 | | _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{ |
| 18105 | | .operand = is_non_err, |
| 18106 | | .payload = cond_br_payload, |
| 18107 | | } } }); |
| 18125 | const br_inst_data: Air.Inst = .{ |
| 18126 | .tag = .br, |
| 18127 | .data = .{ .br = .{ |
| 18128 | .block_inst = block_inst, |
| 18129 | .operand = .void_value, |
| 18130 | } }, |
| 18131 | }; |
| 18132 | sema.air_instructions.appendAssumeCapacity(br_inst_data); // then_br_inst |
| 18133 | sema.air_instructions.appendAssumeCapacity(br_inst_data); // else_br_inst |
| 18134 | |
| 18135 | parent_block.instructions.appendAssumeCapacity(block_inst); |
| 18108 | 18136 | } |
| 18109 | 18137 | |
| 18110 | | fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { |
| 18111 | | const pt = sema.pt; |
| 18112 | | const zcu = pt.zcu; |
| 18113 | | return fn_ret_ty.isError(zcu) and zcu.comp.config.any_error_tracing; |
| 18138 | fn wantErrorReturnTracing(sema: *Sema) bool { |
| 18139 | const zcu = sema.pt.zcu; |
| 18140 | return sema.fn_ret_ty.isError(zcu) and zcu.comp.config.any_error_tracing; |
| 18114 | 18141 | } |
| 18115 | 18142 | |
| 18116 | 18143 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | ... | @@ -18251,47 +18278,44 @@ fn analyzeRet( |
| 18251 | 18278 | else => |e| return e, |
| 18252 | 18279 | }; |
| 18253 | 18280 | |
| 18254 | | if (block.inlining) |inlining| { |
| 18281 | if (block.isComptime()) { |
| 18282 | const inlining = block.inlining orelse { |
| 18283 | return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{}); |
| 18284 | }; |
| 18255 | 18285 | assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr |
| 18256 | | if (block.isComptime()) { |
| 18257 | | const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); |
| 18258 | | inlining.comptime_result = operand; |
| 18286 | const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); |
| 18287 | inlining.comptime_result = operand; |
| 18259 | 18288 | |
| 18260 | | if (sema.fn_ret_ty.isError(zcu) and ret_val.getErrorName(zcu) != .none) { |
| 18261 | | try sema.comptime_err_ret_trace.append(src); |
| 18262 | | } |
| 18263 | | return error.ComptimeReturn; |
| 18289 | if (sema.fn_ret_ty.isError(zcu) and ret_val.getErrorName(zcu) != .none) { |
| 18290 | try sema.comptime_err_ret_trace.append(src); |
| 18264 | 18291 | } |
| 18265 | | // We are inlining a function call; rewrite the `ret` as a `break`. |
| 18266 | | const br_inst = try block.addBr(inlining.merges.block_inst, operand); |
| 18267 | | try inlining.merges.results.append(sema.gpa, operand); |
| 18268 | | try inlining.merges.br_list.append(sema.gpa, br_inst.toIndex().?); |
| 18269 | | try inlining.merges.src_locs.append(sema.gpa, operand_src); |
| 18270 | | return; |
| 18271 | | } else if (block.isComptime()) { |
| 18272 | | return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{}); |
| 18273 | | } else if (sema.func_is_naked) { |
| 18274 | | const msg = msg: { |
| 18275 | | const msg = try sema.errMsg(src, "cannot return from naked function", .{}); |
| 18276 | | errdefer msg.destroy(sema.gpa); |
| 18277 | | |
| 18278 | | try sema.errNote(src, msg, "can only return using assembly", .{}); |
| 18279 | | break :msg msg; |
| 18280 | | }; |
| 18281 | | return sema.failWithOwnedErrorMsg(block, msg); |
| 18292 | return error.ComptimeReturn; |
| 18282 | 18293 | } |
| 18283 | 18294 | |
| 18284 | | try sema.validateRuntimeValue(block, operand_src, operand); |
| 18295 | if (block.inlining == null and sema.func_is_naked) return sema.failWithOwnedErrorMsg(block, msg: { |
| 18296 | const msg = try sema.errMsg(src, "cannot return from naked function", .{}); |
| 18297 | errdefer msg.destroy(sema.gpa); |
| 18298 | |
| 18299 | try sema.errNote(src, msg, "can only return using assembly", .{}); |
| 18300 | break :msg msg; |
| 18301 | }); |
| 18285 | 18302 | |
| 18286 | | const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret; |
| 18287 | | if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) { |
| 18288 | | // Avoid adding a frame to the error return trace in case the value is comptime-known |
| 18289 | | // to be not an error. |
| 18303 | if (sema.wantErrorReturnTracing()) { |
| 18290 | 18304 | const is_non_err = try sema.analyzeIsNonErr(block, operand_src, operand); |
| 18291 | | return sema.retWithErrTracing(block, src, is_non_err, air_tag, operand); |
| 18305 | try sema.maybePushErrorTrace(block, src, is_non_err); |
| 18292 | 18306 | } |
| 18293 | 18307 | |
| 18294 | | _ = try block.addUnOp(air_tag, operand); |
| 18308 | if (block.inlining) |inlining| { |
| 18309 | assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr |
| 18310 | const br_inst = try block.addBr(inlining.merges.block_inst, operand); |
| 18311 | try inlining.merges.results.append(sema.gpa, operand); |
| 18312 | try inlining.merges.br_list.append(sema.gpa, br_inst.toIndex().?); |
| 18313 | try inlining.merges.src_locs.append(sema.gpa, operand_src); |
| 18314 | } else { |
| 18315 | try sema.validateRuntimeValue(block, operand_src, operand); |
| 18316 | const ret_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret; |
| 18317 | _ = try block.addUnOp(ret_tag, operand); |
| 18318 | } |
| 18295 | 18319 | } |
| 18296 | 18320 | |
| 18297 | 18321 | fn floatOpAllowed(tag: Zir.Inst.Tag) bool { |