authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-06 08:15:46+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-08 10:53:50+00:00
log03f5b967f0d0dcdcb850061613cdb0793e2d8be2
treeb24253b9f2c865e5564e1503f3533c170df1bd58
parente62aac3ec4b21da20d7c57d937e508f2929138d0
signaturelock-open Commit is signed but in an unrecognized format.

AstGen: correctly deduplicate `ref` of `param` and `alloc_inferred`

Both of these instructions were previously under a special case in `rvalue` which resulted in every reference to such an instruction adding a new `ref` instruction. This had the effect that, for instance, `&a != &a` for parameters. Deduplicating these `ref` instructions was problematic for different reasons. For `alloc_inferred`, the problem was that it's not valid to `ref` the alloc until the allocation has been resolved (`resolve_inferred_alloc`), but `AstGen.appendBodyWithFixups` would place the `ref` directly after the `alloc_inferred`. This is solved by bringing `resolve_inferred_alloc` in line with `make_ptr_const` by having it *return* the final pointer, rather than modifying `sema.inst_map` of the original `alloc_inferred`. That way, the `ref` refers to the `resolve_inferred_alloc` instruction, so is placed immediately after it, avoiding this issue. For `param`, the problem is a bit trickier: `param` instructions live in a body which must contain only `param` instructions, then a `func{,_inferred,_fancy}`, then a `break_inline`. Moreover, `param` instructions may be referenced not only by the function body, but also by other parameters, the return type expression, etc. Each of these bodies requires separate `ref` instructions. This is solved by pulling entries out of `ref_table` after evaluating each component of the function declaration, and appending the refs later on when actually putting the bodies together. This gives way to another issue: if you write `fn f(x: T) @TypeOf(x.foo())`, then since `x.foo()` takes a reference to `x`, this `ref` instruction is now in a comptime context (outside of the `@TypeOf` ZIR body), so emits a compile error. This is solved by loosening the rules around `ref` instructions; because they are not side-effecting, it is okay to allow `ref` of runtime values at comptime, resulting in a runtime-known value in a comptime scope. We already apply this mechanism in some cases; for instance, it's why `runtime_array.len` works in a `comptime` context. In future, we will want to give similar treatment to many operations in Sema: in general, it's fine to apply runtime operations at comptime provided they don't have side effects! Resolves: #22140

4 files changed, 292 insertions(+), 242 deletions(-)

lib/std/zig/AstGen.zig+214-207
......@@ -1373,7 +1373,9 @@ fn fnProtoExpr(
13731373 const main_tokens = tree.nodes.items(.main_token);
13741374 const name_token = param.name_token orelse main_tokens[param_type_node];
13751375 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
1376 const param_inst = try block_scope.addParam(&param_gz, tag, name_token, param_name, param.first_doc_comment);
1376 // We pass `prev_param_insts` as `&.{}` here because a function prototype can't refer to previous
1377 // arguments (we haven't set up scopes here).
1378 const param_inst = try block_scope.addParam(&param_gz, &.{}, tag, name_token, param_name, param.first_doc_comment);
13771379 assert(param_inst_expected == param_inst);
13781380 }
13791381 }
......@@ -1423,6 +1425,13 @@ fn fnProtoExpr(
14231425 .addrspace_ref = .none,
14241426 .addrspace_gz = null,
14251427
1428 .align_param_refs = &.{},
1429 .addrspace_param_refs = &.{},
1430 .section_param_refs = &.{},
1431 .cc_param_refs = &.{},
1432 .ret_param_refs = &.{},
1433 .param_insts = &.{},
1434
14261435 .param_block = block_inst,
14271436 .body_gz = null,
14281437 .lib_name = .empty,
......@@ -3189,28 +3198,13 @@ fn deferStmt(
31893198 try checkUsed(gz, scope, sub_scope);
31903199 _ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);
31913200
3192 // We must handle ref_table for remapped_err_code manually.
31933201 const body = defer_gen.instructionsSlice();
3194 const body_len = blk: {
3195 var refs: u32 = 0;
3196 if (opt_remapped_err_code.unwrap()) |remapped_err_code| {
3197 var cur_inst = remapped_err_code;
3198 while (gz.astgen.ref_table.get(cur_inst)) |ref_inst| {
3199 refs += 1;
3200 cur_inst = ref_inst;
3201 }
3202 }
3203 break :blk gz.astgen.countBodyLenAfterFixups(body) + refs;
3204 };
3202 const extra_insts: []const Zir.Inst.Index = if (opt_remapped_err_code.unwrap()) |ec| &.{ec} else &.{};
3203 const body_len = gz.astgen.countBodyLenAfterFixupsExtraRefs(body, extra_insts);
32053204
32063205 const index: u32 = @intCast(gz.astgen.extra.items.len);
32073206 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len);
3208 if (opt_remapped_err_code.unwrap()) |remapped_err_code| {
3209 if (gz.astgen.ref_table.fetchRemove(remapped_err_code)) |kv| {
3210 gz.astgen.appendPossiblyRefdBodyInst(&gz.astgen.extra, kv.value);
3211 }
3212 }
3213 gz.astgen.appendBodyWithFixups(body);
3207 gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, body, extra_insts);
32143208
32153209 const defer_scope = try block_arena.create(Scope.Defer);
32163210
......@@ -3313,11 +3307,8 @@ fn varDecl(
33133307 const is_comptime = gz.is_comptime or
33143308 tree.nodes.items(.tag)[var_decl.ast.init_node] == .@"comptime";
33153309
3316 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
3317 var opt_type_inst: Zir.Inst.Ref = .none;
33183310 const init_rl: ResultInfo.Loc = if (type_node != 0) init_rl: {
33193311 const type_inst = try typeExpr(gz, scope, type_node);
3320 opt_type_inst = type_inst;
33213312 if (align_inst == .none) {
33223313 break :init_rl .{ .ptr = .{ .inst = try gz.addUnNode(.alloc, type_inst, node) } };
33233314 } else {
......@@ -3345,12 +3336,11 @@ fn varDecl(
33453336 .is_comptime = is_comptime,
33463337 });
33473338 };
3348 resolve_inferred_alloc = alloc_inst;
33493339 break :init_rl .{ .inferred_ptr = alloc_inst };
33503340 };
3351 const var_ptr = switch (init_rl) {
3352 .ptr => |ptr| ptr.inst,
3353 .inferred_ptr => |inst| inst,
3341 const var_ptr: Zir.Inst.Ref, const resolve_inferred: bool = switch (init_rl) {
3342 .ptr => |ptr| .{ ptr.inst, false },
3343 .inferred_ptr => |inst| .{ inst, true },
33543344 else => unreachable,
33553345 };
33563346 const init_result_info: ResultInfo = .{ .rl = init_rl, .ctx = .const_init };
......@@ -3365,10 +3355,10 @@ fn varDecl(
33653355 if (nodeMayAppendToErrorTrace(tree, var_decl.ast.init_node))
33663356 _ = try gz.addSaveErrRetIndex(.{ .if_of_error_type = init_inst });
33673357
3368 const const_ptr = if (resolve_inferred_alloc != .none) p: {
3369 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
3370 break :p var_ptr;
3371 } else try gz.addUnNode(.make_ptr_const, var_ptr, node);
3358 const const_ptr = if (resolve_inferred)
3359 try gz.addUnNode(.resolve_inferred_alloc, var_ptr, node)
3360 else
3361 try gz.addUnNode(.make_ptr_const, var_ptr, node);
33723362
33733363 try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr);
33743364
......@@ -3388,8 +3378,7 @@ fn varDecl(
33883378 if (var_decl.comptime_token != null and gz.is_comptime)
33893379 return astgen.failTok(var_decl.comptime_token.?, "'comptime var' is redundant in comptime scope", .{});
33903380 const is_comptime = var_decl.comptime_token != null or gz.is_comptime;
3391 var resolve_inferred_alloc: Zir.Inst.Ref = .none;
3392 const alloc: Zir.Inst.Ref, const result_info: ResultInfo = if (var_decl.ast.type_node != 0) a: {
3381 const alloc: Zir.Inst.Ref, const resolve_inferred: bool, const result_info: ResultInfo = if (var_decl.ast.type_node != 0) a: {
33933382 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
33943383 const alloc = alloc: {
33953384 if (align_inst == .none) {
......@@ -3408,7 +3397,7 @@ fn varDecl(
34083397 });
34093398 }
34103399 };
3411 break :a .{ alloc, .{ .rl = .{ .ptr = .{ .inst = alloc } } } };
3400 break :a .{ alloc, false, .{ .rl = .{ .ptr = .{ .inst = alloc } } } };
34123401 } else a: {
34133402 const alloc = alloc: {
34143403 if (align_inst == .none) {
......@@ -3427,25 +3416,24 @@ fn varDecl(
34273416 });
34283417 }
34293418 };
3430 resolve_inferred_alloc = alloc;
3431 break :a .{ alloc, .{ .rl = .{ .inferred_ptr = alloc } } };
3419 break :a .{ alloc, true, .{ .rl = .{ .inferred_ptr = alloc } } };
34323420 };
34333421 const prev_anon_name_strategy = gz.anon_name_strategy;
34343422 gz.anon_name_strategy = .dbg_var;
34353423 _ = try reachableExprComptime(gz, scope, result_info, var_decl.ast.init_node, node, is_comptime);
34363424 gz.anon_name_strategy = prev_anon_name_strategy;
3437 if (resolve_inferred_alloc != .none) {
3438 _ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
3439 }
3425 const final_ptr: Zir.Inst.Ref = if (resolve_inferred) ptr: {
3426 break :ptr try gz.addUnNode(.resolve_inferred_alloc, alloc, node);
3427 } else alloc;
34403428
3441 try gz.addDbgVar(.dbg_var_ptr, ident_name, alloc);
3429 try gz.addDbgVar(.dbg_var_ptr, ident_name, final_ptr);
34423430
34433431 const sub_scope = try block_arena.create(Scope.LocalPtr);
34443432 sub_scope.* = .{
34453433 .parent = scope,
34463434 .gen_zir = gz,
34473435 .name = ident_name,
3448 .ptr = alloc,
3436 .ptr = final_ptr,
34493437 .token_src = name_token,
34503438 .maybe_comptime = is_comptime,
34513439 .id_cat = .@"local variable",
......@@ -3726,26 +3714,25 @@ fn assignDestructureMaybeDecls(
37263714 else => continue, // We were mutating an existing lvalue - nothing to do
37273715 }
37283716 const full_var_decl = tree.fullVarDecl(variable_node).?;
3729 const raw_ptr = switch (variable_rl) {
3717 const raw_ptr, const resolve_inferred = switch (variable_rl) {
37303718 .discard => unreachable,
3731 .typed_ptr => |typed_ptr| typed_ptr.inst,
3732 .inferred_ptr => |ptr_inst| ptr_inst,
3719 .typed_ptr => |typed_ptr| .{ typed_ptr.inst, false },
3720 .inferred_ptr => |ptr_inst| .{ ptr_inst, true },
37333721 };
3734 // If the alloc was inferred, resolve it.
3735 if (full_var_decl.ast.type_node == 0) {
3736 _ = try gz.addUnNode(.resolve_inferred_alloc, raw_ptr, variable_node);
3737 }
37383722 const is_const = switch (token_tags[full_var_decl.ast.mut_token]) {
37393723 .keyword_var => false,
37403724 .keyword_const => true,
37413725 else => unreachable,
37423726 };
3743 // If the alloc was const, make it const.
3744 const var_ptr = if (is_const and full_var_decl.ast.type_node != 0) make_const: {
3745 // Note that we don't do this if type_node == 0 since `resolve_inferred_alloc`
3746 // handles it for us.
3747 break :make_const try gz.addUnNode(.make_ptr_const, raw_ptr, node);
3748 } else raw_ptr;
3727
3728 // If the alloc was inferred, resolve it. If the alloc was const, make it const.
3729 const final_ptr = if (resolve_inferred)
3730 try gz.addUnNode(.resolve_inferred_alloc, raw_ptr, variable_node)
3731 else if (is_const)
3732 try gz.addUnNode(.make_ptr_const, raw_ptr, node)
3733 else
3734 raw_ptr;
3735
37493736 const name_token = full_var_decl.ast.mut_token + 1;
37503737 const ident_name_raw = tree.tokenSlice(name_token);
37513738 const ident_name = try astgen.identAsString(name_token);
......@@ -3756,14 +3743,14 @@ fn assignDestructureMaybeDecls(
37563743 ident_name_raw,
37573744 if (is_const) .@"local constant" else .@"local variable",
37583745 );
3759 try gz.addDbgVar(.dbg_var_ptr, ident_name, var_ptr);
3746 try gz.addDbgVar(.dbg_var_ptr, ident_name, final_ptr);
37603747 // Finally, create the scope.
37613748 const sub_scope = try block_arena.create(Scope.LocalPtr);
37623749 sub_scope.* = .{
37633750 .parent = cur_scope,
37643751 .gen_zir = gz,
37653752 .name = ident_name,
3766 .ptr = var_ptr,
3753 .ptr = final_ptr,
37673754 .token_src = name_token,
37683755 .maybe_comptime = is_const or is_comptime,
37693756 .id_cat = if (is_const) .@"local constant" else .@"local variable",
......@@ -4182,6 +4169,9 @@ fn fnDecl(
41824169
41834170 wip_members.nextDecl(decl_inst);
41844171
4172 // Note that the capacity here may not be sufficient, as this does not include `anytype` parameters.
4173 var param_insts: std.ArrayListUnmanaged(Zir.Inst.Index) = try .initCapacity(astgen.arena, fn_proto.ast.params.len);
4174
41854175 var noalias_bits: u32 = 0;
41864176 var params_scope = &fn_gz.base;
41874177 const is_var_args = is_var_args: {
......@@ -4266,7 +4256,7 @@ fn fnDecl(
42664256 const main_tokens = tree.nodes.items(.main_token);
42674257 const name_token = param.name_token orelse main_tokens[param_type_node];
42684258 const tag: Zir.Inst.Tag = if (is_comptime) .param_comptime else .param;
4269 const param_inst = try decl_gz.addParam(&param_gz, tag, name_token, param_name, param.first_doc_comment);
4259 const param_inst = try decl_gz.addParam(&param_gz, param_insts.items, tag, name_token, param_name, param.first_doc_comment);
42704260 assert(param_inst_expected == param_inst);
42714261 break :param param_inst.toRef();
42724262 };
......@@ -4283,6 +4273,7 @@ fn fnDecl(
42834273 .id_cat = .@"function parameter",
42844274 };
42854275 params_scope = &sub_scope.base;
4276 try param_insts.append(astgen.arena, param_inst.toIndex().?);
42864277 }
42874278 break :is_var_args false;
42884279 };
......@@ -4316,6 +4307,7 @@ fn fnDecl(
43164307 _ = try align_gz.addBreak(.break_inline, @enumFromInt(0), inst);
43174308 break :inst inst;
43184309 };
4310 const align_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43194311
43204312 var addrspace_gz = decl_gz.makeSubBlock(params_scope);
43214313 defer addrspace_gz.unstack();
......@@ -4329,6 +4321,7 @@ fn fnDecl(
43294321 _ = try addrspace_gz.addBreak(.break_inline, @enumFromInt(0), inst);
43304322 break :inst inst;
43314323 };
4324 const addrspace_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43324325
43334326 var section_gz = decl_gz.makeSubBlock(params_scope);
43344327 defer section_gz.unstack();
......@@ -4341,6 +4334,7 @@ fn fnDecl(
43414334 _ = try section_gz.addBreak(.break_inline, @enumFromInt(0), inst);
43424335 break :inst inst;
43434336 };
4337 const section_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43444338
43454339 var cc_gz = decl_gz.makeSubBlock(params_scope);
43464340 defer cc_gz.unstack();
......@@ -4377,6 +4371,7 @@ fn fnDecl(
43774371 break :blk .none;
43784372 }
43794373 };
4374 const cc_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43804375
43814376 var ret_gz = decl_gz.makeSubBlock(params_scope);
43824377 defer ret_gz.unstack();
......@@ -4389,6 +4384,7 @@ fn fnDecl(
43894384 _ = try ret_gz.addBreak(.break_inline, @enumFromInt(0), inst);
43904385 break :inst inst;
43914386 };
4387 const ret_body_param_refs = try astgen.fetchRemoveRefEntries(param_insts.items);
43924388
43934389 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
43944390 if (!is_extern) {
......@@ -4401,15 +4397,21 @@ fn fnDecl(
44014397 .src_node = decl_node,
44024398 .cc_ref = cc_ref,
44034399 .cc_gz = &cc_gz,
4400 .cc_param_refs = cc_body_param_refs,
44044401 .align_ref = align_ref,
44054402 .align_gz = &align_gz,
4403 .align_param_refs = align_body_param_refs,
44064404 .ret_ref = ret_ref,
44074405 .ret_gz = &ret_gz,
4406 .ret_param_refs = ret_body_param_refs,
44084407 .section_ref = section_ref,
44094408 .section_gz = &section_gz,
4409 .section_param_refs = section_body_param_refs,
44104410 .addrspace_ref = addrspace_ref,
44114411 .addrspace_gz = &addrspace_gz,
4412 .addrspace_param_refs = addrspace_body_param_refs,
44124413 .param_block = decl_inst,
4414 .param_insts = param_insts.items,
44134415 .body_gz = null,
44144416 .lib_name = lib_name,
44154417 .is_var_args = is_var_args,
......@@ -4471,17 +4473,23 @@ fn fnDecl(
44714473 .src_node = decl_node,
44724474 .cc_ref = cc_ref,
44734475 .cc_gz = &cc_gz,
4476 .cc_param_refs = cc_body_param_refs,
44744477 .align_ref = align_ref,
44754478 .align_gz = &align_gz,
4479 .align_param_refs = align_body_param_refs,
44764480 .ret_ref = ret_ref,
44774481 .ret_gz = &ret_gz,
4482 .ret_param_refs = ret_body_param_refs,
44784483 .section_ref = section_ref,
44794484 .section_gz = &section_gz,
4485 .section_param_refs = section_body_param_refs,
44804486 .addrspace_ref = addrspace_ref,
44814487 .addrspace_gz = &addrspace_gz,
4488 .addrspace_param_refs = addrspace_body_param_refs,
44824489 .lbrace_line = lbrace_line,
44834490 .lbrace_column = lbrace_column,
44844491 .param_block = decl_inst,
4492 .param_insts = param_insts.items,
44854493 .body_gz = &fn_gz,
44864494 .lib_name = lib_name,
44874495 .is_var_args = is_var_args,
......@@ -4972,6 +4980,13 @@ fn testDecl(
49724980 .addrspace_ref = .none,
49734981 .addrspace_gz = null,
49744982
4983 .align_param_refs = &.{},
4984 .addrspace_param_refs = &.{},
4985 .section_param_refs = &.{},
4986 .cc_param_refs = &.{},
4987 .ret_param_refs = &.{},
4988 .param_insts = &.{},
4989
49754990 .lbrace_line = lbrace_line,
49764991 .lbrace_column = lbrace_column,
49774992 .param_block = decl_inst,
......@@ -7429,19 +7444,7 @@ fn switchExprErrUnion(
74297444 }
74307445
74317446 const case_slice = case_scope.instructionsSlice();
7432 // Since we use the switch_block_err_union instruction itself to refer
7433 // to the capture, which will not be added to the child block, we need
7434 // to handle ref_table manually.
7435 const refs_len = refs: {
7436 var n: usize = 0;
7437 var check_inst = switch_block;
7438 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7439 n += 1;
7440 check_inst = ref_inst;
7441 }
7442 break :refs n;
7443 };
7444 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
7447 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(case_slice, &.{switch_block});
74457448 try payloads.ensureUnusedCapacity(gpa, body_len);
74467449 const capture: Zir.Inst.SwitchBlock.ProngInfo.Capture = switch (node_ty) {
74477450 .@"catch" => .none,
......@@ -7458,10 +7461,7 @@ fn switchExprErrUnion(
74587461 .is_inline = false,
74597462 .has_tag_capture = false,
74607463 });
7461 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
7462 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7463 }
7464 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
7464 appendBodyWithFixupsExtraRefsArrayList(astgen, payloads, case_slice, &.{switch_block});
74657465 }
74667466
74677467 const err_name = blk: {
......@@ -7624,26 +7624,8 @@ fn switchExprErrUnion(
76247624 }
76257625
76267626 const case_slice = case_scope.instructionsSlice();
7627 // Since we use the switch_block_err_union instruction itself to refer
7628 // to the capture, which will not be added to the child block, we need
7629 // to handle ref_table manually.
7630 const refs_len = refs: {
7631 var n: usize = 0;
7632 var check_inst = switch_block;
7633 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7634 n += 1;
7635 check_inst = ref_inst;
7636 }
7637 if (uses_err) {
7638 check_inst = err_inst;
7639 while (astgen.ref_table.get(check_inst)) |ref_inst| {
7640 n += 1;
7641 check_inst = ref_inst;
7642 }
7643 }
7644 break :refs n;
7645 };
7646 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
7627 const extra_insts: []const Zir.Inst.Index = if (uses_err) &.{ switch_block, err_inst } else &.{switch_block};
7628 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(case_slice, extra_insts);
76477629 try payloads.ensureUnusedCapacity(gpa, body_len);
76487630 payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{
76497631 .body_len = @intCast(body_len),
......@@ -7651,15 +7633,7 @@ fn switchExprErrUnion(
76517633 .is_inline = case.inline_token != null,
76527634 .has_tag_capture = false,
76537635 });
7654 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
7655 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7656 }
7657 if (uses_err) {
7658 if (astgen.ref_table.fetchRemove(err_inst)) |kv| {
7659 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
7660 }
7661 }
7662 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
7636 appendBodyWithFixupsExtraRefsArrayList(astgen, payloads, case_slice, extra_insts);
76637637 }
76647638 }
76657639 // Now that the item expressions are generated we can add this.
......@@ -8106,27 +8080,8 @@ fn switchExpr(
81068080 }
81078081
81088082 const case_slice = case_scope.instructionsSlice();
8109 // Since we use the switch_block instruction itself to refer to the
8110 // capture, which will not be added to the child block, we need to
8111 // handle ref_table manually, and the same for the inline tag
8112 // capture instruction.
8113 const refs_len = refs: {
8114 var n: usize = 0;
8115 var check_inst = switch_block;
8116 while (astgen.ref_table.get(check_inst)) |ref_inst| {
8117 n += 1;
8118 check_inst = ref_inst;
8119 }
8120 if (has_tag_capture) {
8121 check_inst = tag_inst;
8122 while (astgen.ref_table.get(check_inst)) |ref_inst| {
8123 n += 1;
8124 check_inst = ref_inst;
8125 }
8126 }
8127 break :refs n;
8128 };
8129 const body_len = refs_len + astgen.countBodyLenAfterFixups(case_slice);
8083 const extra_insts: []const Zir.Inst.Index = if (has_tag_capture) &.{ switch_block, tag_inst } else &.{switch_block};
8084 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(case_slice, extra_insts);
81308085 try payloads.ensureUnusedCapacity(gpa, body_len);
81318086 payloads.items[body_len_index] = @bitCast(Zir.Inst.SwitchBlock.ProngInfo{
81328087 .body_len = @intCast(body_len),
......@@ -8134,15 +8089,7 @@ fn switchExpr(
81348089 .is_inline = case.inline_token != null,
81358090 .has_tag_capture = has_tag_capture,
81368091 });
8137 if (astgen.ref_table.fetchRemove(switch_block)) |kv| {
8138 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
8139 }
8140 if (has_tag_capture) {
8141 if (astgen.ref_table.fetchRemove(tag_inst)) |kv| {
8142 appendPossiblyRefdBodyInst(astgen, payloads, kv.value);
8143 }
8144 }
8145 appendBodyWithFixupsArrayList(astgen, payloads, case_slice);
8092 appendBodyWithFixupsExtraRefsArrayList(astgen, payloads, case_slice, extra_insts);
81468093 }
81478094 }
81488095
......@@ -11201,9 +11148,6 @@ fn rvalueInner(
1120111148 const src_token = tree.firstToken(src_node);
1120211149 const result_index = coerced_result.toIndex() orelse
1120311150 return gz.addUnTok(.ref, coerced_result, src_token);
11204 const zir_tags = gz.astgen.instructions.items(.tag);
11205 if (zir_tags[@intFromEnum(result_index)].isParam() or astgen.isInferred(coerced_result))
11206 return gz.addUnTok(.ref, coerced_result, src_token);
1120711151 const gop = try astgen.ref_table.getOrPut(astgen.gpa, result_index);
1120811152 if (!gop.found_existing) {
1120911153 gop.value_ptr.* = try gz.makeUnTok(.ref, coerced_result, src_token);
......@@ -12232,36 +12176,46 @@ const GenZir = struct {
1223212176 /// * ret_gz
1223312177 /// * body_gz (top)
1223412178 /// Unstacks all of those except for `gz`.
12235 fn addFunc(gz: *GenZir, args: struct {
12236 src_node: Ast.Node.Index,
12237 lbrace_line: u32 = 0,
12238 lbrace_column: u32 = 0,
12239 param_block: Zir.Inst.Index,
12240
12241 align_gz: ?*GenZir,
12242 addrspace_gz: ?*GenZir,
12243 section_gz: ?*GenZir,
12244 cc_gz: ?*GenZir,
12245 ret_gz: ?*GenZir,
12246 body_gz: ?*GenZir,
12247
12248 align_ref: Zir.Inst.Ref,
12249 addrspace_ref: Zir.Inst.Ref,
12250 section_ref: Zir.Inst.Ref,
12251 cc_ref: Zir.Inst.Ref,
12252 ret_ref: Zir.Inst.Ref,
12253
12254 lib_name: Zir.NullTerminatedString,
12255 noalias_bits: u32,
12256 is_var_args: bool,
12257 is_inferred_error: bool,
12258 is_test: bool,
12259 is_extern: bool,
12260 is_noinline: bool,
12261
12262 /// Ignored if `body_gz == null`.
12263 proto_hash: std.zig.SrcHash,
12264 }) !Zir.Inst.Ref {
12179 fn addFunc(
12180 gz: *GenZir,
12181 args: struct {
12182 src_node: Ast.Node.Index,
12183 lbrace_line: u32 = 0,
12184 lbrace_column: u32 = 0,
12185 param_block: Zir.Inst.Index,
12186
12187 align_gz: ?*GenZir,
12188 addrspace_gz: ?*GenZir,
12189 section_gz: ?*GenZir,
12190 cc_gz: ?*GenZir,
12191 ret_gz: ?*GenZir,
12192 body_gz: ?*GenZir,
12193
12194 align_param_refs: []Zir.Inst.Index,
12195 addrspace_param_refs: []Zir.Inst.Index,
12196 section_param_refs: []Zir.Inst.Index,
12197 cc_param_refs: []Zir.Inst.Index,
12198 ret_param_refs: []Zir.Inst.Index,
12199 param_insts: []Zir.Inst.Index, // refs to params in `body_gz` should still be in `astgen.ref_table`
12200
12201 align_ref: Zir.Inst.Ref,
12202 addrspace_ref: Zir.Inst.Ref,
12203 section_ref: Zir.Inst.Ref,
12204 cc_ref: Zir.Inst.Ref,
12205 ret_ref: Zir.Inst.Ref,
12206
12207 lib_name: Zir.NullTerminatedString,
12208 noalias_bits: u32,
12209 is_var_args: bool,
12210 is_inferred_error: bool,
12211 is_test: bool,
12212 is_extern: bool,
12213 is_noinline: bool,
12214
12215 /// Ignored if `body_gz == null`.
12216 proto_hash: std.zig.SrcHash,
12217 },
12218 ) !Zir.Inst.Ref {
1226512219 assert(args.src_node != 0);
1226612220 const astgen = gz.astgen;
1226712221 const gpa = astgen.gpa;
......@@ -12309,7 +12263,7 @@ const GenZir = struct {
1230912263 if (args.ret_gz) |ret_gz|
1231012264 ret_body = ret_gz.instructionsSlice();
1231112265 }
12312 const body_len = astgen.countBodyLenAfterFixups(body);
12266 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(body, args.param_insts);
1231312267
1231412268 if (args.cc_ref != .none or args.lib_name != .empty or args.is_var_args or args.is_test or
1231512269 args.is_extern or args.align_ref != .none or args.section_ref != .none or
......@@ -12329,11 +12283,11 @@ const GenZir = struct {
1232912283 try astgen.extra.ensureUnusedCapacity(
1233012284 gpa,
1233112285 @typeInfo(Zir.Inst.FuncFancy).@"struct".fields.len +
12332 fancyFnExprExtraLen(astgen, align_body, args.align_ref) +
12333 fancyFnExprExtraLen(astgen, addrspace_body, args.addrspace_ref) +
12334 fancyFnExprExtraLen(astgen, section_body, args.section_ref) +
12335 fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) +
12336 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +
12286 fancyFnExprExtraLen(astgen, args.align_param_refs, align_body, args.align_ref) +
12287 fancyFnExprExtraLen(astgen, args.addrspace_param_refs, addrspace_body, args.addrspace_ref) +
12288 fancyFnExprExtraLen(astgen, args.section_param_refs, section_body, args.section_ref) +
12289 fancyFnExprExtraLen(astgen, args.cc_param_refs, cc_body, args.cc_ref) +
12290 fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) +
1233712291 body_len + src_locs_and_hash.len +
1233812292 @intFromBool(args.lib_name != .empty) +
1233912293 @intFromBool(args.noalias_bits != 0),
......@@ -12369,7 +12323,11 @@ const GenZir = struct {
1236912323
1237012324 const zir_datas = astgen.instructions.items(.data);
1237112325 if (align_body.len != 0) {
12372 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, align_body));
12326 astgen.extra.appendAssumeCapacity(
12327 astgen.countBodyLenAfterFixups(args.align_param_refs) +
12328 astgen.countBodyLenAfterFixups(align_body),
12329 );
12330 astgen.appendBodyWithFixups(args.align_param_refs);
1237312331 astgen.appendBodyWithFixups(align_body);
1237412332 const break_extra = zir_datas[@intFromEnum(align_body[align_body.len - 1])].@"break".payload_index;
1237512333 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
......@@ -12378,7 +12336,11 @@ const GenZir = struct {
1237812336 astgen.extra.appendAssumeCapacity(@intFromEnum(args.align_ref));
1237912337 }
1238012338 if (addrspace_body.len != 0) {
12381 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, addrspace_body));
12339 astgen.extra.appendAssumeCapacity(
12340 astgen.countBodyLenAfterFixups(args.addrspace_param_refs) +
12341 astgen.countBodyLenAfterFixups(addrspace_body),
12342 );
12343 astgen.appendBodyWithFixups(args.addrspace_param_refs);
1238212344 astgen.appendBodyWithFixups(addrspace_body);
1238312345 const break_extra =
1238412346 zir_datas[@intFromEnum(addrspace_body[addrspace_body.len - 1])].@"break".payload_index;
......@@ -12388,7 +12350,11 @@ const GenZir = struct {
1238812350 astgen.extra.appendAssumeCapacity(@intFromEnum(args.addrspace_ref));
1238912351 }
1239012352 if (section_body.len != 0) {
12391 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, section_body));
12353 astgen.extra.appendAssumeCapacity(
12354 astgen.countBodyLenAfterFixups(args.section_param_refs) +
12355 astgen.countBodyLenAfterFixups(section_body),
12356 );
12357 astgen.appendBodyWithFixups(args.section_param_refs);
1239212358 astgen.appendBodyWithFixups(section_body);
1239312359 const break_extra =
1239412360 zir_datas[@intFromEnum(section_body[section_body.len - 1])].@"break".payload_index;
......@@ -12398,7 +12364,11 @@ const GenZir = struct {
1239812364 astgen.extra.appendAssumeCapacity(@intFromEnum(args.section_ref));
1239912365 }
1240012366 if (cc_body.len != 0) {
12401 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, cc_body));
12367 astgen.extra.appendAssumeCapacity(
12368 astgen.countBodyLenAfterFixups(args.cc_param_refs) +
12369 astgen.countBodyLenAfterFixups(cc_body),
12370 );
12371 astgen.appendBodyWithFixups(args.cc_param_refs);
1240212372 astgen.appendBodyWithFixups(cc_body);
1240312373 const break_extra = zir_datas[@intFromEnum(cc_body[cc_body.len - 1])].@"break".payload_index;
1240412374 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
......@@ -12407,7 +12377,11 @@ const GenZir = struct {
1240712377 astgen.extra.appendAssumeCapacity(@intFromEnum(args.cc_ref));
1240812378 }
1240912379 if (ret_body.len != 0) {
12410 astgen.extra.appendAssumeCapacity(countBodyLenAfterFixups(astgen, ret_body));
12380 astgen.extra.appendAssumeCapacity(
12381 astgen.countBodyLenAfterFixups(args.ret_param_refs) +
12382 astgen.countBodyLenAfterFixups(ret_body),
12383 );
12384 astgen.appendBodyWithFixups(args.ret_param_refs);
1241112385 astgen.appendBodyWithFixups(ret_body);
1241212386 const break_extra = zir_datas[@intFromEnum(ret_body[ret_body.len - 1])].@"break".payload_index;
1241312387 astgen.extra.items[break_extra + std.meta.fieldIndex(Zir.Inst.Break, "block_inst").?] =
......@@ -12420,7 +12394,7 @@ const GenZir = struct {
1242012394 astgen.extra.appendAssumeCapacity(args.noalias_bits);
1242112395 }
1242212396
12423 astgen.appendBodyWithFixups(body);
12397 astgen.appendBodyWithFixupsExtraRefsArrayList(&astgen.extra, body, args.param_insts);
1242412398 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1242512399
1242612400 // Order is important when unstacking.
......@@ -12448,12 +12422,12 @@ const GenZir = struct {
1244812422 try astgen.extra.ensureUnusedCapacity(
1244912423 gpa,
1245012424 @typeInfo(Zir.Inst.Func).@"struct".fields.len + 1 +
12451 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +
12425 fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) +
1245212426 body_len + src_locs_and_hash.len,
1245312427 );
1245412428
1245512429 const ret_body_len = if (ret_body.len != 0)
12456 countBodyLenAfterFixups(astgen, ret_body)
12430 countBodyLenAfterFixups(astgen, args.ret_param_refs) + countBodyLenAfterFixups(astgen, ret_body)
1245712431 else
1245812432 @intFromBool(ret_ref != .none);
1245912433
......@@ -12464,6 +12438,7 @@ const GenZir = struct {
1246412438 });
1246512439 const zir_datas = astgen.instructions.items(.data);
1246612440 if (ret_body.len != 0) {
12441 astgen.appendBodyWithFixups(args.ret_param_refs);
1246712442 astgen.appendBodyWithFixups(ret_body);
1246812443
1246912444 const break_extra = zir_datas[@intFromEnum(ret_body[ret_body.len - 1])].@"break".payload_index;
......@@ -12472,7 +12447,7 @@ const GenZir = struct {
1247212447 } else if (ret_ref != .none) {
1247312448 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));
1247412449 }
12475 astgen.appendBodyWithFixups(body);
12450 astgen.appendBodyWithFixupsExtraRefsArrayList(&astgen.extra, body, args.param_insts);
1247612451 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1247712452
1247812453 // Order is important when unstacking.
......@@ -12498,10 +12473,11 @@ const GenZir = struct {
1249812473 }
1249912474 }
1250012475
12501 fn fancyFnExprExtraLen(astgen: *AstGen, body: []Zir.Inst.Index, ref: Zir.Inst.Ref) u32 {
12502 // In the case of non-empty body, there is one for the body length,
12503 // and then one for each instruction.
12504 return countBodyLenAfterFixups(astgen, body) + @intFromBool(ref != .none);
12476 fn fancyFnExprExtraLen(astgen: *AstGen, param_refs_body: []Zir.Inst.Index, main_body: []Zir.Inst.Index, ref: Zir.Inst.Ref) u32 {
12477 return countBodyLenAfterFixups(astgen, param_refs_body) +
12478 countBodyLenAfterFixups(astgen, main_body) +
12479 // If there is a body, we need an element for its length; otherwise, if there is a ref, we need to include that.
12480 @intFromBool(main_body.len > 0 or ref != .none);
1250512481 }
1250612482
1250712483 fn addVar(gz: *GenZir, args: struct {
......@@ -12673,6 +12649,9 @@ const GenZir = struct {
1267312649 fn addParam(
1267412650 gz: *GenZir,
1267512651 param_gz: *GenZir,
12652 /// Previous parameters, which might be referenced in `param_gz` (the new parameter type).
12653 /// `ref`s of these instructions will be put into this param's type body, and removed from `AstGen.ref_table`.
12654 prev_param_insts: []const Zir.Inst.Index,
1267612655 tag: Zir.Inst.Tag,
1267712656 /// Absolute token index. This function does the conversion to Decl offset.
1267812657 abs_tok_index: Ast.TokenIndex,
......@@ -12681,7 +12660,7 @@ const GenZir = struct {
1268112660 ) !Zir.Inst.Index {
1268212661 const gpa = gz.astgen.gpa;
1268312662 const param_body = param_gz.instructionsSlice();
12684 const body_len = gz.astgen.countBodyLenAfterFixups(param_body);
12663 const body_len = gz.astgen.countBodyLenAfterFixupsExtraRefs(param_body, prev_param_insts);
1268512664 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
1268612665 try gz.astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.Param).@"struct".fields.len + body_len);
1268712666
......@@ -12695,7 +12674,7 @@ const GenZir = struct {
1269512674 .doc_comment = doc_comment_index,
1269612675 .body_len = @intCast(body_len),
1269712676 });
12698 gz.astgen.appendBodyWithFixups(param_body);
12677 gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, param_body, prev_param_insts);
1269912678 param_gz.unstack();
1270012679
1270112680 const new_index: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
......@@ -13938,27 +13917,6 @@ fn scanContainer(
1393813917 return decl_count;
1393913918}
1394013919
13941fn isInferred(astgen: *AstGen, ref: Zir.Inst.Ref) bool {
13942 const inst = ref.toIndex() orelse return false;
13943 const zir_tags = astgen.instructions.items(.tag);
13944 return switch (zir_tags[@intFromEnum(inst)]) {
13945 .alloc_inferred,
13946 .alloc_inferred_mut,
13947 .alloc_inferred_comptime,
13948 .alloc_inferred_comptime_mut,
13949 => true,
13950
13951 .extended => {
13952 const zir_data = astgen.instructions.items(.data);
13953 if (zir_data[@intFromEnum(inst)].extended.opcode != .alloc) return false;
13954 const small: Zir.Inst.AllocExtended.Small = @bitCast(zir_data[@intFromEnum(inst)].extended.small);
13955 return !small.has_type;
13956 },
13957
13958 else => false,
13959 };
13960}
13961
1396213920/// Assumes capacity for body has already been added. Needed capacity taking into
1396313921/// account fixups can be found with `countBodyLenAfterFixups`.
1396413922fn appendBodyWithFixups(astgen: *AstGen, body: []const Zir.Inst.Index) void {
......@@ -13970,6 +13928,20 @@ fn appendBodyWithFixupsArrayList(
1397013928 list: *std.ArrayListUnmanaged(u32),
1397113929 body: []const Zir.Inst.Index,
1397213930) void {
13931 astgen.appendBodyWithFixupsExtraRefsArrayList(list, body, &.{});
13932}
13933
13934fn appendBodyWithFixupsExtraRefsArrayList(
13935 astgen: *AstGen,
13936 list: *std.ArrayListUnmanaged(u32),
13937 body: []const Zir.Inst.Index,
13938 extra_refs: []const Zir.Inst.Index,
13939) void {
13940 for (extra_refs) |extra_inst| {
13941 if (astgen.ref_table.fetchRemove(extra_inst)) |kv| {
13942 appendPossiblyRefdBodyInst(astgen, list, kv.value);
13943 }
13944 }
1397313945 for (body) |body_inst| {
1397413946 appendPossiblyRefdBodyInst(astgen, list, body_inst);
1397513947 }
......@@ -13987,6 +13959,14 @@ fn appendPossiblyRefdBodyInst(
1398713959}
1398813960
1398913961fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
13962 return astgen.countBodyLenAfterFixupsExtraRefs(body, &.{});
13963}
13964
13965/// Return the number of instructions in `body` after prepending the `ref` instructions in `ref_table`.
13966/// As well as all instructions in `body`, we also prepend `ref`s of any instruction in `extra_refs`.
13967/// For instance, if an index has been reserved with a special meaning to a child block, it must be
13968/// passed to `extra_refs` to ensure `ref`s of that index are added correctly.
13969fn countBodyLenAfterFixupsExtraRefs(astgen: *AstGen, body: []const Zir.Inst.Index, extra_refs: []const Zir.Inst.Index) u32 {
1399013970 var count = body.len;
1399113971 for (body) |body_inst| {
1399213972 var check_inst = body_inst;
......@@ -13995,6 +13975,13 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
1399513975 check_inst = ref_inst;
1399613976 }
1399713977 }
13978 for (extra_refs) |extra_inst| {
13979 var check_inst = extra_inst;
13980 while (astgen.ref_table.get(check_inst)) |ref_inst| {
13981 count += 1;
13982 check_inst = ref_inst;
13983 }
13984 }
1399813985 return @intCast(count);
1399913986}
1400013987
......@@ -14176,3 +14163,23 @@ fn setDeclaration(
1417614163 }
1417714164 value_gz.unstack();
1417814165}
14166
14167/// Given a list of instructions, returns a list of all instructions which are a `ref` of one of the originals,
14168/// from `astgen.ref_table`, non-recursively. The entries are removed from `astgen.ref_table`, and the returned
14169/// slice can then be treated as its own body, to append `ref` instructions to a body other than the one they
14170/// would normally exist in.
14171///
14172/// This is used when lowering functions. Very rarely, the callconv expression, align expression, etc may reference
14173/// function parameters via `&param`; in this case, we need to lower to a `ref` instruction in the callconv/align/etc
14174/// body, rather than in the declaration body. However, we don't append these bodies to `extra` until we've evaluated
14175/// *all* of the bodies into a big `GenZir` stack. Therefore, we use this function to pull out these per-body `ref`
14176/// instructions which must be emitted.
14177fn fetchRemoveRefEntries(astgen: *AstGen, param_insts: []const Zir.Inst.Index) ![]Zir.Inst.Index {
14178 var refs: std.ArrayListUnmanaged(Zir.Inst.Index) = .empty;
14179 for (param_insts) |param_inst| {
14180 if (astgen.ref_table.fetchRemove(param_inst)) |kv| {
14181 try refs.append(astgen.arena, kv.value);
14182 }
14183 }
14184 return refs.items;
14185}
lib/std/zig/Zir.zig+3-13
......@@ -998,6 +998,8 @@ pub const Inst = struct {
998998 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
999999 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
10001000 /// is the allocation that needs to have its type inferred.
1001 /// Results in the final resolved pointer. The `alloc_inferred[_comptime][_mut]`
1002 /// instruction should never be referred to after this instruction.
10011003 /// Uses the `un_node` field. The AST node is the var decl.
10021004 resolve_inferred_alloc,
10031005 /// Turns a pointer coming from an `alloc` or `Extended.alloc` into a constant
......@@ -1301,18 +1303,6 @@ pub const Inst = struct {
13011303 };
13021304 }
13031305
1304 pub fn isParam(tag: Tag) bool {
1305 return switch (tag) {
1306 .param,
1307 .param_comptime,
1308 .param_anytype,
1309 .param_anytype_comptime,
1310 => true,
1311
1312 else => false,
1313 };
1314 }
1315
13161306 /// AstGen uses this to find out if `Ref.void_value` should be used in place
13171307 /// of the result of a given instruction. This allows Sema to forego adding
13181308 /// the instruction to the map after analysis.
......@@ -1328,7 +1318,6 @@ pub const Inst = struct {
13281318 .atomic_store,
13291319 .store_node,
13301320 .store_to_inferred_ptr,
1331 .resolve_inferred_alloc,
13321321 .validate_deref,
13331322 .validate_destructure,
13341323 .@"export",
......@@ -1367,6 +1356,7 @@ pub const Inst = struct {
13671356 .alloc_inferred_mut,
13681357 .alloc_inferred_comptime,
13691358 .alloc_inferred_comptime_mut,
1359 .resolve_inferred_alloc,
13701360 .make_ptr_const,
13711361 .array_cat,
13721362 .array_mul,
src/Sema.zig+24-22
......@@ -1051,6 +1051,7 @@ fn analyzeBodyInner(
10511051 .alloc_inferred_mut => try sema.zirAllocInferred(block, false),
10521052 .alloc_inferred_comptime => try sema.zirAllocInferredComptime(true),
10531053 .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(false),
1054 .resolve_inferred_alloc => try sema.zirResolveInferredAlloc(block, inst),
10541055 .alloc_mut => try sema.zirAllocMut(block, inst),
10551056 .alloc_comptime_mut => try sema.zirAllocComptime(block, inst),
10561057 .make_ptr_const => try sema.zirMakePtrConst(block, inst),
......@@ -1418,11 +1419,6 @@ fn analyzeBodyInner(
14181419 i += 1;
14191420 continue;
14201421 },
1421 .resolve_inferred_alloc => {
1422 try sema.zirResolveInferredAlloc(block, inst);
1423 i += 1;
1424 continue;
1425 },
14261422 .validate_struct_init_ty => {
14271423 try sema.zirValidateStructInitTy(block, inst, false);
14281424 i += 1;
......@@ -4158,7 +4154,7 @@ fn zirAllocInferred(
41584154 return result_index.toRef();
41594155}
41604156
4161fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
4157fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
41624158 const tracy = trace(@src());
41634159 defer tracy.end();
41644160
......@@ -4175,7 +4171,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
41754171 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {
41764172 .inferred_alloc_comptime => {
41774173 // The work was already done for us by `Sema.storeToInferredAllocComptime`.
4178 // All we need to do is remap the pointer.
4174 // All we need to do is return the pointer.
41794175 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;
41804176 const resolved_ptr = iac.ptr;
41814177
......@@ -4200,8 +4196,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42004196 }
42014197 }
42024198
4203 // Remap the ZIR operand to the resolved pointer value
4204 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(resolved_ptr));
4199 return Air.internedToRef(resolved_ptr);
42054200 },
42064201 .inferred_alloc => {
42074202 const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc;
......@@ -4228,15 +4223,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42284223 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);
42294224 const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);
42304225
4231 // Remap the ZIR operand to the resolved pointer value
4232 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, Air.internedToRef(new_const_ptr.toIntern()));
4233
42344226 // Unless the block is comptime, `alloc_inferred` always produces
42354227 // a runtime constant. The final inferred type needs to be
42364228 // fully resolved so it can be lowered in codegen.
42374229 try final_elem_ty.resolveFully(pt);
42384230
4239 return;
4231 return Air.internedToRef(new_const_ptr.toIntern());
42404232 }
42414233
42424234 if (try final_elem_ty.comptimeOnlySema(pt)) {
......@@ -4255,11 +4247,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42554247 .data = .{ .ty = final_ptr_ty },
42564248 });
42574249
4258 if (ia1.is_const) {
4259 // Remap the ZIR operand to the pointer const
4260 sema.inst_map.putAssumeCapacity(inst_data.operand.toIndex().?, try sema.makePtrConst(block, ptr));
4261 }
4262
42634250 // Now we need to go back over all the store instructions, and do the logic as if
42644251 // the new result ptr type was available.
42654252
......@@ -4297,6 +4284,12 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42974284 });
42984285 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(replacement_block.instructions.items));
42994286 }
4287
4288 if (ia1.is_const) {
4289 return sema.makePtrConst(block, ptr);
4290 } else {
4291 return ptr;
4292 }
43004293 },
43014294 else => unreachable,
43024295 }
......@@ -33044,7 +33037,9 @@ fn analyzeRef(
3304433037 }
3304533038 }
3304633039
33047 try sema.requireRuntimeBlock(block, src, null);
33040 // No `requireRuntimeBlock`; it's okay to `ref` to a runtime value in a comptime context,
33041 // it's just that we can only use the *type* of the result, since the value is runtime-known.
33042
3304833043 const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);
3304933044 const ptr_type = try pt.ptrTypeSema(.{
3305033045 .child = operand_ty.toIntern(),
......@@ -33058,10 +33053,17 @@ fn analyzeRef(
3305833053 .flags = .{ .address_space = address_space },
3305933054 });
3306033055 const alloc = try block.addTy(.alloc, mut_ptr_type);
33061 try sema.storePtr(block, src, alloc, operand);
3306233056
33063 // TODO: Replace with sema.coerce when that supports adding pointer constness.
33064 return sema.bitCast(block, ptr_type, alloc, src, null);
33057 // In a comptime context, the store would fail, since the operand is runtime-known. But that's
33058 // okay; we don't actually need this store to succeed, since we're creating a runtime value in a
33059 // comptime scope, so the value can never be used aside from to get its type.
33060 if (!block.is_comptime) {
33061 try sema.storePtr(block, src, alloc, operand);
33062 }
33063
33064 // Cast to the constant pointer type. We do this directly rather than going via `coerce` to
33065 // avoid errors in the `block.is_comptime` case.
33066 return block.addBitCast(ptr_type, alloc);
3306533067}
3306633068
3306733069fn analyzeLoad(
test/behavior/fn.zig+51
......@@ -617,3 +617,54 @@ test "inline function with comptime-known comptime-only return type called at ru
617617 try expectEqual(111, a);
618618 try expectEqual(f32, T);
619619}
620
621test "address of function parameter is consistent" {
622 const S = struct {
623 fn paramAddrMatch(x: u8) bool {
624 return &x == &x;
625 }
626 };
627 try expect(S.paramAddrMatch(0));
628 comptime assert(S.paramAddrMatch(0));
629}
630
631test "address of function parameter is consistent in other parameter type" {
632 const S = struct {
633 fn paramAddrMatch(comptime x: u8, y: if (&x != &x) unreachable else u8) void {
634 _ = y;
635 }
636 };
637 S.paramAddrMatch(1, 2);
638}
639
640test "address of function parameter is consistent in function align" {
641 switch (builtin.target.cpu.arch) {
642 .wasm32, .wasm64 => return, // function alignment not supported
643 else => {},
644 }
645 const S = struct {
646 fn paramAddrMatch(comptime x: u8) align(if (&x != &x) unreachable else 1) void {}
647 };
648 S.paramAddrMatch(1);
649}
650
651test "address of function parameter is consistent in function callconv" {
652 const S = struct {
653 fn paramAddrMatch(comptime x: u8) callconv(if (&x != &x) unreachable else .auto) void {}
654 };
655 S.paramAddrMatch(1);
656}
657
658test "address of function parameter is consistent in function return type" {
659 const S = struct {
660 fn paramAddrMatch(comptime x: u8) if (&x != &x) unreachable else void {}
661 };
662 S.paramAddrMatch(1);
663}
664
665test "address of function parameter is consistent in function addrspace" {
666 const S = struct {
667 fn paramAddrMatch(comptime x: u8) addrspace(if (&x != &x) unreachable else .generic) void {}
668 };
669 S.paramAddrMatch(1);
670}