Commit 2cbad364c1

Andrew Kelley <superjoe30@gmail.com>
2018-07-27 00:29:07
add compile error for ignoring return value of while loop bodies
closes #1049
1 parent fd575fe
src/analyze.cpp
@@ -4056,7 +4056,7 @@ void analyze_fn_ir(CodeGen *g, FnTableEntry *fn_table_entry, AstNode *return_typ
     }
 
     if (g->verbose_ir) {
-        fprintf(stderr, "{ // (analyzed)\n");
+        fprintf(stderr, "fn %s() { // (analyzed)\n", buf_ptr(&fn_table_entry->symbol_name));
         ir_print(g, stderr, &fn_table_entry->analyzed_executable, 4);
         fprintf(stderr, "}\n");
     }
src/ir.cpp
@@ -5251,8 +5251,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
         if (body_result == irb->codegen->invalid_instruction)
             return body_result;
 
-        if (!instr_is_unreachable(body_result))
+        if (!instr_is_unreachable(body_result)) {
+            ir_mark_gen(ir_build_check_statement_is_void(irb, payload_scope, node->data.while_expr.body, body_result));
             ir_mark_gen(ir_build_br(irb, payload_scope, node, continue_block, is_comptime));
+        }
 
         if (continue_expr_node) {
             ir_set_cursor_at_end_and_append_block(irb, continue_block);
@@ -5331,8 +5333,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
         if (body_result == irb->codegen->invalid_instruction)
             return body_result;
 
-        if (!instr_is_unreachable(body_result))
+        if (!instr_is_unreachable(body_result)) {
+            ir_mark_gen(ir_build_check_statement_is_void(irb, child_scope, node->data.while_expr.body, body_result));
             ir_mark_gen(ir_build_br(irb, child_scope, node, continue_block, is_comptime));
+        }
 
         if (continue_expr_node) {
             ir_set_cursor_at_end_and_append_block(irb, continue_block);
@@ -5392,8 +5396,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
         if (body_result == irb->codegen->invalid_instruction)
             return body_result;
 
-        if (!instr_is_unreachable(body_result))
+        if (!instr_is_unreachable(body_result)) {
+            ir_mark_gen(ir_build_check_statement_is_void(irb, scope, node->data.while_expr.body, body_result));
             ir_mark_gen(ir_build_br(irb, scope, node, continue_block, is_comptime));
+        }
 
         if (continue_expr_node) {
             ir_set_cursor_at_end_and_append_block(irb, continue_block);
src/ir_print.cpp
@@ -45,6 +45,10 @@ static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) {
 }
 
 static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) {
+    if (instruction == nullptr) {
+        fprintf(irp->f, "(null)");
+        return;
+    }
     if (instruction->value.special != ConstValSpecialRuntime) {
         ir_print_const_value(irp, &instruction->value);
     } else {
test/compile_errors.zig
@@ -1,6 +1,28 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: *tests.CompileErrorContext) void {
+    cases.add(
+        "while loop body expression ignored",
+        \\fn returns() usize {
+        \\    return 2;
+        \\}
+        \\export fn f1() void {
+        \\    while (true) returns();
+        \\}
+        \\export fn f2() void {
+        \\    var x: ?i32 = null;
+        \\    while (x) |_| returns();
+        \\}
+        \\export fn f3() void {
+        \\    var x: error!i32 = error.Bad;
+        \\    while (x) |_| returns() else |_| unreachable;
+        \\}
+    ,
+        ".tmp_source.zig:5:25: error: expression value is ignored",
+        ".tmp_source.zig:9:26: error: expression value is ignored",
+        ".tmp_source.zig:13:26: error: expression value is ignored",
+    );
+
     cases.add(
         "missing parameter name of generic function",
         \\fn dump(var) void {}