Skip to content

Commit

Permalink
a catch unreachable generates unwrap-error code
Browse files Browse the repository at this point in the history
See #545
See #510
See #632
  • Loading branch information
andrewrk committed Jan 7, 2018
1 parent 632d143 commit 5981707
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 9 deletions.
24 changes: 17 additions & 7 deletions src/ir.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 5 additions & 2 deletions test/debug_safety.zig
Expand Up @@ -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;
Expand Down

0 comments on commit 5981707

Please sign in to comment.