Commit 83673a8b5f

Veikka Tuominen <git@vexu.eu>
2023-01-06 18:03:40
fix errdefers in functions that can't return errors
This was broken by 58caed1c71179f48c4e7bffadef0392fa8381e72 Closes #14053
1 parent fd6b79e
Changed files (5)
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);
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,
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,
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,
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);
+}