| ... | ... | @@ -5998,22 +5998,55 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref |
| 5998 | 5998 | if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{}); |
| 5999 | 5999 | |
| 6000 | 6000 | const operand_node = node_datas[node].lhs; |
| 6001 | | if (operand_node != 0) { |
| 6002 | | const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{ |
| 6003 | | .ptr = try gz.addNodeExtended(.ret_ptr, node), |
| 6004 | | } else .{ |
| 6005 | | .ty = try gz.addNodeExtended(.ret_type, node), |
| 6006 | | }; |
| 6007 | | const operand = try expr(gz, scope, rl, operand_node); |
| 6008 | | // TODO check operand to see if we need to generate errdefers |
| 6001 | if (operand_node == 0) { |
| 6002 | // Returning a void value; skip error defers. |
| 6009 | 6003 | try genDefers(gz, &astgen.fn_block.?.base, scope, .none); |
| 6010 | | _ = try gz.addUnNode(.ret_node, operand, node); |
| 6004 | _ = try gz.addUnNode(.ret_node, .void_value, node); |
| 6011 | 6005 | return Zir.Inst.Ref.unreachable_value; |
| 6012 | 6006 | } |
| 6013 | | // Returning a void value; skip error defers. |
| 6014 | | try genDefers(gz, &astgen.fn_block.?.base, scope, .none); |
| 6015 | | _ = try gz.addUnNode(.ret_node, .void_value, node); |
| 6016 | | return Zir.Inst.Ref.unreachable_value; |
| 6007 | |
| 6008 | const rl: ResultLoc = if (nodeMayNeedMemoryLocation(tree, operand_node)) .{ |
| 6009 | .ptr = try gz.addNodeExtended(.ret_ptr, node), |
| 6010 | } else .{ |
| 6011 | .ty = try gz.addNodeExtended(.ret_type, node), |
| 6012 | }; |
| 6013 | const operand = try expr(gz, scope, rl, operand_node); |
| 6014 | |
| 6015 | switch (nodeMayEvalToError(tree, operand_node)) { |
| 6016 | .never => { |
| 6017 | // Returning a value that cannot be an error; skip error defers. |
| 6018 | try genDefers(gz, &astgen.fn_block.?.base, scope, .none); |
| 6019 | _ = try gz.addUnNode(.ret_node, operand, node); |
| 6020 | return Zir.Inst.Ref.unreachable_value; |
| 6021 | }, |
| 6022 | .always => { |
| 6023 | // Value is always an error. Emit both error defers and regular defers. |
| 6024 | const err_code = try gz.addUnNode(.err_union_code, operand, node); |
| 6025 | try genDefers(gz, &astgen.fn_block.?.base, scope, err_code); |
| 6026 | _ = try gz.addUnNode(.ret_node, operand, node); |
| 6027 | return Zir.Inst.Ref.unreachable_value; |
| 6028 | }, |
| 6029 | .maybe => { |
| 6030 | // Emit conditional branch for generating errdefers. |
| 6031 | const is_err = try gz.addUnNode(.is_err, operand, node); |
| 6032 | const condbr = try gz.addCondBr(.condbr, node); |
| 6033 | |
| 6034 | var then_scope = gz.makeSubBlock(scope); |
| 6035 | defer then_scope.instructions.deinit(astgen.gpa); |
| 6036 | const err_code = try then_scope.addUnNode(.err_union_code, operand, node); |
| 6037 | try genDefers(&then_scope, &astgen.fn_block.?.base, scope, err_code); |
| 6038 | _ = try then_scope.addUnNode(.ret_node, operand, node); |
| 6039 | |
| 6040 | var else_scope = gz.makeSubBlock(scope); |
| 6041 | defer else_scope.instructions.deinit(astgen.gpa); |
| 6042 | try genDefers(&else_scope, &astgen.fn_block.?.base, scope, .none); |
| 6043 | _ = try else_scope.addUnNode(.ret_node, operand, node); |
| 6044 | |
| 6045 | try setCondBrPayload(condbr, is_err, &then_scope, &else_scope); |
| 6046 | |
| 6047 | return Zir.Inst.Ref.unreachable_value; |
| 6048 | }, |
| 6049 | } |
| 6017 | 6050 | } |
| 6018 | 6051 | |
| 6019 | 6052 | fn identifier( |
| ... | ... | @@ -7555,6 +7588,219 @@ fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) |
| 7555 | 7588 | } |
| 7556 | 7589 | } |
| 7557 | 7590 | |
| 7591 | fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum { never, always, maybe } { |
| 7592 | const node_tags = tree.nodes.items(.tag); |
| 7593 | const node_datas = tree.nodes.items(.data); |
| 7594 | const main_tokens = tree.nodes.items(.main_token); |
| 7595 | const token_tags = tree.tokens.items(.tag); |
| 7596 | |
| 7597 | var node = start_node; |
| 7598 | while (true) { |
| 7599 | switch (node_tags[node]) { |
| 7600 | .root, |
| 7601 | .@"usingnamespace", |
| 7602 | .test_decl, |
| 7603 | .switch_case, |
| 7604 | .switch_case_one, |
| 7605 | .container_field_init, |
| 7606 | .container_field_align, |
| 7607 | .container_field, |
| 7608 | .asm_output, |
| 7609 | .asm_input, |
| 7610 | => unreachable, |
| 7611 | |
| 7612 | .error_value => return .always, |
| 7613 | |
| 7614 | .@"asm", |
| 7615 | .asm_simple, |
| 7616 | .identifier, |
| 7617 | .field_access, |
| 7618 | .deref, |
| 7619 | .array_access, |
| 7620 | .while_simple, |
| 7621 | .while_cont, |
| 7622 | .for_simple, |
| 7623 | .if_simple, |
| 7624 | .@"while", |
| 7625 | .@"if", |
| 7626 | .@"for", |
| 7627 | .@"switch", |
| 7628 | .switch_comma, |
| 7629 | .call_one, |
| 7630 | .call_one_comma, |
| 7631 | .async_call_one, |
| 7632 | .async_call_one_comma, |
| 7633 | .call, |
| 7634 | .call_comma, |
| 7635 | .async_call, |
| 7636 | .async_call_comma, |
| 7637 | => return .maybe, |
| 7638 | |
| 7639 | .@"return", |
| 7640 | .@"break", |
| 7641 | .@"continue", |
| 7642 | .bit_not, |
| 7643 | .bool_not, |
| 7644 | .global_var_decl, |
| 7645 | .local_var_decl, |
| 7646 | .simple_var_decl, |
| 7647 | .aligned_var_decl, |
| 7648 | .@"defer", |
| 7649 | .@"errdefer", |
| 7650 | .address_of, |
| 7651 | .optional_type, |
| 7652 | .negation, |
| 7653 | .negation_wrap, |
| 7654 | .@"resume", |
| 7655 | .array_type, |
| 7656 | .array_type_sentinel, |
| 7657 | .ptr_type_aligned, |
| 7658 | .ptr_type_sentinel, |
| 7659 | .ptr_type, |
| 7660 | .ptr_type_bit_range, |
| 7661 | .@"suspend", |
| 7662 | .@"anytype", |
| 7663 | .fn_proto_simple, |
| 7664 | .fn_proto_multi, |
| 7665 | .fn_proto_one, |
| 7666 | .fn_proto, |
| 7667 | .fn_decl, |
| 7668 | .anyframe_type, |
| 7669 | .anyframe_literal, |
| 7670 | .integer_literal, |
| 7671 | .float_literal, |
| 7672 | .enum_literal, |
| 7673 | .string_literal, |
| 7674 | .multiline_string_literal, |
| 7675 | .char_literal, |
| 7676 | .true_literal, |
| 7677 | .false_literal, |
| 7678 | .null_literal, |
| 7679 | .undefined_literal, |
| 7680 | .unreachable_literal, |
| 7681 | .error_set_decl, |
| 7682 | .container_decl, |
| 7683 | .container_decl_trailing, |
| 7684 | .container_decl_two, |
| 7685 | .container_decl_two_trailing, |
| 7686 | .container_decl_arg, |
| 7687 | .container_decl_arg_trailing, |
| 7688 | .tagged_union, |
| 7689 | .tagged_union_trailing, |
| 7690 | .tagged_union_two, |
| 7691 | .tagged_union_two_trailing, |
| 7692 | .tagged_union_enum_tag, |
| 7693 | .tagged_union_enum_tag_trailing, |
| 7694 | .add, |
| 7695 | .add_wrap, |
| 7696 | .array_cat, |
| 7697 | .array_mult, |
| 7698 | .assign, |
| 7699 | .assign_bit_and, |
| 7700 | .assign_bit_or, |
| 7701 | .assign_bit_shift_left, |
| 7702 | .assign_bit_shift_right, |
| 7703 | .assign_bit_xor, |
| 7704 | .assign_div, |
| 7705 | .assign_sub, |
| 7706 | .assign_sub_wrap, |
| 7707 | .assign_mod, |
| 7708 | .assign_add, |
| 7709 | .assign_add_wrap, |
| 7710 | .assign_mul, |
| 7711 | .assign_mul_wrap, |
| 7712 | .bang_equal, |
| 7713 | .bit_and, |
| 7714 | .bit_or, |
| 7715 | .bit_shift_left, |
| 7716 | .bit_shift_right, |
| 7717 | .bit_xor, |
| 7718 | .bool_and, |
| 7719 | .bool_or, |
| 7720 | .div, |
| 7721 | .equal_equal, |
| 7722 | .error_union, |
| 7723 | .greater_or_equal, |
| 7724 | .greater_than, |
| 7725 | .less_or_equal, |
| 7726 | .less_than, |
| 7727 | .merge_error_sets, |
| 7728 | .mod, |
| 7729 | .mul, |
| 7730 | .mul_wrap, |
| 7731 | .switch_range, |
| 7732 | .sub, |
| 7733 | .sub_wrap, |
| 7734 | .slice, |
| 7735 | .slice_open, |
| 7736 | .slice_sentinel, |
| 7737 | .array_init_one, |
| 7738 | .array_init_one_comma, |
| 7739 | .array_init_dot_two, |
| 7740 | .array_init_dot_two_comma, |
| 7741 | .array_init_dot, |
| 7742 | .array_init_dot_comma, |
| 7743 | .array_init, |
| 7744 | .array_init_comma, |
| 7745 | .struct_init_one, |
| 7746 | .struct_init_one_comma, |
| 7747 | .struct_init_dot_two, |
| 7748 | .struct_init_dot_two_comma, |
| 7749 | .struct_init_dot, |
| 7750 | .struct_init_dot_comma, |
| 7751 | .struct_init, |
| 7752 | .struct_init_comma, |
| 7753 | => return .never, |
| 7754 | |
| 7755 | // Forward the question to the LHS sub-expression. |
| 7756 | .grouped_expression, |
| 7757 | .@"try", |
| 7758 | .@"await", |
| 7759 | .@"comptime", |
| 7760 | .@"nosuspend", |
| 7761 | .unwrap_optional, |
| 7762 | => node = node_datas[node].lhs, |
| 7763 | |
| 7764 | // Forward the question to the RHS sub-expression. |
| 7765 | .@"catch", |
| 7766 | .@"orelse", |
| 7767 | => node = node_datas[node].rhs, |
| 7768 | |
| 7769 | .block_two, |
| 7770 | .block_two_semicolon, |
| 7771 | .block, |
| 7772 | .block_semicolon, |
| 7773 | => { |
| 7774 | const lbrace = main_tokens[node]; |
| 7775 | if (token_tags[lbrace - 1] == .colon) { |
| 7776 | // Labeled blocks may need a memory location to forward |
| 7777 | // to their break statements. |
| 7778 | return .maybe; |
| 7779 | } else { |
| 7780 | return .never; |
| 7781 | } |
| 7782 | }, |
| 7783 | |
| 7784 | .builtin_call, |
| 7785 | .builtin_call_comma, |
| 7786 | .builtin_call_two, |
| 7787 | .builtin_call_two_comma, |
| 7788 | => { |
| 7789 | const builtin_token = main_tokens[node]; |
| 7790 | const builtin_name = tree.tokenSlice(builtin_token); |
| 7791 | // If the builtin is an invalid name, we don't cause an error here; instead |
| 7792 | // let it pass, and the error will be "invalid builtin function" later. |
| 7793 | const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe; |
| 7794 | if (builtin_info.tag == .err_set_cast) { |
| 7795 | return .always; |
| 7796 | } else { |
| 7797 | return .never; |
| 7798 | } |
| 7799 | }, |
| 7800 | } |
| 7801 | } |
| 7802 | } |
| 7803 | |
| 7558 | 7804 | /// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of |
| 7559 | 7805 | /// result locations must call this function on their result. |
| 7560 | 7806 | /// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer. |