From 598170756cd91b6f300921d256baa72141ec3098 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 7 Jan 2018 18:12:56 -0500 Subject: [PATCH] `a catch unreachable` generates unwrap-error code See #545 See #510 See #632 --- src/ir.cpp | 24 +++++++++++++++++------- test/debug_safety.zig | 7 +++++-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 45fcb36101..826015c4ad 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3898,22 +3898,21 @@ static IrInstruction *ir_gen_address_of(IrBuilder *irb, Scope *scope, AstNode *n align_value, bit_offset_start, bit_offset_end); } -static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { - assert(node->type == NodeTypePrefixOpExpr); - AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - +static IrInstruction *ir_gen_err_assert_ok(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, + LVal lval) +{ IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LVAL_PTR); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, true); + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true); if (payload_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; if (lval.is_ptr) return payload_ptr; - return ir_build_load_ptr(irb, scope, node, payload_ptr); + return ir_build_load_ptr(irb, scope, source_node, payload_ptr); } static IrInstruction *ir_gen_maybe_assert_ok(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { @@ -3965,7 +3964,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod case PrefixOpError: return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpError), lval); case PrefixOpUnwrapError: - return ir_gen_err_assert_ok(irb, scope, node, lval); + return ir_gen_err_assert_ok(irb, scope, node, node->data.prefix_op_expr.primary_expr, lval); case PrefixOpUnwrapMaybe: return ir_gen_maybe_assert_ok(irb, scope, node, lval); } @@ -5181,6 +5180,17 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN AstNode *op2_node = node->data.unwrap_err_expr.op2; AstNode *var_node = node->data.unwrap_err_expr.symbol; + if (op2_node->type == NodeTypeUnreachable) { + if (var_node != nullptr) { + assert(var_node->type == NodeTypeSymbol); + Buf *var_name = var_node->data.symbol_expr.symbol; + add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); + return irb->codegen->invalid_instruction; + } + return ir_gen_err_assert_ok(irb, parent_scope, node, op1_node, LVAL_NONE); + } + + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LVAL_PTR); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; diff --git a/test/debug_safety.zig b/test/debug_safety.zig index 58ebf838b0..fde5b061ee 100644 --- a/test/debug_safety.zig +++ b/test/debug_safety.zig @@ -221,11 +221,14 @@ pub fn addCases(cases: &tests.CompareOutputContext) { cases.addDebugSafety("unwrap error", \\pub fn panic(message: []const u8) -> noreturn { - \\ @import("std").os.exit(126); + \\ if (@import("std").mem.eql(u8, message, "attempt to unwrap error: Whatever")) { + \\ @import("std").os.exit(126); // good + \\ } + \\ @import("std").os.exit(0); // test failed \\} \\error Whatever; \\pub fn main() -> %void { - \\ %%bar(); + \\ bar() catch unreachable; \\} \\fn bar() -> %void { \\ return error.Whatever;