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,...@@ -2001,11 +2001,9 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable,
2001}2001}
20022002
2003static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {2003static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) {
2004 TypeTableEntry *ptr_type = get_underlying_type(instruction->value->type_entry);2004 TypeTableEntry *err_union_type = get_underlying_type(instruction->value->type_entry);
2005 TypeTableEntry *err_union_type = get_underlying_type(ptr_type->data.pointer.child_type);
2006 TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);2005 TypeTableEntry *child_type = get_underlying_type(err_union_type->data.error.child_type);
2007 LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->value);2006 LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value);
2008 LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type);
20092007
2010 LLVMValueRef err_val;2008 LLVMValueRef err_val;
2011 if (type_has_bits(child_type)) {2009 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,...@@ -1934,10 +1934,27 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
1934 size_t defer_counts[3];1934 size_t defer_counts[3];
1935 ir_count_defers(irb, scope, outer_scope, defer_counts);1935 ir_count_defers(irb, scope, outer_scope, defer_counts);
1936 if (defer_counts[ReturnKindError] > 0) {1936 if (defer_counts[ReturnKindError] > 0) {
1937 // TODO in this situation we need to make a conditional1937 IrBasicBlock *err_block = ir_build_basic_block(irb, scope, "ErrRetErr");
1938 // branch on the return value. we potentially must make multiple conditional branches,1938 IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "ErrRetOk");
1939 // if unconditional defers are interleaved with error defers.1939
1940 zig_panic("TODO handle error defers");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);
1941 } else if (defer_counts[ReturnKindMaybe] > 0) {1958 } else if (defer_counts[ReturnKindMaybe] > 0) {
1942 // TODO in this situation we need to make a conditional1959 // TODO in this situation we need to make a conditional
1943 // branch on the maybe value. we potentially must make multiple conditional branches,1960 // 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,...@@ -1946,8 +1963,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
1946 } else {1963 } else {
1947 // generate unconditional defers1964 // generate unconditional defers
1948 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);1965 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
1966 return ir_build_return(irb, scope, node, return_value);
1949 }1967 }
1950 return ir_build_return(irb, scope, node, return_value);
1951 }1968 }
1952 case ReturnKindError:1969 case ReturnKindError:
1953 {1970 {
...@@ -1955,7 +1972,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -1955,7 +1972,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
1955 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);1972 IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
1956 if (err_union_ptr == irb->codegen->invalid_instruction)1973 if (err_union_ptr == irb->codegen->invalid_instruction)
1957 return irb->codegen->invalid_instruction;1974 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
1960 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn");1978 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "ErrRetReturn");
1961 IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "ErrRetContinue");1979 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...@@ -3932,7 +3950,8 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN
3932 if (err_union_ptr == irb->codegen->invalid_instruction)3950 if (err_union_ptr == irb->codegen->invalid_instruction)
3933 return irb->codegen->invalid_instruction;3951 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
3937 IrInstruction *is_comptime;3956 IrInstruction *is_comptime;
3938 if (ir_should_inline(irb)) {3957 if (ir_should_inline(irb)) {
...@@ -9443,26 +9462,20 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc...@@ -9443,26 +9462,20 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
9443 if (value->type_entry->id == TypeTableEntryIdInvalid)9462 if (value->type_entry->id == TypeTableEntryIdInvalid)
9444 return ira->codegen->builtin_types.entry_invalid;9463 return ira->codegen->builtin_types.entry_invalid;
94459464
9446 TypeTableEntry *ptr_type = value->type_entry;9465 TypeTableEntry *non_canon_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);
94509466
9451 TypeTableEntry *non_canon_type = ptr_type->data.pointer.child_type;
9452 TypeTableEntry *canon_type = get_underlying_type(non_canon_type);9467 TypeTableEntry *canon_type = get_underlying_type(non_canon_type);
9453 if (canon_type->id == TypeTableEntryIdInvalid) {9468 if (canon_type->id == TypeTableEntryIdInvalid) {
9454 return ira->codegen->builtin_types.entry_invalid;9469 return ira->codegen->builtin_types.entry_invalid;
9455 } else if (canon_type->id == TypeTableEntryIdErrorUnion) {9470 } else if (canon_type->id == TypeTableEntryIdErrorUnion) {
9456 if (instr_is_comptime(value)) {9471 if (instr_is_comptime(value)) {
9457 ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad);9472 ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
9458 if (!ptr_val)9473 if (!err_union_val)
9459 return ira->codegen->builtin_types.entry_invalid;9474 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
9463 if (err_union_val->special != ConstValSpecialRuntime) {9476 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;9477 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
9465 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);9478 err_union_val->depends_on_compile_var);
9466 out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);9479 out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);
9467 return ira->codegen->builtin_types.entry_bool;9480 return ira->codegen->builtin_types.entry_bool;
9468 }9481 }
...@@ -9470,11 +9483,14 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc...@@ -9470,11 +9483,14 @@ static TypeTableEntry *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruc
94709483
9471 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);9484 ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
9472 return ira->codegen->builtin_types.entry_bool;9485 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;
9473 } else {9490 } else {
9474 ir_add_error(ira, value,9491 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
9475 buf_sprintf("expected error union type, found '%s'", buf_ptr(&non_canon_type->name)));9492 out_val->data.x_bool = false;
9476 // TODO if this is a typedecl, add error note showing the declaration of the type decl9493 return ira->codegen->builtin_types.entry_bool;
9477 return ira->codegen->builtin_types.entry_invalid;
9478 }9494 }
9479}9495}
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");...@@ -7,3 +7,4 @@ const test_atomics = @import("cases3/atomics.zig");
7const test_for = @import("cases3/for.zig");7const test_for = @import("cases3/for.zig");
8const test_math = @import("cases3/math.zig");8const test_math = @import("cases3/math.zig");
9const test_generics = @import("cases3/generics.zig");9const test_generics = @import("cases3/generics.zig");
10const test_defer = @import("cases3/defer.zig");