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