| ... | @@ -1683,7 +1683,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn | ... | @@ -1683,7 +1683,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn |
| 1683 | const defer_scope = scope.cast(Scope.Defer).?; | 1683 | const defer_scope = scope.cast(Scope.Defer).?; |
| 1684 | scope = defer_scope.parent; | 1684 | scope = defer_scope.parent; |
| 1685 | const expr_node = node_datas[defer_scope.defer_node].rhs; | 1685 | const expr_node = node_datas[defer_scope.defer_node].rhs; |
| 1686 | _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); | 1686 | try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node); |
| 1687 | }, | 1687 | }, |
| 1688 | .defer_error => scope = scope.cast(Scope.Defer).?.parent, | 1688 | .defer_error => scope = scope.cast(Scope.Defer).?.parent, |
| 1689 | .top => unreachable, | 1689 | .top => unreachable, |
| ... | @@ -1736,7 +1736,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) | ... | @@ -1736,7 +1736,7 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) |
| 1736 | const defer_scope = scope.cast(Scope.Defer).?; | 1736 | const defer_scope = scope.cast(Scope.Defer).?; |
| 1737 | scope = defer_scope.parent; | 1737 | scope = defer_scope.parent; |
| 1738 | const expr_node = node_datas[defer_scope.defer_node].rhs; | 1738 | const expr_node = node_datas[defer_scope.defer_node].rhs; |
| 1739 | _ = try unusedResultExpr(parent_gz, defer_scope.parent, expr_node); | 1739 | try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node); |
| 1740 | }, | 1740 | }, |
| 1741 | .defer_error => scope = scope.cast(Scope.Defer).?.parent, | 1741 | .defer_error => scope = scope.cast(Scope.Defer).?.parent, |
| 1742 | .namespace => break, | 1742 | .namespace => break, |
| ... | @@ -1922,8 +1922,8 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -1922,8 +1922,8 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 1922 | .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)), | 1922 | .simple_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.simpleVarDecl(statement)), |
| 1923 | .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)), | 1923 | .aligned_var_decl => scope = try varDecl(gz, scope, statement, &block_arena.allocator, tree.alignedVarDecl(statement)), |
| 1924 | | 1924 | |
| 1925 | .@"defer" => scope = try makeDeferScope(scope, statement, &block_arena.allocator, .defer_normal), | 1925 | .@"defer" => scope = try makeDeferScope(gz.astgen, scope, statement, &block_arena.allocator, .defer_normal), |
| 1926 | .@"errdefer" => scope = try makeDeferScope(scope, statement, &block_arena.allocator, .defer_error), | 1926 | .@"errdefer" => scope = try makeDeferScope(gz.astgen, scope, statement, &block_arena.allocator, .defer_error), |
| 1927 | | 1927 | |
| 1928 | .assign => try assign(gz, scope, statement), | 1928 | .assign => try assign(gz, scope, statement), |
| 1929 | | 1929 | |
| ... | @@ -1951,6 +1951,22 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod | ... | @@ -1951,6 +1951,22 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod |
| 1951 | try checkUsed(gz, parent_scope, scope); | 1951 | try checkUsed(gz, parent_scope, scope); |
| 1952 | } | 1952 | } |
| 1953 | | 1953 | |
| | 1954 | fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Scope, expr_node: Ast.Node.Index) InnerError!void { |
| | 1955 | const astgen = gz.astgen; |
| | 1956 | const prev_offset = astgen.source_offset; |
| | 1957 | const prev_line = astgen.source_line; |
| | 1958 | const prev_column = astgen.source_column; |
| | 1959 | defer { |
| | 1960 | astgen.source_offset = prev_offset; |
| | 1961 | astgen.source_line = prev_line; |
| | 1962 | astgen.source_column = prev_column; |
| | 1963 | } |
| | 1964 | astgen.source_offset = defer_scope.source_offset; |
| | 1965 | astgen.source_line = defer_scope.source_line; |
| | 1966 | astgen.source_column = defer_scope.source_column; |
| | 1967 | _ = try unusedResultExpr(gz, expr_scope, expr_node); |
| | 1968 | } |
| | 1969 | |
| 1954 | /// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`. | 1970 | /// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`. |
| 1955 | /// Otherwise returns 0. | 1971 | /// Otherwise returns 0. |
| 1956 | fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index { | 1972 | fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index { |
| ... | @@ -2333,7 +2349,7 @@ fn genDefers( | ... | @@ -2333,7 +2349,7 @@ fn genDefers( |
| 2333 | const prev_in_defer = gz.in_defer; | 2349 | const prev_in_defer = gz.in_defer; |
| 2334 | gz.in_defer = true; | 2350 | gz.in_defer = true; |
| 2335 | defer gz.in_defer = prev_in_defer; | 2351 | defer gz.in_defer = prev_in_defer; |
| 2336 | _ = try unusedResultExpr(gz, defer_scope.parent, expr_node); | 2352 | try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node); |
| 2337 | }, | 2353 | }, |
| 2338 | .defer_error => { | 2354 | .defer_error => { |
| 2339 | const defer_scope = scope.cast(Scope.Defer).?; | 2355 | const defer_scope = scope.cast(Scope.Defer).?; |
| ... | @@ -2344,7 +2360,7 @@ fn genDefers( | ... | @@ -2344,7 +2360,7 @@ fn genDefers( |
| 2344 | const prev_in_defer = gz.in_defer; | 2360 | const prev_in_defer = gz.in_defer; |
| 2345 | gz.in_defer = true; | 2361 | gz.in_defer = true; |
| 2346 | defer gz.in_defer = prev_in_defer; | 2362 | defer gz.in_defer = prev_in_defer; |
| 2347 | _ = try unusedResultExpr(gz, defer_scope.parent, expr_node); | 2363 | try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node); |
| 2348 | }, | 2364 | }, |
| 2349 | .both => |err_code| { | 2365 | .both => |err_code| { |
| 2350 | const expr_node = node_datas[defer_scope.defer_node].rhs; | 2366 | const expr_node = node_datas[defer_scope.defer_node].rhs; |
| ... | @@ -2365,7 +2381,7 @@ fn genDefers( | ... | @@ -2365,7 +2381,7 @@ fn genDefers( |
| 2365 | }; | 2381 | }; |
| 2366 | break :blk &local_val_scope.base; | 2382 | break :blk &local_val_scope.base; |
| 2367 | }; | 2383 | }; |
| 2368 | _ = try unusedResultExpr(gz, sub_scope, expr_node); | 2384 | try unusedResultDeferExpr(gz, defer_scope, sub_scope, expr_node); |
| 2369 | }, | 2385 | }, |
| 2370 | .normal_only => continue, | 2386 | .normal_only => continue, |
| 2371 | } | 2387 | } |
| ... | @@ -2409,16 +2425,27 @@ fn checkUsed( | ... | @@ -2409,16 +2425,27 @@ fn checkUsed( |
| 2409 | } | 2425 | } |
| 2410 | | 2426 | |
| 2411 | fn makeDeferScope( | 2427 | fn makeDeferScope( |
| | 2428 | astgen: *AstGen, |
| 2412 | scope: *Scope, | 2429 | scope: *Scope, |
| 2413 | node: Ast.Node.Index, | 2430 | node: Ast.Node.Index, |
| 2414 | block_arena: *Allocator, | 2431 | block_arena: *Allocator, |
| 2415 | scope_tag: Scope.Tag, | 2432 | scope_tag: Scope.Tag, |
| 2416 | ) InnerError!*Scope { | 2433 | ) InnerError!*Scope { |
| | 2434 | const tree = astgen.tree; |
| | 2435 | const node_datas = tree.nodes.items(.data); |
| | 2436 | const expr_node = node_datas[node].rhs; |
| | 2437 | const token_starts = tree.tokens.items(.start); |
| | 2438 | const node_start = token_starts[tree.firstToken(expr_node)]; |
| 2417 | const defer_scope = try block_arena.create(Scope.Defer); | 2439 | const defer_scope = try block_arena.create(Scope.Defer); |
| | 2440 | astgen.advanceSourceCursor(tree.source, node_start); |
| | 2441 | |
| 2418 | defer_scope.* = .{ | 2442 | defer_scope.* = .{ |
| 2419 | .base = .{ .tag = scope_tag }, | 2443 | .base = .{ .tag = scope_tag }, |
| 2420 | .parent = scope, | 2444 | .parent = scope, |
| 2421 | .defer_node = node, | 2445 | .defer_node = node, |
| | 2446 | .source_offset = astgen.source_offset, |
| | 2447 | .source_line = astgen.source_line, |
| | 2448 | .source_column = astgen.source_column, |
| 2422 | }; | 2449 | }; |
| 2423 | return &defer_scope.base; | 2450 | return &defer_scope.base; |
| 2424 | } | 2451 | } |
| ... | @@ -3184,6 +3211,12 @@ fn fnDecl( | ... | @@ -3184,6 +3211,12 @@ fn fnDecl( |
| 3184 | astgen.fn_block = &fn_gz; | 3211 | astgen.fn_block = &fn_gz; |
| 3185 | defer astgen.fn_block = prev_fn_block; | 3212 | defer astgen.fn_block = prev_fn_block; |
| 3186 | | 3213 | |
| | 3214 | const token_starts = tree.tokens.items(.start); |
| | 3215 | const lbrace_start = token_starts[tree.firstToken(body_node)]; |
| | 3216 | astgen.advanceSourceCursor(tree.source, lbrace_start); |
| | 3217 | const lbrace_line = @intCast(u32, astgen.source_line); |
| | 3218 | const lbrace_column = @intCast(u32, astgen.source_column); |
| | 3219 | |
| 3187 | _ = try expr(&fn_gz, params_scope, .none, body_node); | 3220 | _ = try expr(&fn_gz, params_scope, .none, body_node); |
| 3188 | try checkUsed(gz, &fn_gz.base, params_scope); | 3221 | try checkUsed(gz, &fn_gz.base, params_scope); |
| 3189 | | 3222 | |
| ... | @@ -3202,6 +3235,8 @@ fn fnDecl( | ... | @@ -3202,6 +3235,8 @@ fn fnDecl( |
| 3202 | | 3235 | |
| 3203 | break :func try decl_gz.addFunc(.{ | 3236 | break :func try decl_gz.addFunc(.{ |
| 3204 | .src_node = decl_node, | 3237 | .src_node = decl_node, |
| | 3238 | .lbrace_line = lbrace_line, |
| | 3239 | .lbrace_column = lbrace_column, |
| 3205 | .param_block = block_inst, | 3240 | .param_block = block_inst, |
| 3206 | .ret_ty = ret_gz.instructions.items, | 3241 | .ret_ty = ret_gz.instructions.items, |
| 3207 | .ret_br = ret_br, | 3242 | .ret_br = ret_br, |
| ... | @@ -3544,6 +3579,12 @@ fn testDecl( | ... | @@ -3544,6 +3579,12 @@ fn testDecl( |
| 3544 | astgen.fn_block = &fn_block; | 3579 | astgen.fn_block = &fn_block; |
| 3545 | defer astgen.fn_block = prev_fn_block; | 3580 | defer astgen.fn_block = prev_fn_block; |
| 3546 | | 3581 | |
| | 3582 | const token_starts = tree.tokens.items(.start); |
| | 3583 | const lbrace_start = token_starts[tree.firstToken(body_node)]; |
| | 3584 | astgen.advanceSourceCursor(tree.source, lbrace_start); |
| | 3585 | const lbrace_line = @intCast(u32, astgen.source_line); |
| | 3586 | const lbrace_column = @intCast(u32, astgen.source_column); |
| | 3587 | |
| 3547 | const block_result = try expr(&fn_block, &fn_block.base, .none, body_node); | 3588 | const block_result = try expr(&fn_block, &fn_block.base, .none, body_node); |
| 3548 | if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) { | 3589 | if (fn_block.instructions.items.len == 0 or !fn_block.refIsNoReturn(block_result)) { |
| 3549 | // Since we are adding the return instruction here, we must handle the coercion. | 3590 | // Since we are adding the return instruction here, we must handle the coercion. |
| ... | @@ -3553,6 +3594,8 @@ fn testDecl( | ... | @@ -3553,6 +3594,8 @@ fn testDecl( |
| 3553 | | 3594 | |
| 3554 | const func_inst = try decl_block.addFunc(.{ | 3595 | const func_inst = try decl_block.addFunc(.{ |
| 3555 | .src_node = node, | 3596 | .src_node = node, |
| | 3597 | .lbrace_line = lbrace_line, |
| | 3598 | .lbrace_column = lbrace_column, |
| 3556 | .param_block = block_inst, | 3599 | .param_block = block_inst, |
| 3557 | .ret_ty = &.{}, | 3600 | .ret_ty = &.{}, |
| 3558 | .ret_br = 0, | 3601 | .ret_br = 0, |
| ... | @@ -5935,10 +5978,11 @@ fn switchExpr( | ... | @@ -5935,10 +5978,11 @@ fn switchExpr( |
| 5935 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); | 5978 | const operand_ty_inst = try parent_gz.addUnNode(typeof_tag, operand, operand_node); |
| 5936 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; | 5979 | const item_rl: ResultLoc = .{ .ty = operand_ty_inst }; |
| 5937 | | 5980 | |
| 5938 | // Contains the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. | 5981 | // These contain the data that goes into the `extra` array for the SwitchBlock/SwitchBlockMulti. |
| 5939 | // This is the header as well as the optional else prong body, as well as all the | 5982 | // This is the optional else prong body. |
| 5940 | // scalar cases. | 5983 | var special_case_payload = ArrayListUnmanaged(u32){}; |
| 5941 | // At the end we will memcpy this into place. | 5984 | defer special_case_payload.deinit(gpa); |
| | 5985 | // This is all the scalar cases. |
| 5942 | var scalar_cases_payload = ArrayListUnmanaged(u32){}; | 5986 | var scalar_cases_payload = ArrayListUnmanaged(u32){}; |
| 5943 | defer scalar_cases_payload.deinit(gpa); | 5987 | defer scalar_cases_payload.deinit(gpa); |
| 5944 | // Same deal, but this is only the `extra` data for the multi cases. | 5988 | // Same deal, but this is only the `extra` data for the multi cases. |
| ... | @@ -5956,86 +6000,10 @@ fn switchExpr( | ... | @@ -5956,86 +6000,10 @@ fn switchExpr( |
| 5956 | var case_scope = parent_gz.makeSubBlock(&block_scope.base); | 6000 | var case_scope = parent_gz.makeSubBlock(&block_scope.base); |
| 5957 | defer case_scope.instructions.deinit(gpa); | 6001 | defer case_scope.instructions.deinit(gpa); |
| 5958 | | 6002 | |
| 5959 | // Do the else/`_` first because it goes first in the payload. | 6003 | // In this pass we generate all the item and prong expressions. |
| 5960 | var capture_val_scope: Scope.LocalVal = undefined; | | |
| 5961 | if (special_node != 0) { | | |
| 5962 | const case = switch (node_tags[special_node]) { | | |
| 5963 | .switch_case_one => tree.switchCaseOne(special_node), | | |
| 5964 | .switch_case => tree.switchCase(special_node), | | |
| 5965 | else => unreachable, | | |
| 5966 | }; | | |
| 5967 | const sub_scope = blk: { | | |
| 5968 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | | |
| 5969 | const ident = if (token_tags[payload_token] == .asterisk) | | |
| 5970 | payload_token + 1 | | |
| 5971 | else | | |
| 5972 | payload_token; | | |
| 5973 | const is_ptr = ident != payload_token; | | |
| 5974 | if (mem.eql(u8, tree.tokenSlice(ident), "_")) { | | |
| 5975 | if (is_ptr) { | | |
| 5976 | return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); | | |
| 5977 | } | | |
| 5978 | break :blk &case_scope.base; | | |
| 5979 | } | | |
| 5980 | const capture_tag: Zir.Inst.Tag = if (is_ptr) | | |
| 5981 | .switch_capture_else_ref | | |
| 5982 | else | | |
| 5983 | .switch_capture_else; | | |
| 5984 | const capture = try case_scope.add(.{ | | |
| 5985 | .tag = capture_tag, | | |
| 5986 | .data = .{ .switch_capture = .{ | | |
| 5987 | .switch_inst = switch_block, | | |
| 5988 | .prong_index = undefined, | | |
| 5989 | } }, | | |
| 5990 | }); | | |
| 5991 | const capture_name = try astgen.identAsString(payload_token); | | |
| 5992 | capture_val_scope = .{ | | |
| 5993 | .parent = &case_scope.base, | | |
| 5994 | .gen_zir = &case_scope, | | |
| 5995 | .name = capture_name, | | |
| 5996 | .inst = capture, | | |
| 5997 | .token_src = payload_token, | | |
| 5998 | .id_cat = .@"capture", | | |
| 5999 | }; | | |
| 6000 | break :blk &capture_val_scope.base; | | |
| 6001 | }; | | |
| 6002 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); | | |
| 6003 | try checkUsed(parent_gz, &case_scope.base, sub_scope); | | |
| 6004 | if (!parent_gz.refIsNoReturn(case_result)) { | | |
| 6005 | block_scope.break_count += 1; | | |
| 6006 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | | |
| 6007 | } | | |
| 6008 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. | | |
| 6009 | try scalar_cases_payload.ensureUnusedCapacity(gpa, case_scope.instructions.items.len + | | |
| 6010 | 3 + // operand, scalar_cases_len, else body len | | |
| 6011 | @boolToInt(multi_cases_len != 0)); | | |
| 6012 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); | | |
| 6013 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); | | |
| 6014 | if (multi_cases_len != 0) { | | |
| 6015 | scalar_cases_payload.appendAssumeCapacity(multi_cases_len); | | |
| 6016 | } | | |
| 6017 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | | |
| 6018 | scalar_cases_payload.appendSliceAssumeCapacity(case_scope.instructions.items); | | |
| 6019 | } else { | | |
| 6020 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. | | |
| 6021 | try scalar_cases_payload.ensureUnusedCapacity( | | |
| 6022 | gpa, | | |
| 6023 | @as(usize, 2) + // operand, scalar_cases_len | | |
| 6024 | @boolToInt(multi_cases_len != 0), | | |
| 6025 | ); | | |
| 6026 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(operand)); | | |
| 6027 | scalar_cases_payload.appendAssumeCapacity(scalar_cases_len); | | |
| 6028 | if (multi_cases_len != 0) { | | |
| 6029 | scalar_cases_payload.appendAssumeCapacity(multi_cases_len); | | |
| 6030 | } | | |
| 6031 | } | | |
| 6032 | | | |
| 6033 | // In this pass we generate all the item and prong expressions except the special case. | | |
| 6034 | var multi_case_index: u32 = 0; | 6004 | var multi_case_index: u32 = 0; |
| 6035 | var scalar_case_index: u32 = 0; | 6005 | var scalar_case_index: u32 = 0; |
| 6036 | for (case_nodes) |case_node| { | 6006 | for (case_nodes) |case_node| { |
| 6037 | if (case_node == special_node) | | |
| 6038 | continue; | | |
| 6039 | const case = switch (node_tags[case_node]) { | 6007 | const case = switch (node_tags[case_node]) { |
| 6040 | .switch_case_one => tree.switchCaseOne(case_node), | 6008 | .switch_case_one => tree.switchCaseOne(case_node), |
| 6041 | .switch_case => tree.switchCase(case_node), | 6009 | .switch_case => tree.switchCase(case_node), |
| ... | @@ -6045,9 +6013,10 @@ fn switchExpr( | ... | @@ -6045,9 +6013,10 @@ fn switchExpr( |
| 6045 | // Reset the scope. | 6013 | // Reset the scope. |
| 6046 | case_scope.instructions.shrinkRetainingCapacity(0); | 6014 | case_scope.instructions.shrinkRetainingCapacity(0); |
| 6047 | | 6015 | |
| 6048 | const is_multi_case = case.ast.values.len != 1 or | 6016 | const is_multi_case = case.ast.values.len > 1 or |
| 6049 | node_tags[case.ast.values[0]] == .switch_range; | 6017 | (case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range); |
| 6050 | | 6018 | |
| | 6019 | var capture_val_scope: Scope.LocalVal = undefined; |
| 6051 | const sub_scope = blk: { | 6020 | const sub_scope = blk: { |
| 6052 | const payload_token = case.payload_token orelse break :blk &case_scope.base; | 6021 | const payload_token = case.payload_token orelse break :blk &case_scope.base; |
| 6053 | const ident = if (token_tags[payload_token] == .asterisk) | 6022 | const ident = if (token_tags[payload_token] == .asterisk) |
| ... | @@ -6061,28 +6030,42 @@ fn switchExpr( | ... | @@ -6061,28 +6030,42 @@ fn switchExpr( |
| 6061 | } | 6030 | } |
| 6062 | break :blk &case_scope.base; | 6031 | break :blk &case_scope.base; |
| 6063 | } | 6032 | } |
| 6064 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); | 6033 | const capture = if (case_node == special_node) capture: { |
| 6065 | const is_ptr_bits: u2 = @boolToInt(is_ptr); | 6034 | const capture_tag: Zir.Inst.Tag = if (is_ptr) |
| 6066 | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { | 6035 | .switch_capture_else_ref |
| 6067 | 0b00 => .switch_capture, | 6036 | else |
| 6068 | 0b01 => .switch_capture_ref, | 6037 | .switch_capture_else; |
| 6069 | 0b10 => .switch_capture_multi, | 6038 | break :capture try case_scope.add(.{ |
| 6070 | 0b11 => .switch_capture_multi_ref, | 6039 | .tag = capture_tag, |
| 6071 | }; | 6040 | .data = .{ .switch_capture = .{ |
| 6072 | const capture_index = if (is_multi_case) ci: { | 6041 | .switch_inst = switch_block, |
| 6073 | multi_case_index += 1; | 6042 | .prong_index = undefined, |
| 6074 | break :ci multi_case_index - 1; | 6043 | } }, |
| 6075 | } else ci: { | 6044 | }); |
| 6076 | scalar_case_index += 1; | 6045 | } else capture: { |
| 6077 | break :ci scalar_case_index - 1; | 6046 | const is_multi_case_bits: u2 = @boolToInt(is_multi_case); |
| | 6047 | const is_ptr_bits: u2 = @boolToInt(is_ptr); |
| | 6048 | const capture_tag: Zir.Inst.Tag = switch ((is_multi_case_bits << 1) | is_ptr_bits) { |
| | 6049 | 0b00 => .switch_capture, |
| | 6050 | 0b01 => .switch_capture_ref, |
| | 6051 | 0b10 => .switch_capture_multi, |
| | 6052 | 0b11 => .switch_capture_multi_ref, |
| | 6053 | }; |
| | 6054 | const capture_index = if (is_multi_case) ci: { |
| | 6055 | multi_case_index += 1; |
| | 6056 | break :ci multi_case_index - 1; |
| | 6057 | } else ci: { |
| | 6058 | scalar_case_index += 1; |
| | 6059 | break :ci scalar_case_index - 1; |
| | 6060 | }; |
| | 6061 | break :capture try case_scope.add(.{ |
| | 6062 | .tag = capture_tag, |
| | 6063 | .data = .{ .switch_capture = .{ |
| | 6064 | .switch_inst = switch_block, |
| | 6065 | .prong_index = capture_index, |
| | 6066 | } }, |
| | 6067 | }); |
| 6078 | }; | 6068 | }; |
| 6079 | const capture = try case_scope.add(.{ | | |
| 6080 | .tag = capture_tag, | | |
| 6081 | .data = .{ .switch_capture = .{ | | |
| 6082 | .switch_inst = switch_block, | | |
| 6083 | .prong_index = capture_index, | | |
| 6084 | } }, | | |
| 6085 | }); | | |
| 6086 | const capture_name = try astgen.identAsString(ident); | 6069 | const capture_name = try astgen.identAsString(ident); |
| 6087 | capture_val_scope = .{ | 6070 | capture_val_scope = .{ |
| 6088 | .parent = &case_scope.base, | 6071 | .parent = &case_scope.base, |
| ... | @@ -6134,6 +6117,17 @@ fn switchExpr( | ... | @@ -6134,6 +6117,17 @@ fn switchExpr( |
| 6134 | multi_cases_payload.items[header_index + 1] = ranges_len; | 6117 | multi_cases_payload.items[header_index + 1] = ranges_len; |
| 6135 | multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len); | 6118 | multi_cases_payload.items[header_index + 2] = @intCast(u32, case_scope.instructions.items.len); |
| 6136 | try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items); | 6119 | try multi_cases_payload.appendSlice(gpa, case_scope.instructions.items); |
| | 6120 | } else if (case_node == special_node) { |
| | 6121 | const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr); |
| | 6122 | try checkUsed(parent_gz, &case_scope.base, sub_scope); |
| | 6123 | if (!parent_gz.refIsNoReturn(case_result)) { |
| | 6124 | block_scope.break_count += 1; |
| | 6125 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| | 6126 | } |
| | 6127 | try special_case_payload.ensureUnusedCapacity(gpa, 1 + // body_len |
| | 6128 | case_scope.instructions.items.len); |
| | 6129 | special_case_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); |
| | 6130 | special_case_payload.appendSliceAssumeCapacity(case_scope.instructions.items); |
| 6137 | } else { | 6131 | } else { |
| 6138 | const item_node = case.ast.values[0]; | 6132 | const item_node = case.ast.values[0]; |
| 6139 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); | 6133 | const item_inst = try comptimeExpr(parent_gz, scope, item_rl, item_node); |
| ... | @@ -6143,7 +6137,7 @@ fn switchExpr( | ... | @@ -6143,7 +6137,7 @@ fn switchExpr( |
| 6143 | block_scope.break_count += 1; | 6137 | block_scope.break_count += 1; |
| 6144 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); | 6138 | _ = try case_scope.addBreak(.@"break", switch_block, case_result); |
| 6145 | } | 6139 | } |
| 6146 | try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 + | 6140 | try scalar_cases_payload.ensureUnusedCapacity(gpa, 2 + // item + body_len |
| 6147 | case_scope.instructions.items.len); | 6141 | case_scope.instructions.items.len); |
| 6148 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); | 6142 | scalar_cases_payload.appendAssumeCapacity(@enumToInt(item_inst)); |
| 6149 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); | 6143 | scalar_cases_payload.appendAssumeCapacity(@intCast(u32, case_scope.instructions.items.len)); |
| ... | @@ -6180,8 +6174,17 @@ fn switchExpr( | ... | @@ -6180,8 +6174,17 @@ fn switchExpr( |
| 6180 | const payload_index = astgen.extra.items.len; | 6174 | const payload_index = astgen.extra.items.len; |
| 6181 | const zir_datas = astgen.instructions.items(.data); | 6175 | const zir_datas = astgen.instructions.items(.data); |
| 6182 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); | 6176 | zir_datas[switch_block].pl_node.payload_index = @intCast(u32, payload_index); |
| 6183 | try astgen.extra.ensureUnusedCapacity(gpa, scalar_cases_payload.items.len + | 6177 | // Documentation for this: `Zir.Inst.SwitchBlock` and `Zir.Inst.SwitchBlockMulti`. |
| | 6178 | try astgen.extra.ensureUnusedCapacity(gpa, @as(usize, 2) + // operand, scalar_cases_len |
| | 6179 | @boolToInt(multi_cases_len != 0) + |
| | 6180 | special_case_payload.items.len + |
| | 6181 | scalar_cases_payload.items.len + |
| 6184 | multi_cases_payload.items.len); | 6182 | multi_cases_payload.items.len); |
| | 6183 | astgen.extra.appendAssumeCapacity(@enumToInt(operand)); |
| | 6184 | astgen.extra.appendAssumeCapacity(scalar_cases_len); |
| | 6185 | if (multi_cases_len != 0) { |
| | 6186 | astgen.extra.appendAssumeCapacity(multi_cases_len); |
| | 6187 | } |
| 6185 | const strat = rl.strategy(&block_scope); | 6188 | const strat = rl.strategy(&block_scope); |
| 6186 | switch (strat.tag) { | 6189 | switch (strat.tag) { |
| 6187 | .break_operand => { | 6190 | .break_operand => { |
| ... | @@ -6189,6 +6192,7 @@ fn switchExpr( | ... | @@ -6189,6 +6192,7 @@ fn switchExpr( |
| 6189 | // `elide_store_to_block_ptr_instructions` will either be true, | 6192 | // `elide_store_to_block_ptr_instructions` will either be true, |
| 6190 | // or all prongs are noreturn. | 6193 | // or all prongs are noreturn. |
| 6191 | if (!strat.elide_store_to_block_ptr_instructions) { | 6194 | if (!strat.elide_store_to_block_ptr_instructions) { |
| | 6195 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items); |
| 6192 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | 6196 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); |
| 6193 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | 6197 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); |
| 6194 | return indexToRef(switch_block); | 6198 | return indexToRef(switch_block); |
| ... | @@ -6204,32 +6208,30 @@ fn switchExpr( | ... | @@ -6204,32 +6208,30 @@ fn switchExpr( |
| 6204 | // it as the break operand. | 6208 | // it as the break operand. |
| 6205 | | 6209 | |
| 6206 | var extra_index: usize = 0; | 6210 | var extra_index: usize = 0; |
| 6207 | extra_index += 2; | | |
| 6208 | extra_index += @boolToInt(multi_cases_len != 0); | | |
| 6209 | if (special_prong != .none) special_prong: { | 6211 | if (special_prong != .none) special_prong: { |
| 6210 | const body_len_index = extra_index; | 6212 | const body_len_index = extra_index; |
| 6211 | const body_len = scalar_cases_payload.items[extra_index]; | 6213 | const body_len = special_case_payload.items[extra_index]; |
| 6212 | extra_index += 1; | 6214 | extra_index += 1; |
| 6213 | if (body_len < 2) { | 6215 | if (body_len < 2) { |
| 6214 | extra_index += body_len; | 6216 | extra_index += body_len; |
| 6215 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 6217 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]); |
| 6216 | break :special_prong; | 6218 | break :special_prong; |
| 6217 | } | 6219 | } |
| 6218 | extra_index += body_len - 2; | 6220 | extra_index += body_len - 2; |
| 6219 | const store_inst = scalar_cases_payload.items[extra_index]; | 6221 | const store_inst = special_case_payload.items[extra_index]; |
| 6220 | if (zir_tags[store_inst] != .store_to_block_ptr or | 6222 | if (zir_tags[store_inst] != .store_to_block_ptr or |
| 6221 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) | 6223 | zir_datas[store_inst].bin.lhs != block_scope.rl_ptr) |
| 6222 | { | 6224 | { |
| 6223 | extra_index += 2; | 6225 | extra_index += 2; |
| 6224 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 6226 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]); |
| 6225 | break :special_prong; | 6227 | break :special_prong; |
| 6226 | } | 6228 | } |
| 6227 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); | 6229 | assert(zir_datas[store_inst].bin.lhs == block_scope.rl_ptr); |
| 6228 | if (block_scope.rl_ty_inst != .none) { | 6230 | if (block_scope.rl_ty_inst != .none) { |
| 6229 | extra_index += 1; | 6231 | extra_index += 1; |
| 6230 | const break_inst = scalar_cases_payload.items[extra_index]; | 6232 | const break_inst = special_case_payload.items[extra_index]; |
| 6231 | extra_index += 1; | 6233 | extra_index += 1; |
| 6232 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 6234 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]); |
| 6233 | zir_tags[store_inst] = .as; | 6235 | zir_tags[store_inst] = .as; |
| 6234 | zir_datas[store_inst].bin = .{ | 6236 | zir_datas[store_inst].bin = .{ |
| 6235 | .lhs = block_scope.rl_ty_inst, | 6237 | .lhs = block_scope.rl_ty_inst, |
| ... | @@ -6237,15 +6239,16 @@ fn switchExpr( | ... | @@ -6237,15 +6239,16 @@ fn switchExpr( |
| 6237 | }; | 6239 | }; |
| 6238 | zir_datas[break_inst].@"break".operand = indexToRef(store_inst); | 6240 | zir_datas[break_inst].@"break".operand = indexToRef(store_inst); |
| 6239 | } else { | 6241 | } else { |
| 6240 | scalar_cases_payload.items[body_len_index] -= 1; | 6242 | special_case_payload.items[body_len_index] -= 1; |
| 6241 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 6243 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]); |
| 6242 | extra_index += 1; | 6244 | extra_index += 1; |
| 6243 | astgen.extra.appendAssumeCapacity(scalar_cases_payload.items[extra_index]); | 6245 | astgen.extra.appendAssumeCapacity(special_case_payload.items[extra_index]); |
| 6244 | extra_index += 1; | 6246 | extra_index += 1; |
| 6245 | } | 6247 | } |
| 6246 | } else { | 6248 | } else { |
| 6247 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items[0..extra_index]); | 6249 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items[0..extra_index]); |
| 6248 | } | 6250 | } |
| | 6251 | extra_index = 0; |
| 6249 | var scalar_i: u32 = 0; | 6252 | var scalar_i: u32 = 0; |
| 6250 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { | 6253 | while (scalar_i < scalar_cases_len) : (scalar_i += 1) { |
| 6251 | const start_index = extra_index; | 6254 | const start_index = extra_index; |
| ... | @@ -6342,6 +6345,7 @@ fn switchExpr( | ... | @@ -6342,6 +6345,7 @@ fn switchExpr( |
| 6342 | }, | 6345 | }, |
| 6343 | .break_void => { | 6346 | .break_void => { |
| 6344 | assert(!strat.elide_store_to_block_ptr_instructions); | 6347 | assert(!strat.elide_store_to_block_ptr_instructions); |
| | 6348 | astgen.extra.appendSliceAssumeCapacity(special_case_payload.items); |
| 6345 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); | 6349 | astgen.extra.appendSliceAssumeCapacity(scalar_cases_payload.items); |
| 6346 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); | 6350 | astgen.extra.appendSliceAssumeCapacity(multi_cases_payload.items); |
| 6347 | // Modify all the terminating instruction tags to become `break` variants. | 6351 | // Modify all the terminating instruction tags to become `break` variants. |
| ... | @@ -9282,6 +9286,9 @@ const Scope = struct { | ... | @@ -9282,6 +9286,9 @@ const Scope = struct { |
| 9282 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. | 9286 | /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`. |
| 9283 | parent: *Scope, | 9287 | parent: *Scope, |
| 9284 | defer_node: Ast.Node.Index, | 9288 | defer_node: Ast.Node.Index, |
| | 9289 | source_offset: u32, |
| | 9290 | source_line: u32, |
| | 9291 | source_column: u32, |
| 9285 | }; | 9292 | }; |
| 9286 | | 9293 | |
| 9287 | /// Represents a global scope that has any number of declarations in it. | 9294 | /// Represents a global scope that has any number of declarations in it. |
| ... | @@ -9563,6 +9570,8 @@ const GenZir = struct { | ... | @@ -9563,6 +9570,8 @@ const GenZir = struct { |
| 9563 | | 9570 | |
| 9564 | fn addFunc(gz: *GenZir, args: struct { | 9571 | fn addFunc(gz: *GenZir, args: struct { |
| 9565 | src_node: Ast.Node.Index, | 9572 | src_node: Ast.Node.Index, |
| | 9573 | lbrace_line: u32 = 0, |
| | 9574 | lbrace_column: u32 = 0, |
| 9566 | body: []const Zir.Inst.Index, | 9575 | body: []const Zir.Inst.Index, |
| 9567 | param_block: Zir.Inst.Index, | 9576 | param_block: Zir.Inst.Index, |
| 9568 | ret_ty: []const Zir.Inst.Index, | 9577 | ret_ty: []const Zir.Inst.Index, |
| ... | @@ -9592,19 +9601,13 @@ const GenZir = struct { | ... | @@ -9592,19 +9601,13 @@ const GenZir = struct { |
| 9592 | const fn_decl = args.src_node; | 9601 | const fn_decl = args.src_node; |
| 9593 | assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); | 9602 | assert(node_tags[fn_decl] == .fn_decl or node_tags[fn_decl] == .test_decl); |
| 9594 | const block = node_datas[fn_decl].rhs; | 9603 | const block = node_datas[fn_decl].rhs; |
| 9595 | const lbrace_start = token_starts[tree.firstToken(block)]; | | |
| 9596 | const rbrace_start = token_starts[tree.lastToken(block)]; | 9604 | const rbrace_start = token_starts[tree.lastToken(block)]; |
| 9597 | | | |
| 9598 | astgen.advanceSourceCursor(tree.source, lbrace_start); | | |
| 9599 | const lbrace_line = @intCast(u32, astgen.source_line); | | |
| 9600 | const lbrace_column = @intCast(u32, astgen.source_column); | | |
| 9601 | | | |
| 9602 | astgen.advanceSourceCursor(tree.source, rbrace_start); | 9605 | astgen.advanceSourceCursor(tree.source, rbrace_start); |
| 9603 | const rbrace_line = @intCast(u32, astgen.source_line); | 9606 | const rbrace_line = @intCast(u32, astgen.source_line); |
| 9604 | const rbrace_column = @intCast(u32, astgen.source_column); | 9607 | const rbrace_column = @intCast(u32, astgen.source_column); |
| 9605 | | 9608 | |
| 9606 | const columns = lbrace_column | (rbrace_column << 16); | 9609 | const columns = args.lbrace_column | (rbrace_column << 16); |
| 9607 | src_locs_buffer[0] = lbrace_line; | 9610 | src_locs_buffer[0] = args.lbrace_line; |
| 9608 | src_locs_buffer[1] = rbrace_line; | 9611 | src_locs_buffer[1] = rbrace_line; |
| 9609 | src_locs_buffer[2] = columns; | 9612 | src_locs_buffer[2] = columns; |
| 9610 | src_locs = &src_locs_buffer; | 9613 | src_locs = &src_locs_buffer; |
| ... | @@ -10577,6 +10580,7 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void { | ... | @@ -10577,6 +10580,7 @@ fn advanceSourceCursor(astgen: *AstGen, source: []const u8, end: usize) void { |
| 10577 | var i = astgen.source_offset; | 10580 | var i = astgen.source_offset; |
| 10578 | var line = astgen.source_line; | 10581 | var line = astgen.source_line; |
| 10579 | var column = astgen.source_column; | 10582 | var column = astgen.source_column; |
| | 10583 | assert(i <= end); |
| 10580 | while (i < end) : (i += 1) { | 10584 | while (i < end) : (i += 1) { |
| 10581 | if (source[i] == '\n') { | 10585 | if (source[i] == '\n') { |
| 10582 | line += 1; | 10586 | line += 1; |