Commit 64dddd7afe

Andrew Kelley <andrew@ziglang.org>
2019-03-24 00:33:00
add compile error for ignoring error
closes #772
1 parent 6a9c32f
doc/langref.html.in
@@ -3346,8 +3346,8 @@ fn deferErrorExample(is_error: bool) !void {
 }
 
 test "errdefer unwinding" {
-    _ = deferErrorExample(false);
-    _ = deferErrorExample(true);
+    deferErrorExample(false) catch {};
+    deferErrorExample(true) catch {};
 }
       {#code_end#}
       {#see_also|Errors#}
src/ir.cpp
@@ -13994,6 +13994,12 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source
     assert(ptr->value.type->id == ZigTypeIdPointer);
 
     if (ptr->value.data.x_ptr.special == ConstPtrSpecialDiscard) {
+        if (uncasted_value->value.type->id == ZigTypeIdErrorUnion ||
+            uncasted_value->value.type->id == ZigTypeIdErrorSet)
+        {
+            ir_add_error(ira, source_instr, buf_sprintf("error is discarded"));
+            return ira->codegen->invalid_instruction;
+        }
         return ir_const_void(ira, source_instr);
     }
 
src-self-hosted/codegen.zig
@@ -296,7 +296,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
         if (!param.typ.handleIsPtr()) {
             //clear_debug_source_node(g);
             const llvm_param = llvm.GetParam(llvm_fn, @intCast(c_uint, i));
-            _ = renderStoreUntyped(
+            _ = try renderStoreUntyped(
                 ofile,
                 llvm_param,
                 scope_var.data.Param.llvm_value,
src-self-hosted/ir.zig
@@ -1453,7 +1453,7 @@ pub const Builder = struct {
                 child_scope = decl_var.params.variable.child_scope;
             } else if (!is_continuation_unreachable) {
                 // this statement's value must be void
-                _ = irb.build(
+                _ = try irb.build(
                     Inst.CheckVoidStmt,
                     child_scope,
                     Span{
@@ -1887,7 +1887,7 @@ pub const Builder = struct {
     }
 
     fn genAsyncReturn(irb: *Builder, scope: *Scope, span: Span, result: *Inst, is_gen: bool) !*Inst {
-        _ = irb.buildGen(
+        _ = try irb.buildGen(
             Inst.AddImplicitReturnType,
             scope,
             span,
std/os/child_process.zig
@@ -802,7 +802,7 @@ fn destroyPipe(pipe: [2]i32) void {
 // Child of fork calls this to report an error to the fork parent.
 // Then the child exits.
 fn forkChildErrReport(fd: i32, err: ChildProcess.SpawnError) noreturn {
-    _ = writeIntFd(fd, ErrInt(@errorToInt(err)));
+    writeIntFd(fd, ErrInt(@errorToInt(err))) catch {};
     posix.exit(1);
 }
 
std/build.zig
@@ -282,7 +282,7 @@ pub const Builder = struct {
             if (self.verbose) {
                 warn("rm {}\n", installed_file);
             }
-            _ = os.deleteFile(installed_file);
+            os.deleteFile(installed_file) catch {};
         }
 
         // TODO remove empty directories
std/os.zig
@@ -807,7 +807,7 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
                 return switch (err) {
                     windows.ERROR.ENVVAR_NOT_FOUND => error.EnvironmentVariableNotFound,
                     else => {
-                        _ = unexpectedErrorWindows(err);
+                        unexpectedErrorWindows(err) catch {};
                         return error.EnvironmentVariableNotFound;
                     },
                 };
@@ -877,9 +877,9 @@ pub fn getCwd(out_buffer: *[MAX_PATH_BYTES]u8) GetCwdError![]u8 {
 
 test "os.getCwd" {
     // at least call it so it gets compiled
-    _ = getCwdAlloc(debug.global_allocator);
+    _ = getCwdAlloc(debug.global_allocator) catch undefined;
     var buf: [MAX_PATH_BYTES]u8 = undefined;
-    _ = getCwd(&buf);
+    _ = getCwd(&buf) catch undefined;
 }
 
 pub const SymLinkError = PosixSymLinkError || WindowsSymLinkError;
test/stage1/behavior/error.zig
@@ -205,8 +205,8 @@ fn foo2(f: fn () anyerror!void) void {
 fn bar2() (error{}!void) {}
 
 test "error: Zero sized error set returned with value payload crash" {
-    _ = foo3(0);
-    _ = comptime foo3(0);
+    _ = foo3(0) catch {};
+    _ = comptime foo3(0) catch {};
 }
 
 const Error = error{};
test/compile_errors.zig
@@ -2,6 +2,18 @@ const tests = @import("tests.zig");
 const builtin = @import("builtin");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "discarding error value",
+        \\export fn entry() void {
+        \\    _ = foo();
+        \\}
+        \\fn foo() !void {
+        \\    return error.OutOfMemory;
+        \\}
+    ,
+        "tmp.zig:2:7: error: error is discarded",
+    );
+
     cases.add(
         "volatile on global assembly",
         \\comptime {
test/runtime_safety.zig
@@ -370,7 +370,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
         \\    @import("std").os.exit(126);
         \\}
         \\pub fn main() void {
-        \\    _ = bar(9999);
+        \\    bar(9999) catch {};
         \\}
         \\fn bar(x: u16) anyerror {
         \\    return @intToError(x);
@@ -384,7 +384,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void {
         \\const Set1 = error{A, B};
         \\const Set2 = error{A, C};
         \\pub fn main() void {
-        \\    _ = foo(Set1.B);
+        \\    foo(Set1.B) catch {};
         \\}
         \\fn foo(set1: Set1) Set2 {
         \\    return @errSetCast(Set2, set1);