authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-19 17:25:09-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-19 17:25:09-05:00
log2419f0c91436106f85ea8b6ec183cdaea438a1d0
tree18c4d72142c50137fff9ace7f8a2139ed2ff6aec
parent09d50e35a4555d9af2c794390a4375c7fc0e48f7

IR: support maybe defers


5 files changed, 107 insertions(+), 73 deletions(-)

src/all_types.hpp+2-2
...@@ -1410,7 +1410,7 @@ enum IrInstructionId {...@@ -1410,7 +1410,7 @@ enum IrInstructionId {
1410 IrInstructionIdAsm,1410 IrInstructionIdAsm,
1411 IrInstructionIdCompileVar,1411 IrInstructionIdCompileVar,
1412 IrInstructionIdSizeOf,1412 IrInstructionIdSizeOf,
1413 IrInstructionIdTestNull,1413 IrInstructionIdTestNonNull,
1414 IrInstructionIdUnwrapMaybe,1414 IrInstructionIdUnwrapMaybe,
1415 IrInstructionIdMaybeWrap,1415 IrInstructionIdMaybeWrap,
1416 IrInstructionIdEnumTag,1416 IrInstructionIdEnumTag,
...@@ -1787,7 +1787,7 @@ struct IrInstructionSizeOf {...@@ -1787,7 +1787,7 @@ struct IrInstructionSizeOf {
17871787
1788// returns true if nonnull, returns false if null1788// returns true if nonnull, returns false if null
1789// this is so that `zeroes` sets maybe values to null1789// this is so that `zeroes` sets maybe values to null
1790struct IrInstructionTestNull {1790struct IrInstructionTestNonNull {
1791 IrInstruction base;1791 IrInstruction base;
17921792
1793 IrInstruction *value;1793 IrInstruction *value;
src/codegen.cpp+13-18
...@@ -1554,26 +1554,20 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru...@@ -1554,26 +1554,20 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
1554 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");1554 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
1555}1555}
15561556
1557// 0 - null, 1 - non null1557static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) {
1558static LLVMValueRef gen_null_bit(CodeGen *g, TypeTableEntry *ptr_type, LLVMValueRef maybe_ptr) {1558 bool maybe_is_ptr = (maybe_type->id == TypeTableEntryIdPointer || maybe_type->id == TypeTableEntryIdFn);
1559 assert(ptr_type->id == TypeTableEntryIdPointer);
1560 TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type;
1561 assert(maybe_type->id == TypeTableEntryIdMaybe);
1562 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1563 LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type);
1564 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1565 if (maybe_is_ptr) {1559 if (maybe_is_ptr) {
1566 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref, LLVMConstNull(child_type->type_ref), "");1560 return LLVMBuildICmp(g->builder, LLVMIntNE, maybe_handle, LLVMConstNull(maybe_type->type_ref), "");
1567 } else {1561 } else {
1568 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_null_index, "");1562 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_handle, maybe_null_index, "");
1569 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");1563 return LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1570 }1564 }
1571}1565}
15721566
1573static LLVMValueRef ir_render_test_null(CodeGen *g, IrExecutable *executable, IrInstructionTestNull *instruction) {1567static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable,
1574 TypeTableEntry *ptr_type = instruction->value->type_entry;1568 IrInstructionTestNonNull *instruction)
1575 assert(ptr_type->id == TypeTableEntryIdPointer);1569{
1576 return gen_null_bit(g, ptr_type, ir_llvm_value(g, instruction->value));1570 return gen_non_null_bit(g, instruction->value->type_entry, ir_llvm_value(g, instruction->value));
1577}1571}
15781572
1579static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,1573static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
...@@ -1586,11 +1580,12 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,...@@ -1586,11 +1580,12 @@ static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable,
1586 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;1580 TypeTableEntry *child_type = maybe_type->data.maybe.child_type;
1587 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);1581 bool maybe_is_ptr = (child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn);
1588 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);1582 LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value);
1583 LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type);
1589 if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {1584 if (ir_want_debug_safety(g, &instruction->base) && instruction->safety_check_on) {
1590 LLVMValueRef nonnull_bit = gen_null_bit(g, ptr_type, maybe_ptr);1585 LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle);
1591 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");1586 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk");
1592 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");1587 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail");
1593 LLVMBuildCondBr(g->builder, nonnull_bit, ok_block, fail_block);1588 LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block);
15941589
1595 LLVMPositionBuilderAtEnd(g->builder, fail_block);1590 LLVMPositionBuilderAtEnd(g->builder, fail_block);
1596 gen_debug_safety_crash(g);1591 gen_debug_safety_crash(g);
...@@ -2227,8 +2222,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2227,8 +2222,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2227 return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);2222 return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
2228 case IrInstructionIdAsm:2223 case IrInstructionIdAsm:
2229 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);2224 return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
2230 case IrInstructionIdTestNull:2225 case IrInstructionIdTestNonNull:
2231 return ir_render_test_null(g, executable, (IrInstructionTestNull *)instruction);2226 return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
2232 case IrInstructionIdUnwrapMaybe:2227 case IrInstructionIdUnwrapMaybe:
2233 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);2228 return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction);
2234 case IrInstructionIdClz:2229 case IrInstructionIdClz:
src/ir.cpp+64-47
...@@ -275,8 +275,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {...@@ -275,8 +275,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
275 return IrInstructionIdSizeOf;275 return IrInstructionIdSizeOf;
276}276}
277277
278static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNull *) {278static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) {
279 return IrInstructionIdTestNull;279 return IrInstructionIdTestNonNull;
280}280}
281281
282static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) {282static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) {
...@@ -1200,7 +1200,7 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *so...@@ -1200,7 +1200,7 @@ static IrInstruction *ir_build_size_of(IrBuilder *irb, Scope *scope, AstNode *so
1200}1200}
12011201
1202static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {1202static IrInstruction *ir_build_test_null(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
1203 IrInstructionTestNull *instruction = ir_build_instruction<IrInstructionTestNull>(irb, scope, source_node);1203 IrInstructionTestNonNull *instruction = ir_build_instruction<IrInstructionTestNonNull>(irb, scope, source_node);
1204 instruction->value = value;1204 instruction->value = value;
12051205
1206 ir_ref_instruction(value);1206 ir_ref_instruction(value);
...@@ -1956,10 +1956,27 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -1956,10 +1956,27 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
1956 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);1956 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
1957 return ir_build_return(irb, scope, node, return_value);1957 return ir_build_return(irb, scope, node, return_value);
1958 } else if (defer_counts[ReturnKindMaybe] > 0) {1958 } else if (defer_counts[ReturnKindMaybe] > 0) {
1959 // TODO in this situation we need to make a conditional1959 IrBasicBlock *null_block = ir_build_basic_block(irb, scope, "MaybeRetNull");
1960 // branch on the maybe value. we potentially must make multiple conditional branches,1960 IrBasicBlock *ok_block = ir_build_basic_block(irb, scope, "MaybeRetOk");
1961 // if unconditional defers are interleaved with error defers.1961
1962 zig_panic("TODO handle maybe defers");1962 IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, return_value);
1963
1964 IrInstruction *is_comptime;
1965 if (ir_should_inline(irb)) {
1966 is_comptime = ir_build_const_bool(irb, scope, node, true);
1967 } else {
1968 is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
1969 }
1970
1971 ir_build_cond_br(irb, scope, node, is_non_null, ok_block, null_block, is_comptime);
1972
1973 ir_set_cursor_at_end(irb, null_block);
1974 ir_gen_defers_for_block(irb, scope, outer_scope, false, true);
1975 ir_build_return(irb, scope, node, return_value);
1976
1977 ir_set_cursor_at_end(irb, ok_block);
1978 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
1979 return ir_build_return(irb, scope, node, return_value);
1963 } else {1980 } else {
1964 // generate unconditional defers1981 // generate unconditional defers
1965 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);1982 ir_gen_defers_for_block(irb, scope, outer_scope, false, false);
...@@ -1998,12 +2015,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -1998,12 +2015,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
1998 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);2015 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
1999 if (maybe_val_ptr == irb->codegen->invalid_instruction)2016 if (maybe_val_ptr == irb->codegen->invalid_instruction)
2000 return irb->codegen->invalid_instruction;2017 return irb->codegen->invalid_instruction;
2001 IrInstruction *is_nonnull_val = ir_build_test_null(irb, scope, node, maybe_val_ptr);2018 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
2019 IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, maybe_val);
20022020
2003 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn");2021 IrBasicBlock *return_block = ir_build_basic_block(irb, scope, "MaybeRetReturn");
2004 IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue");2022 IrBasicBlock *continue_block = ir_build_basic_block(irb, scope, "MaybeRetContinue");
2005 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb));2023 IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, ir_should_inline(irb));
2006 ir_build_cond_br(irb, scope, node, is_nonnull_val, continue_block, return_block, is_comptime);2024 ir_build_cond_br(irb, scope, node, is_non_null, continue_block, return_block, is_comptime);
20072025
2008 ir_set_cursor_at_end(irb, return_block);2026 ir_set_cursor_at_end(irb, return_block);
2009 ir_gen_defers_for_block(irb, scope, outer_scope, false, true);2027 ir_gen_defers_for_block(irb, scope, outer_scope, false, true);
...@@ -2247,7 +2265,8 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As...@@ -2247,7 +2265,8 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As
2247 if (maybe_ptr == irb->codegen->invalid_instruction)2265 if (maybe_ptr == irb->codegen->invalid_instruction)
2248 return irb->codegen->invalid_instruction;2266 return irb->codegen->invalid_instruction;
22492267
2250 IrInstruction *is_non_null = ir_build_test_null(irb, parent_scope, node, maybe_ptr);2268 IrInstruction *maybe_val = ir_build_load_ptr(irb, parent_scope, node, maybe_ptr);
2269 IrInstruction *is_non_null = ir_build_test_null(irb, parent_scope, node, maybe_val);
22512270
2252 IrInstruction *is_comptime;2271 IrInstruction *is_comptime;
2253 if (ir_should_inline(irb)) {2272 if (ir_should_inline(irb)) {
...@@ -3514,11 +3533,12 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -3514,11 +3533,12 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
3514 AstNode *else_node = node->data.if_var_expr.else_node;3533 AstNode *else_node = node->data.if_var_expr.else_node;
3515 bool var_is_ptr = node->data.if_var_expr.var_is_ptr;3534 bool var_is_ptr = node->data.if_var_expr.var_is_ptr;
35163535
3517 IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);3536 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPurposeAddressOf);
3518 if (expr_value == irb->codegen->invalid_instruction)3537 if (maybe_val_ptr == irb->codegen->invalid_instruction)
3519 return expr_value;3538 return maybe_val_ptr;
35203539
3521 IrInstruction *is_nonnull_value = ir_build_test_null(irb, scope, node, expr_value);3540 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr);
3541 IrInstruction *is_non_null = ir_build_test_null(irb, scope, node, maybe_val);
35223542
3523 IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen");3543 IrBasicBlock *then_block = ir_build_basic_block(irb, scope, "MaybeThen");
3524 IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse");3544 IrBasicBlock *else_block = ir_build_basic_block(irb, scope, "MaybeElse");
...@@ -3528,9 +3548,9 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -3528,9 +3548,9 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
3528 if (ir_should_inline(irb) || node->data.if_var_expr.is_inline) {3548 if (ir_should_inline(irb) || node->data.if_var_expr.is_inline) {
3529 is_comptime = ir_build_const_bool(irb, scope, node, true);3549 is_comptime = ir_build_const_bool(irb, scope, node, true);
3530 } else {3550 } else {
3531 is_comptime = ir_build_test_comptime(irb, scope, node, is_nonnull_value);3551 is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null);
3532 }3552 }
3533 ir_build_cond_br(irb, scope, node, is_nonnull_value, then_block, else_block, is_comptime);3553 ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime);
35343554
3535 ir_set_cursor_at_end(irb, then_block);3555 ir_set_cursor_at_end(irb, then_block);
3536 IrInstruction *var_type = nullptr;3556 IrInstruction *var_type = nullptr;
...@@ -3544,7 +3564,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -3544,7 +3564,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, Scope *scope, AstNode *
3544 VariableTableEntry *var = ir_create_var(irb, node, scope,3564 VariableTableEntry *var = ir_create_var(irb, node, scope,
3545 var_decl->symbol, is_const, is_const, is_shadowable, is_comptime);3565 var_decl->symbol, is_const, is_const, is_shadowable, is_comptime);
35463566
3547 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, expr_value, false);3567 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false);
3548 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);3568 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);
3549 ir_build_var_decl(irb, scope, node, var, var_type, var_value);3569 ir_build_var_decl(irb, scope, node, var, var_type, var_value);
3550 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var->child_scope);3570 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var->child_scope);
...@@ -4440,7 +4460,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,...@@ -4440,7 +4460,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
4440 }4460 }
44414461
4442 // implicitly take a const pointer to something4462 // implicitly take a const pointer to something
4443 {4463 if (!type_requires_comptime(actual_type)) {
4444 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);4464 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
4445 if (types_match_const_cast_only(expected_type, const_ptr_actual)) {4465 if (types_match_const_cast_only(expected_type, const_ptr_actual)) {
4446 return ImplicitCastMatchResultYes;4466 return ImplicitCastMatchResultYes;
...@@ -5230,7 +5250,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -5230,7 +5250,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
5230 }5250 }
52315251
5232 // explicit cast from something to const pointer of it5252 // explicit cast from something to const pointer of it
5233 {5253 if (!type_requires_comptime(actual_type)) {
5234 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);5254 TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
5235 if (types_match_const_cast_only(wanted_type, const_ptr_actual)) {5255 if (types_match_const_cast_only(wanted_type, const_ptr_actual)) {
5236 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);5256 return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
...@@ -7763,39 +7783,36 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,...@@ -7763,39 +7783,36 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
7763 zig_unreachable();7783 zig_unreachable();
7764}7784}
77657785
7766static TypeTableEntry *ir_analyze_instruction_test_null(IrAnalyze *ira,7786static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrInstructionTestNonNull *instruction) {
7767 IrInstructionTestNull *test_null_instruction)7787 IrInstruction *value = instruction->value->other;
7768{
7769 IrInstruction *value = test_null_instruction->value->other;
7770 if (value->type_entry->id == TypeTableEntryIdInvalid)7788 if (value->type_entry->id == TypeTableEntryIdInvalid)
7771 return ira->codegen->builtin_types.entry_invalid;7789 return ira->codegen->builtin_types.entry_invalid;
77727790
7773 // This will be a pointer type because test null IR instruction operates on a pointer to a thing.7791 TypeTableEntry *type_entry = value->type_entry;
7774 TypeTableEntry *ptr_type = value->type_entry;
7775 assert(ptr_type->id == TypeTableEntryIdPointer);
7776
7777 TypeTableEntry *type_entry = ptr_type->data.pointer.child_type;
7778 if (type_entry->id != TypeTableEntryIdMaybe) {
7779 add_node_error(ira->codegen, test_null_instruction->base.source_node,
7780 buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name)));
7781 return ira->codegen->builtin_types.entry_invalid;
7782 }
77837792
7784 if (value->static_value.special != ConstValSpecialRuntime) {7793 if (type_entry->id == TypeTableEntryIdMaybe) {
7785 ConstExprValue *maybe_val = value->static_value.data.x_ptr.base_ptr;7794 if (instr_is_comptime(value)) {
7786 assert(value->static_value.data.x_ptr.index == SIZE_MAX);7795 ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefBad);
7796 if (!maybe_val)
7797 return ira->codegen->builtin_types.entry_invalid;
77877798
7788 if (maybe_val->special != ConstValSpecialRuntime) {7799 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
7789 bool depends_on_compile_var = maybe_val->depends_on_compile_var;7800 maybe_val->depends_on_compile_var);
7790 ConstExprValue *out_val = ir_build_const_from(ira, &test_null_instruction->base,7801 out_val->data.x_bool = (maybe_val->data.x_maybe != nullptr);
7791 depends_on_compile_var);
7792 out_val->data.x_bool = (maybe_val->data.x_maybe == nullptr);
7793 return ira->codegen->builtin_types.entry_bool;7802 return ira->codegen->builtin_types.entry_bool;
7794 }7803 }
7795 }
77967804
7797 ir_build_test_null_from(&ira->new_irb, &test_null_instruction->base, value);7805 ir_build_test_null_from(&ira->new_irb, &instruction->base, value);
7798 return ira->codegen->builtin_types.entry_bool;7806 return ira->codegen->builtin_types.entry_bool;
7807 } else if (type_entry->id == TypeTableEntryIdNullLit) {
7808 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
7809 out_val->data.x_bool = false;
7810 return ira->codegen->builtin_types.entry_bool;
7811 } else {
7812 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, false);
7813 out_val->data.x_bool = true;
7814 return ira->codegen->builtin_types.entry_bool;
7815 }
7799}7816}
78007817
7801static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,7818static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira,
...@@ -9689,8 +9706,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -9689,8 +9706,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
9689 return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);9706 return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
9690 case IrInstructionIdSizeOf:9707 case IrInstructionIdSizeOf:
9691 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);9708 return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction);
9692 case IrInstructionIdTestNull:9709 case IrInstructionIdTestNonNull:
9693 return ir_analyze_instruction_test_null(ira, (IrInstructionTestNull *)instruction);9710 return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction);
9694 case IrInstructionIdUnwrapMaybe:9711 case IrInstructionIdUnwrapMaybe:
9695 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction);9712 return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction);
9696 case IrInstructionIdClz:9713 case IrInstructionIdClz:
...@@ -9908,7 +9925,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -9908,7 +9925,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
9908 case IrInstructionIdSliceType:9925 case IrInstructionIdSliceType:
9909 case IrInstructionIdCompileVar:9926 case IrInstructionIdCompileVar:
9910 case IrInstructionIdSizeOf:9927 case IrInstructionIdSizeOf:
9911 case IrInstructionIdTestNull:9928 case IrInstructionIdTestNonNull:
9912 case IrInstructionIdUnwrapMaybe:9929 case IrInstructionIdUnwrapMaybe:
9913 case IrInstructionIdClz:9930 case IrInstructionIdClz:
9914 case IrInstructionIdCtz:9931 case IrInstructionIdCtz:
src/ir_print.cpp+3-3
...@@ -579,7 +579,7 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {...@@ -579,7 +579,7 @@ static void ir_print_size_of(IrPrint *irp, IrInstructionSizeOf *instruction) {
579 fprintf(irp->f, ")");579 fprintf(irp->f, ")");
580}580}
581581
582static void ir_print_test_null(IrPrint *irp, IrInstructionTestNull *instruction) {582static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instruction) {
583 fprintf(irp->f, "*");583 fprintf(irp->f, "*");
584 ir_print_other_instruction(irp, instruction->value);584 ir_print_other_instruction(irp, instruction->value);
585 fprintf(irp->f, " != null");585 fprintf(irp->f, " != null");
...@@ -1012,8 +1012,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1012,8 +1012,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1012 case IrInstructionIdSizeOf:1012 case IrInstructionIdSizeOf:
1013 ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);1013 ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
1014 break;1014 break;
1015 case IrInstructionIdTestNull:1015 case IrInstructionIdTestNonNull:
1016 ir_print_test_null(irp, (IrInstructionTestNull *)instruction);1016 ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction);
1017 break;1017 break;
1018 case IrInstructionIdUnwrapMaybe:1018 case IrInstructionIdUnwrapMaybe:
1019 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);1019 ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction);
test/cases3/defer.zig+25-3
...@@ -3,7 +3,7 @@ var index: usize = undefined;...@@ -3,7 +3,7 @@ var index: usize = undefined;
33
4error FalseNotAllowed;4error FalseNotAllowed;
55
6fn runSomeDefers(x: bool) -> %bool {6fn runSomeErrorDefers(x: bool) -> %bool {
7 index = 0;7 index = 0;
8 defer {result[index] = 'a'; index += 1;};8 defer {result[index] = 'a'; index += 1;};
9 %defer {result[index] = 'b'; index += 1;};9 %defer {result[index] = 'b'; index += 1;};
...@@ -11,14 +11,22 @@ fn runSomeDefers(x: bool) -> %bool {...@@ -11,14 +11,22 @@ fn runSomeDefers(x: bool) -> %bool {
11 return if (x) x else error.FalseNotAllowed;11 return if (x) x else error.FalseNotAllowed;
12}12}
1313
14fn runSomeMaybeDefers(x: bool) -> ?bool {
15 index = 0;
16 defer {result[index] = 'a'; index += 1;};
17 ?defer {result[index] = 'b'; index += 1;};
18 defer {result[index] = 'c'; index += 1;};
19 return if (x) x else null;
20}
21
14fn mixingNormalAndErrorDefers() {22fn mixingNormalAndErrorDefers() {
15 @setFnTest(this);23 @setFnTest(this);
1624
17 assert(%%runSomeDefers(true));25 assert(%%runSomeErrorDefers(true));
18 assert(result[0] == 'c');26 assert(result[0] == 'c');
19 assert(result[1] == 'a');27 assert(result[1] == 'a');
2028
21 const ok = runSomeDefers(false) %% |err| {29 const ok = runSomeErrorDefers(false) %% |err| {
22 assert(err == error.FalseNotAllowed);30 assert(err == error.FalseNotAllowed);
23 true31 true
24 };32 };
...@@ -28,6 +36,20 @@ fn mixingNormalAndErrorDefers() {...@@ -28,6 +36,20 @@ fn mixingNormalAndErrorDefers() {
28 assert(result[2] == 'a');36 assert(result[2] == 'a');
29}37}
3038
39fn mixingNormalAndMaybeDefers() {
40 @setFnTest(this);
41
42 assert(??runSomeMaybeDefers(true));
43 assert(result[0] == 'c');
44 assert(result[1] == 'a');
45
46 const ok = runSomeMaybeDefers(false) ?? true;
47 assert(ok);
48 assert(result[0] == 'c');
49 assert(result[1] == 'b');
50 assert(result[2] == 'a');
51}
52
31// TODO const assert = @import("std").debug.assert;53// TODO const assert = @import("std").debug.assert;
32fn assert(ok: bool) {54fn assert(ok: bool) {
33 if (!ok)55 if (!ok)