@@ -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,
0 commit comments