@@ -6005,22 +6005,55 @@ fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref
6005
6005
if (gz .in_defer ) return astgen .failNode (node , "cannot return from defer expression" , .{});
6006
6006
6007
6007
const operand_node = node_datas [node ].lhs ;
6008
- if (operand_node != 0 ) {
6009
- const rl : ResultLoc = if (nodeMayNeedMemoryLocation (tree , operand_node )) .{
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
6008
+ if (operand_node == 0 ) {
6009
+ // Returning a void value; skip error defers.
6016
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
6012
return Zir .Inst .Ref .unreachable_value ;
6019
6013
}
6020
- // Returning a void value; skip error defers.
6021
- try genDefers (gz , & astgen .fn_block .? .base , scope , .none );
6022
- _ = try gz .addUnNode (.ret_node , .void_value , node );
6023
- return Zir .Inst .Ref .unreachable_value ;
6014
+
6015
+ const rl : ResultLoc = if (nodeMayNeedMemoryLocation (tree , operand_node )) .{
6016
+ .ptr = try gz .addNodeExtended (.ret_ptr , node ),
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
6059
fn identifier (
@@ -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
7857
/// Applies `rl` semantics to `inst`. Expressions which do not do their own handling of
7612
7858
/// result locations must call this function on their result.
7613
7859
/// As an example, if the `ResultLoc` is `ptr`, it will write the result to the pointer.
0 commit comments