| ... | @@ -18034,28 +18034,24 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi | ... | @@ -18034,28 +18034,24 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi |
| 18034 | return sema.analyzeRet(block, operand, src, block.src(.{ .node_offset_return_operand = inst_data.src_node })); | 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 | const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr); | 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 | _ = try block.addUnOp(.ret_load, ret_ptr); | 18042 | _ = try block.addUnOp(.ret_load, ret_ptr); |
| 18043 | } | 18043 | } |
| 18044 | | 18044 | |
| 18045 | fn retWithErrTracing( | 18045 | fn maybePushErrorTrace( |
| 18046 | sema: *Sema, | 18046 | sema: *Sema, |
| 18047 | block: *Block, | 18047 | parent_block: *Block, |
| 18048 | src: LazySrcLoc, | 18048 | src: LazySrcLoc, |
| 18049 | is_non_err: Air.Inst.Ref, | 18049 | is_non_err: Air.Inst.Ref, |
| 18050 | ret_tag: Air.Inst.Tag, | | |
| 18051 | operand: Air.Inst.Ref, | | |
| 18052 | ) CompileError!void { | 18050 | ) CompileError!void { |
| 18053 | const pt = sema.pt; | 18051 | const pt = sema.pt; |
| | 18052 | |
| 18054 | const need_check = switch (is_non_err) { | 18053 | const need_check = switch (is_non_err) { |
| 18055 | .bool_true => { | 18054 | .bool_true => return, |
| 18056 | _ = try block.addUnOp(ret_tag, operand); | | |
| 18057 | return; | | |
| 18058 | }, | | |
| 18059 | .bool_false => false, | 18055 | .bool_false => false, |
| 18060 | else => true, | 18056 | else => true, |
| 18061 | }; | 18057 | }; |
| ... | @@ -18068,27 +18064,44 @@ fn retWithErrTracing( | ... | @@ -18068,27 +18064,44 @@ fn retWithErrTracing( |
| 18068 | const return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError)); | 18064 | const return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError)); |
| 18069 | | 18065 | |
| 18070 | if (!need_check) { | 18066 | if (!need_check) { |
| 18071 | try sema.callBuiltin(block, src, return_err_fn, .never_tail, &.{}, .@"error return"); | 18067 | try sema.callBuiltin(parent_block, src, return_err_fn, .never_tail, &.{}, .@"error return"); |
| 18072 | _ = try block.addUnOp(ret_tag, operand); | | |
| 18073 | return; | 18068 | return; |
| 18074 | } | 18069 | } |
| 18075 | | 18070 | |
| 18076 | var then_block = block.makeSubBlock(); | 18071 | var err_block = parent_block.makeSubBlock(); |
| 18077 | defer then_block.instructions.deinit(gpa); | 18072 | defer err_block.instructions.deinit(gpa); |
| 18078 | _ = try then_block.addUnOp(ret_tag, operand); | 18073 | try sema.callBuiltin(&err_block, src, return_err_fn, .never_tail, &.{}, .@"error return"); |
| 18079 | | 18074 | |
| 18080 | var else_block = block.makeSubBlock(); | 18075 | try parent_block.instructions.ensureUnusedCapacity(gpa, 1); |
| 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); | | |
| 18084 | | 18076 | |
| 18085 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len + | 18077 | try sema.air_instructions.ensureUnusedCapacity(gpa, 4); |
| 18086 | then_block.instructions.items.len + else_block.instructions.items.len + | 18078 | try sema.air_extra.ensureUnusedCapacity( |
| 18087 | @typeInfo(Air.Block).@"struct".fields.len + 1); | 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 | const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ | 18102 | const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{ |
| 18090 | .then_body_len = @intCast(then_block.instructions.items.len), | 18103 | .then_body_len = 1, |
| 18091 | .else_body_len = @intCast(else_block.instructions.items.len), | 18104 | .else_body_len = @intCast(err_block.instructions.items.len + 1), |
| 18092 | .branch_hints = .{ | 18105 | .branch_hints = .{ |
| 18093 | // Weight against error branch. | 18106 | // Weight against error branch. |
| 18094 | .true = .likely, | 18107 | .true = .likely, |
| ... | @@ -18098,19 +18111,33 @@ fn retWithErrTracing( | ... | @@ -18098,19 +18111,33 @@ fn retWithErrTracing( |
| 18098 | .else_cov = .none, | 18111 | .else_cov = .none, |
| 18099 | }, | 18112 | }, |
| 18100 | }); | 18113 | }); |
| 18101 | sema.air_extra.appendSliceAssumeCapacity(@ptrCast(then_block.instructions.items)); | 18114 | sema.air_extra.appendAssumeCapacity(@intFromEnum(then_br_inst)); |
| 18102 | sema.air_extra.appendSliceAssumeCapacity(@ptrCast(else_block.instructions.items)); | 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 = .{ | 18125 | const br_inst_data: Air.Inst = .{ |
| 18105 | .operand = is_non_err, | 18126 | .tag = .br, |
| 18106 | .payload = cond_br_payload, | 18127 | .data = .{ .br = .{ |
| 18107 | } } }); | 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 { | 18138 | fn wantErrorReturnTracing(sema: *Sema) bool { |
| 18111 | const pt = sema.pt; | 18139 | const zcu = sema.pt.zcu; |
| 18112 | const zcu = pt.zcu; | 18140 | return sema.fn_ret_ty.isError(zcu) and zcu.comp.config.any_error_tracing; |
| 18113 | return fn_ret_ty.isError(zcu) and zcu.comp.config.any_error_tracing; | | |
| 18114 | } | 18141 | } |
| 18115 | | 18142 | |
| 18116 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | 18143 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { |
| ... | @@ -18251,47 +18278,44 @@ fn analyzeRet( | ... | @@ -18251,47 +18278,44 @@ fn analyzeRet( |
| 18251 | else => |e| return e, | 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 | assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr | 18285 | assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr |
| 18256 | if (block.isComptime()) { | 18286 | const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); |
| 18257 | const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); | 18287 | inlining.comptime_result = operand; |
| 18258 | inlining.comptime_result = operand; | | |
| 18259 | | 18288 | |
| 18260 | if (sema.fn_ret_ty.isError(zcu) and ret_val.getErrorName(zcu) != .none) { | 18289 | if (sema.fn_ret_ty.isError(zcu) and ret_val.getErrorName(zcu) != .none) { |
| 18261 | try sema.comptime_err_ret_trace.append(src); | 18290 | try sema.comptime_err_ret_trace.append(src); |
| 18262 | } | | |
| 18263 | return error.ComptimeReturn; | | |
| 18264 | } | 18291 | } |
| 18265 | // We are inlining a function call; rewrite the `ret` as a `break`. | 18292 | return error.ComptimeReturn; |
| 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); | | |
| 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; | 18303 | if (sema.wantErrorReturnTracing()) { |
| 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. | | |
| 18290 | const is_non_err = try sema.analyzeIsNonErr(block, operand_src, operand); | 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 | fn floatOpAllowed(tag: Zir.Inst.Tag) bool { | 18321 | fn floatOpAllowed(tag: Zir.Inst.Tag) bool { |