| ... | ... | @@ -768,12 +768,12 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr |
| 768 | 768 | .if_simple => return ifExpr(gz, scope, rl.br(), node, tree.ifSimple(node)), |
| 769 | 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)), |
| 772 | | .while_cont => return whileExpr(gz, scope, rl.br(), node, tree.whileCont(node)), |
| 773 | | .@"while" => return whileExpr(gz, scope, rl.br(), node, tree.whileFull(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), false), |
| 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)), |
| 776 | | .@"for" => return forExpr(gz, scope, rl.br(), node, tree.forFull(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), false), |
| 777 | 777 | |
| 778 | 778 | .slice_open => { |
| 779 | 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 | 2152 | const astgen = gz.astgen; |
| 2153 | 2153 | const tree = astgen.tree; |
| 2154 | 2154 | const node_tags = tree.nodes.items(.tag); |
| 2155 | const node_data = tree.nodes.items(.data); |
| 2155 | 2156 | |
| 2156 | 2157 | if (statements.len == 0) return; |
| 2157 | 2158 | |
| ... | ... | @@ -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 | | // zig fmt: off |
| 2182 | var inner_node = statement; |
| 2183 | while (true) { |
| 2184 | switch (node_tags[inner_node]) { |
| 2185 | // zig fmt: off |
| 2183 | 2186 | .global_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.globalVarDecl(statement)), |
| 2184 | 2187 | .local_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.localVarDecl(statement)), |
| 2185 | 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 | 2207 | .assign_add_wrap => try assignOp(gz, scope, statement, .addwrap), |
| 2205 | 2208 | .assign_mul => try assignOp(gz, scope, statement, .mul), |
| 2206 | 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 | 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 | 2262 | // We need to emit an error if the result is not `noreturn` or `void`, but |
| 2246 | 2263 | // we want to avoid adding the ZIR instruction if possible for performance. |
| 2247 | 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 | 2269 | var noreturn_src_node: Ast.Node.Index = 0; |
| 2249 | 2270 | const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { |
| 2250 | 2271 | // Note that this array becomes invalid after appending more items to it |
| ... | ... | @@ -5648,6 +5669,7 @@ fn whileExpr( |
| 5648 | 5669 | rl: ResultLoc, |
| 5649 | 5670 | node: Ast.Node.Index, |
| 5650 | 5671 | while_full: Ast.full.While, |
| 5672 | is_statement: bool, |
| 5651 | 5673 | ) InnerError!Zir.Inst.Ref { |
| 5652 | 5674 | const astgen = parent_gz.astgen; |
| 5653 | 5675 | const tree = astgen.tree; |
| ... | ... | @@ -5818,6 +5840,8 @@ fn whileExpr( |
| 5818 | 5840 | try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst); |
| 5819 | 5841 | } |
| 5820 | 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 | 5845 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 5822 | 5846 | try then_scope.addDbgBlockEnd(); |
| 5823 | 5847 | |
| ... | ... | @@ -5860,7 +5884,11 @@ fn whileExpr( |
| 5860 | 5884 | // control flow apply to outer loops; not this one. |
| 5861 | 5885 | loop_scope.continue_block = 0; |
| 5862 | 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 | 5892 | if (!else_scope.endsWithNoReturn()) { |
| 5865 | 5893 | loop_scope.break_count += 1; |
| 5866 | 5894 | } |
| ... | ... | @@ -5868,7 +5896,7 @@ fn whileExpr( |
| 5868 | 5896 | try else_scope.addDbgBlockEnd(); |
| 5869 | 5897 | break :blk .{ |
| 5870 | 5898 | .src = else_node, |
| 5871 | | .result = e, |
| 5899 | .result = else_result, |
| 5872 | 5900 | }; |
| 5873 | 5901 | } else .{ |
| 5874 | 5902 | .src = while_full.ast.then_expr, |
| ... | ... | @@ -5881,7 +5909,7 @@ fn whileExpr( |
| 5881 | 5909 | } |
| 5882 | 5910 | } |
| 5883 | 5911 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; |
| 5884 | | return finishThenElseBlock( |
| 5912 | const result = try finishThenElseBlock( |
| 5885 | 5913 | parent_gz, |
| 5886 | 5914 | rl, |
| 5887 | 5915 | node, |
| ... | ... | @@ -5896,6 +5924,10 @@ fn whileExpr( |
| 5896 | 5924 | cond_block, |
| 5897 | 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 | 5933 | fn forExpr( |
| ... | ... | @@ -5904,6 +5936,7 @@ fn forExpr( |
| 5904 | 5936 | rl: ResultLoc, |
| 5905 | 5937 | node: Ast.Node.Index, |
| 5906 | 5938 | for_full: Ast.full.While, |
| 5939 | is_statement: bool, |
| 5907 | 5940 | ) InnerError!Zir.Inst.Ref { |
| 5908 | 5941 | const astgen = parent_gz.astgen; |
| 5909 | 5942 | |
| ... | ... | @@ -6047,6 +6080,8 @@ fn forExpr( |
| 6047 | 6080 | }; |
| 6048 | 6081 | |
| 6049 | 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 | 6085 | try checkUsed(parent_gz, &then_scope.base, then_sub_scope); |
| 6051 | 6086 | try then_scope.addDbgBlockEnd(); |
| 6052 | 6087 | |
| ... | ... | @@ -6064,6 +6099,10 @@ fn forExpr( |
| 6064 | 6099 | loop_scope.continue_block = 0; |
| 6065 | 6100 | loop_scope.break_block = 0; |
| 6066 | 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 | 6106 | if (!else_scope.endsWithNoReturn()) { |
| 6068 | 6107 | loop_scope.break_count += 1; |
| 6069 | 6108 | } |
| ... | ... | @@ -6082,7 +6121,7 @@ fn forExpr( |
| 6082 | 6121 | } |
| 6083 | 6122 | } |
| 6084 | 6123 | const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break"; |
| 6085 | | return finishThenElseBlock( |
| 6124 | const result = try finishThenElseBlock( |
| 6086 | 6125 | parent_gz, |
| 6087 | 6126 | rl, |
| 6088 | 6127 | node, |
| ... | ... | @@ -6097,6 +6136,10 @@ fn forExpr( |
| 6097 | 6136 | cond_block, |
| 6098 | 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 | 6145 | fn switchExpr( |