authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-19 16:45:15-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-19 16:45:15-05:00
log09d50e35a4555d9af2c794390a4375c7fc0e48f7
tree14c3b6abf1c13eb763c31a0743a41b826e864e20
parent14422e0312b3df271bfb60e8a6233afb128354fc

IR: support error defers


4 files changed, 76 insertions(+), 26 deletions(-)

src/codegen.cpp+2-4
......@@ -2001,11 +2001,9 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
20012001}
20022002
20032003static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
2004 TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);
2005 TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
2004 TypeTableEntry *err_union_type = get_underlying_type(instruction->value->type_entry);
20062005 TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
2007 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);
2008 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type);
2006 LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
20092007
20102008 LLVMValueRef err_val;
20112009 if (type_has_bits(child_type)) {
src/ir.cpp+38-22
......@@ -1934,10 +1934,27 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
19341934 size_t defer_counts[3];
19351935 ir_count_defers(irb, scope, outer_scope, defer_counts);
19361936 if (defer_counts[ReturnKindError] > 0) {
1937 // TODO in this situation we need to make a conditional
1938 // branch on the return value. we potentially must make multiple conditional branches,
1939 // if unconditional defers are interleaved with error defers.
1940 zig_panic("TODO handle error defers");
1937 IrBasicBlock *err_block = ir_build_basic_block(irb, scope, "ErrRetErr");
1938 IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "ErrRetOk");
1939
1940 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
1941
1942 IrInstruction *is_comptime;
1943 if (ir_should_inline(irb)) {
1944 is_comptime = ir_build_const_bool(irb, scope, node, true);
1945 } else {
1946 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
1947 }
1948
1949 ir_build_cond_br(irb, scope, node, is_err, err_block, ok_block, is_comptime);
1950
1951 ir_set_cursor_at_end(irb, err_block);
1952 ir_gen_defers_for_block(irb, scope, outer_scope, true, false);
1953 ir_build_return(irb, scope, node, return_value);
1954
1955 ir_set_cursor_at_end(irb, ok_block);
1956 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
1957 return ir_build_return(irb, scope, node, return_value);
19411958 } else if (defer_counts[ReturnKindMaybe] > 0) {
19421959 // TODO in this situation we need to make a conditional
19431960 // branch on the maybe value. we potentially must make multiple conditional branches,
......@@ -1946,8 +1963,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
19461963 } else {
19471964 // generate unconditional defers
19481965 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
1966 return ir_build_return(irb, scope, node, return_value);
19491967 }
1950 return ir_build_return(irb, scope, node, return_value);
19511968 }
19521969 case ReturnKindError:
19531970 {
......@@ -1955,7 +1972,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
19551972 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
19561973 if (err_union_ptr == irb->codegen->invalid_instruction)
19571974 return irb->codegen->invalid_instruction;
1958 IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_ptr);
1975 IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr);
1976 IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val);
19591977
19601978 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn");
19611979 IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "ErrRetContinue");
......@@ -3932,7 +3950,8 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
39323950 if (err_union_ptr == irb->codegen->invalid_instruction)
39333951 return irb->codegen->invalid_instruction;
39343952
3935 IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_ptr);
3953 IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr);
3954 IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val);
39363955
39373956 IrInstruction *is_comptime;
39383957 if (ir_should_inline(irb)) {
......@@ -9443,26 +9462,20 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
94439462 if (value->type_entry->id == TypeTableEntryIdInvalid)
94449463 return ira->codegen->builtin_types.entry_invalid;
94459464
9446 TypeTableEntry *ptr_type = value->type_entry;
9447
9448 // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing.
9449 assert(ptr_type->id == TypeTableEntryIdPointer);
9465 TypeTableEntry *non_canon_type = value->type_entry;
94509466
9451 TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type;
94529467 TypeTableEntry *canon_type = get_underlying_type(non_canon_type);
94539468 if (canon_type->id == TypeTableEntryIdInvalid) {
94549469 return ira->codegen->builtin_types.entry_invalid;
94559470 } else if (canon_type->id == TypeTableEntryIdErrorUnion) {
94569471 if (instr_is_comptime(value)) {
9457 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);
9458 if (!ptr_val)
9472 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
9473 if (!err_union_val)
94599474 return ira->codegen->builtin_types.entry_invalid;
9460 ConstExprValue *err_union_val = ptr_val->data.x_ptr.base_ptr;
9461 assert(ptr_val->data.x_ptr.index == SIZE_MAX);
94629475
94639476 if (err_union_val->special != ConstValSpecialRuntime) {
9464 bool depends_on_compile_var = ptr_val->depends_on_compile_var || err_union_val->depends_on_compile_var;
9465 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
9477 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
9478 err_union_val->depends_on_compile_var);
94669479 out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);
94679480 return ira->codegen->builtin_types.entry_bool;
94689481 }
......@@ -9470,11 +9483,14 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
94709483
94719484 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
94729485 return ira->codegen->builtin_types.entry_bool;
9486 } else if (canon_type->id == TypeTableEntryIdPureError) {
9487 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
9488 out_val->data.x_bool = true;
9489 return ira->codegen->builtin_types.entry_bool;
94739490 } else {
9474 ir_add_error(ira, value,
9475 buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name)));
9476 // TODO if this is a typedecl, add error note showing the declaration of the type decl
9477 return ira->codegen->builtin_types.entry_invalid;
9491 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
9492 out_val->data.x_bool = false;
9493 return ira->codegen->builtin_types.entry_bool;
94789494 }
94799495}
94809496
test/cases3/defer.zig created+35
......@@ -0,0 +1,35 @@
1var result: [3]u8 = undefined;
2var index: usize = undefined;
3
4error FalseNotAllowed;
5
6fn runSomeDefers(x: bool) -> %bool {
7 index = 0;
8 defer {result[index] = 'a'; index += 1;};
9 %defer {result[index] = 'b'; index += 1;};
10 defer {result[index] = 'c'; index += 1;};
11 return if (x) x else error.FalseNotAllowed;
12}
13
14fn mixingNormalAndErrorDefers() {
15 @setFnTest(this);
16
17 assert(%%runSomeDefers(true));
18 assert(result[0] == 'c');
19 assert(result[1] == 'a');
20
21 const ok = runSomeDefers(false) %% |err| {
22 assert(err == error.FalseNotAllowed);
23 true
24 };
25 assert(ok);
26 assert(result[0] == 'c');
27 assert(result[1] == 'b');
28 assert(result[2] == 'a');
29}
30
31// TODO const assert = @import("std").debug.assert;
32fn assert(ok: bool) {
33 if (!ok)
34 @unreachable();
35}
test/self_hosted3.zig+1
......@@ -7,3 +7,4 @@ const test_atomics = @import("cases3/atomics.zig");
77const test_for = @import("cases3/for.zig");
88const test_math = @import("cases3/math.zig");
99const test_generics = @import("cases3/generics.zig");
10const test_defer = @import("cases3/defer.zig");