| ... | @@ -768,12 +768,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr | ... | @@ -768,12 +768,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 768 | .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)), | 768 | .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)), |
| 769 | .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)), | 769 | .@"if" => return ifExpr(gz, scope, rl.br(), node, tree.ifFull(node)), |
| 770 | | 770 | |
| 771 | .while_simple => return whileExpr(gz, scope, rl.br(), node, tree.whileSimple(node)), | 771 | .while_simple => return whileExpr(gz, scope, rl.br(), node, tree.whileSimple(node), false), |
| 772 | .while_cont => return whileExpr(gz, scope, rl.br(), node, tree.whileCont(node)), | 772 | .while_cont => return whileExpr(gz, scope, rl.br(), node, tree.whileCont(node), false), |
| 773 | .@"while" => return whileExpr(gz, scope, rl.br(), node, tree.whileFull(node)), | 773 | .@"while" => return whileExpr(gz, scope, rl.br(), node, tree.whileFull(node), false), |
| 774 | | 774 | |
| 775 | .for_simple => return forExpr(gz, scope, rl.br(), node, tree.forSimple(node)), | 775 | .for_simple => return forExpr(gz, scope, rl.br(), node, tree.forSimple(node), false), |
| 776 | .@"for" => return forExpr(gz, scope, rl.br(), node, tree.forFull(node)), | 776 | .@"for" => return forExpr(gz, scope, rl.br(), node, tree.forFull(node), false), |
| 777 | | 777 | |
| 778 | .slice_open => { | 778 | .slice_open => { |
| 779 | const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); | 779 | const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); |
| ... | @@ -2152,6 +2152,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -2152,6 +2152,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 2152 | const astgen = gz.astgen; | 2152 | const astgen = gz.astgen; |
| 2153 | const tree = astgen.tree; | 2153 | const tree = astgen.tree; |
| 2154 | const node_tags = tree.nodes.items(.tag); | 2154 | const node_tags = tree.nodes.items(.tag); |
| | 2155 | const node_data = tree.nodes.items(.data); |
| 2155 | | 2156 | |
| 2156 | if (statements.len == 0) return; | 2157 | if (statements.len == 0) return; |
| 2157 | | 2158 | |
| ... | @@ -2178,8 +2179,10 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -2178,8 +2179,10 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 2178 | }, | 2179 | }, |
| 2179 | ); | 2180 | ); |
| 2180 | } | 2181 | } |
| 2181 | switch (node_tags[statement]) { | 2182 | var inner_node = statement; |
| 2182 | // zig fmt: off | 2183 | while (true) { |
| | 2184 | switch (node_tags[inner_node]) { |
| | 2185 | // zig fmt: off |
| 2183 | .global_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.globalVarDecl(statement)), | 2186 | .global_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.globalVarDecl(statement)), |
| 2184 | .local_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.localVarDecl(statement)), | 2187 | .local_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.localVarDecl(statement)), |
| 2185 | .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)), | 2188 | .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)), |
| ... | @@ -2204,9 +2207,23 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -2204,9 +2207,23 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 2204 | .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), | 2207 | .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), |
| 2205 | .assign_mul => try assignOp(gz, scope, statement, .mul), | 2208 | .assign_mul => try assignOp(gz, scope, statement, .mul), |
| 2206 | .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), | 2209 | .assign_mul_wrap => try assignOp(gz, scope, statement, .mulwrap), |
| | 2210 | |
| | 2211 | .grouped_expression => { |
| | 2212 | inner_node = node_data[statement].lhs; |
| | 2213 | continue; |
| | 2214 | }, |
| 2207 | | 2215 | |
| 2208 | else => noreturn_src_node = try unusedResultExpr(gz, scope, statement), | 2216 | .while_simple => _ = try whileExpr(gz, scope, .discard, inner_node, tree.whileSimple(inner_node), true), |
| | 2217 | .while_cont => _ = try whileExpr(gz, scope, .discard, inner_node, tree.whileCont(inner_node), true), |
| | 2218 | .@"while" => _ = try whileExpr(gz, scope, .discard, inner_node, tree.whileFull(inner_node), true), |
| | 2219 | |
| | 2220 | .for_simple => _ = try forExpr(gz, scope, .discard, inner_node, tree.forSimple(inner_node), true), |
| | 2221 | .@"for" => _ = try forExpr(gz, scope, .discard, inner_node, tree.forFull(inner_node), true), |
| | 2222 | |
| | 2223 | else => noreturn_src_node = try unusedResultExpr(gz, scope, inner_node), |
| 2209 | // zig fmt: on | 2224 | // zig fmt: on |
| | 2225 | } |
| | 2226 | break; |
| 2210 | } | 2227 | } |
| 2211 | } | 2228 | } |
| 2212 | | 2229 | |
| ... | @@ -2245,6 +2262,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner | ... | @@ -2245,6 +2262,10 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2245 | // We need to emit an error if the result is not `noreturn` or `void`, but | 2262 | // We need to emit an error if the result is not `noreturn` or `void`, but |
| 2246 | // we want to avoid adding the ZIR instruction if possible for performance. | 2263 | // we want to avoid adding the ZIR instruction if possible for performance. |
| 2247 | const maybe_unused_result = try expr(gz, scope, .none, statement); | 2264 | const maybe_unused_result = try expr(gz, scope, .none, statement); |
| | 2265 | return addEnsureResult(gz, maybe_unused_result, statement); |
| | 2266 | } |
| | 2267 | |
| | 2268 | fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: Ast.Node.Index) InnerError!Ast.Node.Index { |
| 2248 | var noreturn_src_node: Ast.Node.Index = 0; | 2269 | var noreturn_src_node: Ast.Node.Index = 0; |
| 2249 | const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { | 2270 | const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { |
| 2250 | // Note that this array becomes invalid after appending more items to it | 2271 | // Note that this array becomes invalid after appending more items to it |
| ... | @@ -5648,6 +5669,7 @@ fn whileExpr( | ... | @@ -5648,6 +5669,7 @@ fn whileExpr( |
| 5648 | rl: ResultLoc, | 5669 | rl: ResultLoc, |
| 5649 | node: Ast.Node.Index, | 5670 | node: Ast.Node.Index, |
| 5650 | while_full: Ast.full.While, | 5671 | while_full: Ast.full.While, |
| | 5672 | is_statement: bool, |
| 5651 | ) InnerError!Zir.Inst.Ref { | 5673 | ) InnerError!Zir.Inst.Ref { |
| 5652 | const astgen = parent_gz.astgen; | 5674 | const astgen = parent_gz.astgen; |
| 5653 | const tree = astgen.tree; | 5675 | const tree = astgen.tree; |
| ... | @@ -5818,6 +5840,8 @@ fn whileExpr( | ... | @@ -5818,6 +5840,8 @@ fn whileExpr( |
| 5818 | try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); | 5840 | try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); |
| 5819 | } | 5841 | } |
| 5820 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); | 5842 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr); |
| | 5843 | _ = try addEnsureResult(&then_scope, then_result, while_full.ast.then_expr); |
| | 5844 | |
| 5821 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); | 5845 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 5822 | try then_scope.addDbgBlockEnd(); | 5846 | try then_scope.addDbgBlockEnd(); |
| 5823 | | 5847 | |
| ... | @@ -5860,7 +5884,11 @@ fn whileExpr( | ... | @@ -5860,7 +5884,11 @@ fn whileExpr( |
| 5860 | // control flow apply to outer loops; not this one. | 5884 | // control flow apply to outer loops; not this one. |
| 5861 | loop_scope.continue_block = 0; | 5885 | loop_scope.continue_block = 0; |
| 5862 | loop_scope.break_block = 0; | 5886 | loop_scope.break_block = 0; |
| 5863 | const e = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); | 5887 | const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); |
| | 5888 | if (is_statement) { |
| | 5889 | _ = try addEnsureResult(&else_scope, else_result, else_node); |
| | 5890 | } |
| | 5891 | |
| 5864 | if (!else_scope.endsWithNoReturn()) { | 5892 | if (!else_scope.endsWithNoReturn()) { |
| 5865 | loop_scope.break_count += 1; | 5893 | loop_scope.break_count += 1; |
| 5866 | } | 5894 | } |
| ... | @@ -5868,7 +5896,7 @@ fn whileExpr( | ... | @@ -5868,7 +5896,7 @@ fn whileExpr( |
| 5868 | try else_scope.addDbgBlockEnd(); | 5896 | try else_scope.addDbgBlockEnd(); |
| 5869 | break :blk .{ | 5897 | break :blk .{ |
| 5870 | .src = else_node, | 5898 | .src = else_node, |
| 5871 | .result = e, | 5899 | .result = else_result, |
| 5872 | }; | 5900 | }; |
| 5873 | } else .{ | 5901 | } else .{ |
| 5874 | .src = while_full.ast.then_expr, | 5902 | .src = while_full.ast.then_expr, |
| ... | @@ -5881,7 +5909,7 @@ fn whileExpr( | ... | @@ -5881,7 +5909,7 @@ fn whileExpr( |
| 5881 | } | 5909 | } |
| 5882 | } | 5910 | } |
| 5883 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | 5911 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; |
| 5884 | return finishThenElseBlock( | 5912 | const result = try finishThenElseBlock( |
| 5885 | parent_gz, | 5913 | parent_gz, |
| 5886 | rl, | 5914 | rl, |
| 5887 | node, | 5915 | node, |
| ... | @@ -5896,6 +5924,10 @@ fn whileExpr( | ... | @@ -5896,6 +5924,10 @@ fn whileExpr( |
| 5896 | cond_block, | 5924 | cond_block, |
| 5897 | break_tag, | 5925 | break_tag, |
| 5898 | ); | 5926 | ); |
| | 5927 | if (is_statement) { |
| | 5928 | _ = try parent_gz.addUnNode(.ensure_result_used, result, node); |
| | 5929 | } |
| | 5930 | return result; |
| 5899 | } | 5931 | } |
| 5900 | | 5932 | |
| 5901 | fn forExpr( | 5933 | fn forExpr( |
| ... | @@ -5904,6 +5936,7 @@ fn forExpr( | ... | @@ -5904,6 +5936,7 @@ fn forExpr( |
| 5904 | rl: ResultLoc, | 5936 | rl: ResultLoc, |
| 5905 | node: Ast.Node.Index, | 5937 | node: Ast.Node.Index, |
| 5906 | for_full: Ast.full.While, | 5938 | for_full: Ast.full.While, |
| | 5939 | is_statement: bool, |
| 5907 | ) InnerError!Zir.Inst.Ref { | 5940 | ) InnerError!Zir.Inst.Ref { |
| 5908 | const astgen = parent_gz.astgen; | 5941 | const astgen = parent_gz.astgen; |
| 5909 | | 5942 | |
| ... | @@ -6047,6 +6080,8 @@ fn forExpr( | ... | @@ -6047,6 +6080,8 @@ fn forExpr( |
| 6047 | }; | 6080 | }; |
| 6048 | | 6081 | |
| 6049 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); | 6082 | const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr); |
| | 6083 | _ = try addEnsureResult(&then_scope, then_result, for_full.ast.then_expr); |
| | 6084 | |
| 6050 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); | 6085 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 6051 | try then_scope.addDbgBlockEnd(); | 6086 | try then_scope.addDbgBlockEnd(); |
| 6052 | | 6087 | |
| ... | @@ -6064,6 +6099,10 @@ fn forExpr( | ... | @@ -6064,6 +6099,10 @@ fn forExpr( |
| 6064 | loop_scope.continue_block = 0; | 6099 | loop_scope.continue_block = 0; |
| 6065 | loop_scope.break_block = 0; | 6100 | loop_scope.break_block = 0; |
| 6066 | const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); | 6101 | const else_result = try expr(&else_scope, sub_scope, loop_scope.break_result_loc, else_node); |
| | 6102 | if (is_statement) { |
| | 6103 | _ = try addEnsureResult(&else_scope, else_result, else_node); |
| | 6104 | } |
| | 6105 | |
| 6067 | if (!else_scope.endsWithNoReturn()) { | 6106 | if (!else_scope.endsWithNoReturn()) { |
| 6068 | loop_scope.break_count += 1; | 6107 | loop_scope.break_count += 1; |
| 6069 | } | 6108 | } |
| ... | @@ -6082,7 +6121,7 @@ fn forExpr( | ... | @@ -6082,7 +6121,7 @@ fn forExpr( |
| 6082 | } | 6121 | } |
| 6083 | } | 6122 | } |
| 6084 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; | 6123 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; |
| 6085 | return finishThenElseBlock( | 6124 | const result = try finishThenElseBlock( |
| 6086 | parent_gz, | 6125 | parent_gz, |
| 6087 | rl, | 6126 | rl, |
| 6088 | node, | 6127 | node, |
| ... | @@ -6097,6 +6136,10 @@ fn forExpr( | ... | @@ -6097,6 +6136,10 @@ fn forExpr( |
| 6097 | cond_block, | 6136 | cond_block, |
| 6098 | break_tag, | 6137 | break_tag, |
| 6099 | ); | 6138 | ); |
| | 6139 | if (is_statement) { |
| | 6140 | _ = try parent_gz.addUnNode(.ensure_result_used, result, node); |
| | 6141 | } |
| | 6142 | return result; |
| 6100 | } | 6143 | } |
| 6101 | | 6144 | |
| 6102 | fn switchExpr( | 6145 | fn switchExpr( |