diff --git a/src/AstGen.zig b/src/AstGen.zig index 7331ab6410..1d2244a5b5 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2463,6 +2463,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As .is_non_null_ptr, .is_non_err, .is_non_err_ptr, + .ret_is_non_err, .mod_rem, .mul, .mulwrap, @@ -7012,7 +7013,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref // Emit conditional branch for generating errdefers. const result = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand; - const is_non_err = try gz.addUnNode(.is_non_err, result, node); + const is_non_err = try gz.addUnNode(.ret_is_non_err, result, node); const condbr = try gz.addCondBr(.condbr, node); var then_scope = gz.makeSubBlock(scope); diff --git a/src/Sema.zig b/src/Sema.zig index 6fa2f92dd7..ec698f7a3b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -953,6 +953,7 @@ fn analyzeBodyInner( .int_type => try sema.zirIntType(block, inst), .is_non_err => try sema.zirIsNonErr(block, inst), .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), + .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), .is_non_null => try sema.zirIsNonNull(block, inst), .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), .merge_error_sets => try sema.zirMergeErrorSets(block, inst), @@ -10288,6 +10289,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError .ret_err_value_code, .restore_err_ret_index, .is_non_err, + .ret_is_non_err, .condbr, => {}, else => break, @@ -16577,7 +16579,7 @@ fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const src = inst_data.src(); const operand = try sema.resolveInst(inst_data.operand); try sema.checkErrorType(block, src, sema.typeOf(operand)); - return sema.analyzeIsNonErr(block, inst_data.src(), operand); + return sema.analyzeIsNonErr(block, src, operand); } fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -16592,6 +16594,16 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError return sema.analyzeIsNonErr(block, src, loaded); } +fn zirRetIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const tracy = trace(@src()); + defer tracy.end(); + + const inst_data = sema.code.instructions.items(.data)[inst].un_node; + const src = inst_data.src(); + const operand = try sema.resolveInst(inst_data.operand); + return sema.analyzeIsNonErr(block, src, operand); +} + fn zirCondbr( sema: *Sema, parent_block: *Block, diff --git a/src/Zir.zig b/src/Zir.zig index 3f2e935050..94e6a9a11a 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -481,6 +481,9 @@ pub const Inst = struct { /// Return a boolean false if dereferenced pointer is an error /// Uses the `un_node` field. is_non_err_ptr, + /// Same as `is_non_er` but doesn't validate that the type can be an error. + /// Uses the `un_node` field. + ret_is_non_err, /// A labeled block of code that loops forever. At the end of the body will have either /// a `repeat` instruction or a `repeat_inline` instruction. /// Uses the `pl_node` field. The AST node is either a for loop or while loop. @@ -1083,6 +1086,7 @@ pub const Inst = struct { .is_non_null_ptr, .is_non_err, .is_non_err_ptr, + .ret_is_non_err, .mod_rem, .mul, .mulwrap, @@ -1386,6 +1390,7 @@ pub const Inst = struct { .is_non_null_ptr, .is_non_err, .is_non_err_ptr, + .ret_is_non_err, .mod_rem, .mul, .mulwrap, @@ -1640,6 +1645,7 @@ pub const Inst = struct { .is_non_null_ptr = .un_node, .is_non_err = .un_node, .is_non_err_ptr = .un_node, + .ret_is_non_err = .un_node, .loop = .pl_node, .repeat = .node, .repeat_inline = .node, diff --git a/src/print_zir.zig b/src/print_zir.zig index 49c97a5bc7..6e8923bed9 100644 --- a/src/print_zir.zig +++ b/src/print_zir.zig @@ -179,6 +179,7 @@ const Writer = struct { .is_non_null_ptr, .is_non_err, .is_non_err_ptr, + .ret_is_non_err, .typeof, .struct_init_empty, .type_info, diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index 9b83290a0a..32f63b1a46 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -148,3 +148,14 @@ test "simple else prong doesn't emit an error for unreachable else prong" { }; try expect(a == 1); } + +test "errdefer used in function that doesn't return an error" { + const S = struct { + fn foo() u8 { + var a: u8 = 5; + errdefer a += 1; + return a; + } + }; + try expect(S.foo() == 5); +}