authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-25 02:58:27+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-12-25 02:58:27+00:00
log497592c9b45a94fb7b6028bf45b80f183e395a9b
tree467873c408750cb4223f3ccf31775e42ec9fbd5c
parentaf5e731729592af4a5716edd3b1e03264d66ea46
parent3afda4322c34dedc2319701fdfac3505c8d311e9
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #22303 from mlugg/131-new

compiler: analyze type and value of global declarations separately

29 files changed, 3095 insertions(+), 2546 deletions(-)

lib/std/zig/AstGen.zig+582-536
......@@ -106,7 +106,6 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
106106 Zir.Inst.SwitchBlock.Bits,
107107 Zir.Inst.SwitchBlockErrUnion.Bits,
108108 Zir.Inst.FuncFancy.Bits,
109 Zir.Inst.Declaration.Flags,
110109 => @bitCast(@field(extra, field.name)),
111110
112111 else => @compileError("bad field type"),
......@@ -1317,12 +1316,45 @@ fn fnProtoExpr(
13171316 return astgen.failTok(some, "function type cannot have a name", .{});
13181317 }
13191318
1319 if (fn_proto.ast.align_expr != 0) {
1320 return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
1321 }
1322
1323 if (fn_proto.ast.addrspace_expr != 0) {
1324 return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{});
1325 }
1326
1327 if (fn_proto.ast.section_expr != 0) {
1328 return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{});
1329 }
1330
1331 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
1332 const is_inferred_error = token_tags[maybe_bang] == .bang;
1333 if (is_inferred_error) {
1334 return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{});
1335 }
1336
13201337 const is_extern = blk: {
13211338 const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
13221339 break :blk token_tags[maybe_extern_token] == .keyword_extern;
13231340 };
13241341 assert(!is_extern);
13251342
1343 return fnProtoExprInner(gz, scope, ri, node, fn_proto, false);
1344}
1345
1346fn fnProtoExprInner(
1347 gz: *GenZir,
1348 scope: *Scope,
1349 ri: ResultInfo,
1350 node: Ast.Node.Index,
1351 fn_proto: Ast.full.FnProto,
1352 implicit_ccc: bool,
1353) InnerError!Zir.Inst.Ref {
1354 const astgen = gz.astgen;
1355 const tree = astgen.tree;
1356 const token_tags = tree.tokens.items(.tag);
1357
13261358 var block_scope = gz.makeSubBlock(scope);
13271359 defer block_scope.unstack();
13281360
......@@ -1386,18 +1418,6 @@ fn fnProtoExpr(
13861418 break :is_var_args false;
13871419 };
13881420
1389 if (fn_proto.ast.align_expr != 0) {
1390 return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
1391 }
1392
1393 if (fn_proto.ast.addrspace_expr != 0) {
1394 return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{});
1395 }
1396
1397 if (fn_proto.ast.section_expr != 0) {
1398 return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{});
1399 }
1400
14011421 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
14021422 try expr(
14031423 &block_scope,
......@@ -1405,14 +1425,11 @@ fn fnProtoExpr(
14051425 .{ .rl = .{ .coerced_ty = try block_scope.addBuiltinValue(fn_proto.ast.callconv_expr, .calling_convention) } },
14061426 fn_proto.ast.callconv_expr,
14071427 )
1428 else if (implicit_ccc)
1429 try block_scope.addBuiltinValue(node, .calling_convention_c)
14081430 else
1409 Zir.Inst.Ref.none;
1431 .none;
14101432
1411 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
1412 const is_inferred_error = token_tags[maybe_bang] == .bang;
1413 if (is_inferred_error) {
1414 return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{});
1415 }
14161433 const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type);
14171434
14181435 const result = try block_scope.addFunc(.{
......@@ -1428,11 +1445,8 @@ fn fnProtoExpr(
14281445
14291446 .param_block = block_inst,
14301447 .body_gz = null,
1431 .lib_name = .empty,
14321448 .is_var_args = is_var_args,
14331449 .is_inferred_error = false,
1434 .is_test = false,
1435 .is_extern = false,
14361450 .is_noinline = false,
14371451 .noalias_bits = noalias_bits,
14381452
......@@ -4121,17 +4135,6 @@ fn fnDecl(
41214135
41224136 const saved_cursor = astgen.saveSourceCursor();
41234137
4124 var decl_gz: GenZir = .{
4125 .is_comptime = true,
4126 .decl_node_index = fn_proto.ast.proto_node,
4127 .decl_line = astgen.source_line,
4128 .parent = scope,
4129 .astgen = astgen,
4130 .instructions = gz.instructions,
4131 .instructions_top = gz.instructions.items.len,
4132 };
4133 defer decl_gz.unstack();
4134
41354138 const decl_column = astgen.source_column;
41364139
41374140 // Set this now, since parameter types, return type, etc may be generic.
......@@ -4152,12 +4155,140 @@ fn fnDecl(
41524155 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
41534156 break :blk token_tags[maybe_inline_token] == .keyword_inline;
41544157 };
4158 const lib_name = if (fn_proto.lib_name) |lib_name_token| blk: {
4159 const lib_name_str = try astgen.strLitAsString(lib_name_token);
4160 const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len];
4161 if (mem.indexOfScalar(u8, lib_name_slice, 0) != null) {
4162 return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{});
4163 } else if (lib_name_str.len == 0) {
4164 return astgen.failTok(lib_name_token, "library name cannot be empty", .{});
4165 }
4166 break :blk lib_name_str.index;
4167 } else .empty;
4168 if (fn_proto.ast.callconv_expr != 0 and has_inline_keyword) {
4169 return astgen.failNode(
4170 fn_proto.ast.callconv_expr,
4171 "explicit callconv incompatible with inline keyword",
4172 .{},
4173 );
4174 }
4175 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
4176 const is_inferred_error = token_tags[maybe_bang] == .bang;
4177 if (body_node == 0) {
4178 if (!is_extern) {
4179 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
4180 }
4181 if (is_inferred_error) {
4182 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
4183 }
4184 } else {
4185 assert(!is_extern); // validated by parser (TODO why???)
4186 }
4187
4188 wip_members.nextDecl(decl_inst);
4189
4190 var type_gz: GenZir = .{
4191 .is_comptime = true,
4192 .decl_node_index = fn_proto.ast.proto_node,
4193 .decl_line = astgen.source_line,
4194 .parent = scope,
4195 .astgen = astgen,
4196 .instructions = gz.instructions,
4197 .instructions_top = gz.instructions.items.len,
4198 };
4199 defer type_gz.unstack();
4200
4201 if (is_extern) {
4202 // We include a function *type*, not a value.
4203 const type_inst = try fnProtoExprInner(&type_gz, &type_gz.base, .{ .rl = .none }, decl_node, fn_proto, true);
4204 _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, decl_node);
4205 }
4206
4207 var align_gz = type_gz.makeSubBlock(scope);
4208 defer align_gz.unstack();
4209
4210 if (fn_proto.ast.align_expr != 0) {
4211 astgen.restoreSourceCursor(saved_cursor);
4212 const inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, fn_proto.ast.align_expr);
4213 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4214 }
4215
4216 var linksection_gz = align_gz.makeSubBlock(scope);
4217 defer linksection_gz.unstack();
4218
4219 if (fn_proto.ast.section_expr != 0) {
4220 astgen.restoreSourceCursor(saved_cursor);
4221 const inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, fn_proto.ast.section_expr);
4222 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4223 }
4224
4225 var addrspace_gz = linksection_gz.makeSubBlock(scope);
4226 defer addrspace_gz.unstack();
4227
4228 if (fn_proto.ast.addrspace_expr != 0) {
4229 astgen.restoreSourceCursor(saved_cursor);
4230 const addrspace_ty = try addrspace_gz.addBuiltinValue(fn_proto.ast.addrspace_expr, .address_space);
4231 const inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, fn_proto.ast.section_expr);
4232 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
4233 }
4234
4235 var value_gz = addrspace_gz.makeSubBlock(scope);
4236 defer value_gz.unstack();
4237
4238 if (!is_extern) {
4239 // We include a function *value*, not a type.
4240 astgen.restoreSourceCursor(saved_cursor);
4241 try astgen.fnDeclInner(&value_gz, &value_gz.base, saved_cursor, decl_inst, decl_node, body_node, fn_proto);
4242 }
4243
4244 // *Now* we can incorporate the full source code into the hasher.
4245 astgen.src_hasher.update(tree.getNodeSource(decl_node));
4246
4247 var hash: std.zig.SrcHash = undefined;
4248 astgen.src_hasher.final(&hash);
4249 try setDeclaration(decl_inst, .{
4250 .src_hash = hash,
4251 .src_line = type_gz.decl_line,
4252 .src_column = decl_column,
4253
4254 .kind = .@"const",
4255 .name = try astgen.identAsString(fn_name_token),
4256 .is_pub = is_pub,
4257 .is_threadlocal = false,
4258 .linkage = if (is_extern) .@"extern" else if (is_export) .@"export" else .normal,
4259 .lib_name = lib_name,
4260
4261 .type_gz = &type_gz,
4262 .align_gz = &align_gz,
4263 .linksection_gz = &linksection_gz,
4264 .addrspace_gz = &addrspace_gz,
4265 .value_gz = &value_gz,
4266 });
4267}
4268
4269fn fnDeclInner(
4270 astgen: *AstGen,
4271 decl_gz: *GenZir,
4272 scope: *Scope,
4273 saved_cursor: SourceCursor,
4274 decl_inst: Zir.Inst.Index,
4275 decl_node: Ast.Node.Index,
4276 body_node: Ast.Node.Index,
4277 fn_proto: Ast.full.FnProto,
4278) InnerError!void {
4279 const tree = astgen.tree;
4280 const token_tags = tree.tokens.items(.tag);
4281
41554282 const is_noinline = blk: {
41564283 const maybe_noinline_token = fn_proto.extern_export_inline_token orelse break :blk false;
41574284 break :blk token_tags[maybe_noinline_token] == .keyword_noinline;
41584285 };
4159
4160 wip_members.nextDecl(decl_inst);
4286 const has_inline_keyword = blk: {
4287 const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
4288 break :blk token_tags[maybe_inline_token] == .keyword_inline;
4289 };
4290 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
4291 const is_inferred_error = token_tags[maybe_bang] == .bang;
41614292
41624293 // Note that the capacity here may not be sufficient, as this does not include `anytype` parameters.
41634294 var param_insts: std.ArrayListUnmanaged(Zir.Inst.Index) = try .initCapacity(astgen.arena, fn_proto.ast.params.len);
......@@ -4192,11 +4323,9 @@ fn fnDecl(
41924323 break :blk .empty;
41934324
41944325 const param_name = try astgen.identAsString(name_token);
4195 if (!is_extern) {
4196 try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes, .@"function parameter");
4197 }
4326 try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes, .@"function parameter");
41984327 break :blk param_name;
4199 } else if (!is_extern) {
4328 } else {
42004329 if (param.anytype_ellipsis3) |tok| {
42014330 return astgen.failTok(tok, "missing parameter name", .{});
42024331 } else {
......@@ -4225,7 +4354,7 @@ fn fnDecl(
42254354 }
42264355 return astgen.failNode(param.type_expr, "missing parameter name", .{});
42274356 }
4228 } else .empty;
4357 };
42294358
42304359 const param_inst = if (is_anytype) param: {
42314360 const name_token = param.name_token orelse param.anytype_ellipsis3.?;
......@@ -4251,12 +4380,12 @@ fn fnDecl(
42514380 break :param param_inst.toRef();
42524381 };
42534382
4254 if (param_name == .empty or is_extern) continue;
4383 if (param_name == .empty) continue;
42554384
42564385 const sub_scope = try astgen.arena.create(Scope.LocalVal);
42574386 sub_scope.* = .{
42584387 .parent = params_scope,
4259 .gen_zir = &decl_gz,
4388 .gen_zir = decl_gz,
42604389 .name = param_name,
42614390 .inst = param_inst,
42624391 .token_src = param.name_token.?,
......@@ -4268,23 +4397,9 @@ fn fnDecl(
42684397 break :is_var_args false;
42694398 };
42704399
4271 const lib_name = if (fn_proto.lib_name) |lib_name_token| blk: {
4272 const lib_name_str = try astgen.strLitAsString(lib_name_token);
4273 const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len];
4274 if (mem.indexOfScalar(u8, lib_name_slice, 0) != null) {
4275 return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{});
4276 } else if (lib_name_str.len == 0) {
4277 return astgen.failTok(lib_name_token, "library name cannot be empty", .{});
4278 }
4279 break :blk lib_name_str.index;
4280 } else .empty;
4281
4282 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
4283 const is_inferred_error = token_tags[maybe_bang] == .bang;
4284
42854400 // After creating the function ZIR instruction, it will need to update the break
4286 // instructions inside the expression blocks for align, addrspace, cc, and ret_ty
4287 // to use the function instruction as the "block" to break from.
4401 // instructions inside the expression blocks for cc and ret_ty to use the function
4402 // instruction as the body to break from.
42884403
42894404 var ret_gz = decl_gz.makeSubBlock(params_scope);
42904405 defer ret_gz.unstack();
......@@ -4309,13 +4424,6 @@ fn fnDecl(
43094424 defer cc_gz.unstack();
43104425 const cc_ref: Zir.Inst.Ref = blk: {
43114426 if (fn_proto.ast.callconv_expr != 0) {
4312 if (has_inline_keyword) {
4313 return astgen.failNode(
4314 fn_proto.ast.callconv_expr,
4315 "explicit callconv incompatible with inline keyword",
4316 .{},
4317 );
4318 }
43194427 const inst = try expr(
43204428 &cc_gz,
43214429 scope,
......@@ -4328,10 +4436,6 @@ fn fnDecl(
43284436 }
43294437 _ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst);
43304438 break :blk inst;
4331 } else if (is_extern) {
4332 const inst = try cc_gz.addBuiltinValue(decl_node, .calling_convention_c);
4333 _ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst);
4334 break :blk inst;
43354439 } else if (has_inline_keyword) {
43364440 const inst = try cc_gz.addBuiltinValue(decl_node, .calling_convention_inline);
43374441 _ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst);
......@@ -4341,167 +4445,86 @@ fn fnDecl(
43414445 }
43424446 };
43434447
4344 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
4345 if (!is_extern) {
4346 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
4347 }
4348 if (is_inferred_error) {
4349 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
4350 }
4351 break :func try decl_gz.addFunc(.{
4352 .src_node = decl_node,
4353 .cc_ref = cc_ref,
4354 .cc_gz = &cc_gz,
4355 .ret_ref = ret_ref,
4356 .ret_gz = &ret_gz,
4357 .ret_param_refs = ret_body_param_refs,
4358 .param_block = decl_inst,
4359 .param_insts = param_insts.items,
4360 .body_gz = null,
4361 .lib_name = lib_name,
4362 .is_var_args = is_var_args,
4363 .is_inferred_error = false,
4364 .is_test = false,
4365 .is_extern = true,
4366 .is_noinline = is_noinline,
4367 .noalias_bits = noalias_bits,
4368 .proto_hash = undefined, // ignored for `body_gz == null`
4369 });
4370 } else func: {
4371 var body_gz: GenZir = .{
4372 .is_comptime = false,
4373 .decl_node_index = fn_proto.ast.proto_node,
4374 .decl_line = decl_gz.decl_line,
4375 .parent = params_scope,
4376 .astgen = astgen,
4377 .instructions = gz.instructions,
4378 .instructions_top = gz.instructions.items.len,
4379 };
4380 defer body_gz.unstack();
4381
4382 // We want `params_scope` to be stacked like this:
4383 // body_gz (top)
4384 // param2
4385 // param1
4386 // param0
4387 // decl_gz (bottom)
4388
4389 // Construct the prototype hash.
4390 // Leave `astgen.src_hasher` unmodified; this will be used for hashing
4391 // the *whole* function declaration, including its body.
4392 var proto_hasher = astgen.src_hasher;
4393 const proto_node = tree.nodes.items(.data)[decl_node].lhs;
4394 proto_hasher.update(tree.getNodeSource(proto_node));
4395 var proto_hash: std.zig.SrcHash = undefined;
4396 proto_hasher.final(&proto_hash);
4397
4398 const prev_fn_block = astgen.fn_block;
4399 const prev_fn_ret_ty = astgen.fn_ret_ty;
4400 defer {
4401 astgen.fn_block = prev_fn_block;
4402 astgen.fn_ret_ty = prev_fn_ret_ty;
4403 }
4404 astgen.fn_block = &body_gz;
4405 astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
4406 // We're essentially guaranteed to need the return type at some point,
4407 // since the return type is likely not `void` or `noreturn` so there
4408 // will probably be an explicit return requiring RLS. Fetch this
4409 // return type now so the rest of the function can use it.
4410 break :r try body_gz.addNode(.ret_type, decl_node);
4411 } else ret_ref;
4412
4413 const prev_var_args = astgen.fn_var_args;
4414 astgen.fn_var_args = is_var_args;
4415 defer astgen.fn_var_args = prev_var_args;
4416
4417 astgen.advanceSourceCursorToNode(body_node);
4418 const lbrace_line = astgen.source_line - decl_gz.decl_line;
4419 const lbrace_column = astgen.source_column;
4420
4421 _ = try fullBodyExpr(&body_gz, &body_gz.base, .{ .rl = .none }, body_node, .allow_branch_hint);
4422 try checkUsed(gz, scope, params_scope);
4423
4424 if (!body_gz.endsWithNoReturn()) {
4425 // As our last action before the return, "pop" the error trace if needed
4426 _ = try body_gz.addRestoreErrRetIndex(.ret, .always, decl_node);
4427
4428 // Add implicit return at end of function.
4429 _ = try body_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
4430 }
4431
4432 break :func try decl_gz.addFunc(.{
4433 .src_node = decl_node,
4434 .cc_ref = cc_ref,
4435 .cc_gz = &cc_gz,
4436 .ret_ref = ret_ref,
4437 .ret_gz = &ret_gz,
4438 .ret_param_refs = ret_body_param_refs,
4439 .lbrace_line = lbrace_line,
4440 .lbrace_column = lbrace_column,
4441 .param_block = decl_inst,
4442 .param_insts = param_insts.items,
4443 .body_gz = &body_gz,
4444 .lib_name = lib_name,
4445 .is_var_args = is_var_args,
4446 .is_inferred_error = is_inferred_error,
4447 .is_test = false,
4448 .is_extern = false,
4449 .is_noinline = is_noinline,
4450 .noalias_bits = noalias_bits,
4451 .proto_hash = proto_hash,
4452 });
4448 var body_gz: GenZir = .{
4449 .is_comptime = false,
4450 .decl_node_index = fn_proto.ast.proto_node,
4451 .decl_line = decl_gz.decl_line,
4452 .parent = params_scope,
4453 .astgen = astgen,
4454 .instructions = decl_gz.instructions,
4455 .instructions_top = decl_gz.instructions.items.len,
44534456 };
4457 defer body_gz.unstack();
4458
4459 // The scope stack looks like this:
4460 // body_gz (top)
4461 // param2
4462 // param1
4463 // param0
4464 // decl_gz (bottom)
4465
4466 // Construct the prototype hash.
4467 // Leave `astgen.src_hasher` unmodified; this will be used for hashing
4468 // the *whole* function declaration, including its body.
4469 var proto_hasher = astgen.src_hasher;
4470 const proto_node = tree.nodes.items(.data)[decl_node].lhs;
4471 proto_hasher.update(tree.getNodeSource(proto_node));
4472 var proto_hash: std.zig.SrcHash = undefined;
4473 proto_hasher.final(&proto_hash);
44544474
4455 // Before we stack more stuff onto `decl_gz`, add its final instruction.
4456 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
4475 const prev_fn_block = astgen.fn_block;
4476 const prev_fn_ret_ty = astgen.fn_ret_ty;
4477 defer {
4478 astgen.fn_block = prev_fn_block;
4479 astgen.fn_ret_ty = prev_fn_ret_ty;
4480 }
4481 astgen.fn_block = &body_gz;
4482 astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
4483 // We're essentially guaranteed to need the return type at some point,
4484 // since the return type is likely not `void` or `noreturn` so there
4485 // will probably be an explicit return requiring RLS. Fetch this
4486 // return type now so the rest of the function can use it.
4487 break :r try body_gz.addNode(.ret_type, decl_node);
4488 } else ret_ref;
44574489
4458 // Now that `cc_gz,` `ret_gz`, and `body_gz` are unstacked, we evaluate align, addrspace, and linksection.
4490 const prev_var_args = astgen.fn_var_args;
4491 astgen.fn_var_args = is_var_args;
4492 defer astgen.fn_var_args = prev_var_args;
44594493
4460 // We're jumping back in source, so restore the cursor.
4461 astgen.restoreSourceCursor(saved_cursor);
4494 astgen.advanceSourceCursorToNode(body_node);
4495 const lbrace_line = astgen.source_line - decl_gz.decl_line;
4496 const lbrace_column = astgen.source_column;
44624497
4463 var align_gz = decl_gz.makeSubBlock(scope);
4464 defer align_gz.unstack();
4465 if (fn_proto.ast.align_expr != 0) {
4466 const inst = try expr(&decl_gz, &decl_gz.base, coerced_align_ri, fn_proto.ast.align_expr);
4467 _ = try align_gz.addBreak(.break_inline, decl_inst, inst);
4468 }
4498 _ = try fullBodyExpr(&body_gz, &body_gz.base, .{ .rl = .none }, body_node, .allow_branch_hint);
4499 try checkUsed(decl_gz, scope, params_scope);
44694500
4470 var section_gz = align_gz.makeSubBlock(scope);
4471 defer section_gz.unstack();
4472 if (fn_proto.ast.section_expr != 0) {
4473 const inst = try expr(&decl_gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, fn_proto.ast.section_expr);
4474 _ = try section_gz.addBreak(.break_inline, decl_inst, inst);
4475 }
4501 if (!body_gz.endsWithNoReturn()) {
4502 // As our last action before the return, "pop" the error trace if needed
4503 _ = try body_gz.addRestoreErrRetIndex(.ret, .always, decl_node);
44764504
4477 var addrspace_gz = section_gz.makeSubBlock(scope);
4478 defer addrspace_gz.unstack();
4479 if (fn_proto.ast.addrspace_expr != 0) {
4480 const addrspace_ty = try decl_gz.addBuiltinValue(fn_proto.ast.addrspace_expr, .address_space);
4481 const inst = try expr(&decl_gz, scope, .{ .rl = .{ .coerced_ty = addrspace_ty } }, fn_proto.ast.addrspace_expr);
4482 _ = try addrspace_gz.addBreak(.break_inline, decl_inst, inst);
4505 // Add implicit return at end of function.
4506 _ = try body_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
44834507 }
44844508
4485 // *Now* we can incorporate the full source code into the hasher.
4486 astgen.src_hasher.update(tree.getNodeSource(decl_node));
4487
4488 var hash: std.zig.SrcHash = undefined;
4489 astgen.src_hasher.final(&hash);
4490 try setDeclaration(
4491 decl_inst,
4492 hash,
4493 .{ .named = fn_name_token },
4494 decl_gz.decl_line,
4495 decl_column,
4496 is_pub,
4497 is_export,
4498 &decl_gz,
4499 .{
4500 .align_gz = &align_gz,
4501 .linksection_gz = &section_gz,
4502 .addrspace_gz = &addrspace_gz,
4503 },
4504 );
4509 const func_inst = try decl_gz.addFunc(.{
4510 .src_node = decl_node,
4511 .cc_ref = cc_ref,
4512 .cc_gz = &cc_gz,
4513 .ret_ref = ret_ref,
4514 .ret_gz = &ret_gz,
4515 .ret_param_refs = ret_body_param_refs,
4516 .lbrace_line = lbrace_line,
4517 .lbrace_column = lbrace_column,
4518 .param_block = decl_inst,
4519 .param_insts = param_insts.items,
4520 .body_gz = &body_gz,
4521 .is_var_args = is_var_args,
4522 .is_inferred_error = is_inferred_error,
4523 .is_noinline = is_noinline,
4524 .noalias_bits = noalias_bits,
4525 .proto_hash = proto_hash,
4526 });
4527 _ = try decl_gz.addBreakWithSrcNode(.break_inline, decl_inst, func_inst, decl_node);
45054528}
45064529
45074530fn globalVarDecl(
......@@ -4522,26 +4545,7 @@ fn globalVarDecl(
45224545 astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
45234546
45244547 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
4525 // We do this at the beginning so that the instruction index marks the range start
4526 // of the top level declaration.
4527 const decl_inst = try gz.makeDeclaration(node);
4528
45294548 const name_token = var_decl.ast.mut_token + 1;
4530 astgen.advanceSourceCursorToNode(node);
4531
4532 var block_scope: GenZir = .{
4533 .parent = scope,
4534 .decl_node_index = node,
4535 .decl_line = astgen.source_line,
4536 .astgen = astgen,
4537 .is_comptime = true,
4538 .instructions = gz.instructions,
4539 .instructions_top = gz.instructions.items.len,
4540 };
4541 defer block_scope.unstack();
4542
4543 const decl_column = astgen.source_column;
4544
45454549 const is_pub = var_decl.visib_token != null;
45464550 const is_export = blk: {
45474551 const maybe_export_token = var_decl.extern_export_token orelse break :blk false;
......@@ -4551,15 +4555,12 @@ fn globalVarDecl(
45514555 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
45524556 break :blk token_tags[maybe_extern_token] == .keyword_extern;
45534557 };
4554 wip_members.nextDecl(decl_inst);
4555
45564558 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
45574559 if (!is_mutable) {
45584560 return astgen.failTok(tok, "threadlocal variable cannot be constant", .{});
45594561 }
45604562 break :blk true;
45614563 } else false;
4562
45634564 const lib_name = if (var_decl.lib_name) |lib_name_token| blk: {
45644565 const lib_name_str = try astgen.strLitAsString(lib_name_token);
45654566 const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len];
......@@ -4571,9 +4572,14 @@ fn globalVarDecl(
45714572 break :blk lib_name_str.index;
45724573 } else .empty;
45734574
4574 assert(var_decl.comptime_token == null); // handled by parser
4575 astgen.advanceSourceCursorToNode(node);
4576
4577 const decl_column = astgen.source_column;
4578
4579 const decl_inst = try gz.makeDeclaration(node);
4580 wip_members.nextDecl(decl_inst);
45754581
4576 const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: {
4582 if (var_decl.ast.init_node != 0) {
45774583 if (is_extern) {
45784584 return astgen.failNode(
45794585 var_decl.ast.init_node,
......@@ -4581,102 +4587,91 @@ fn globalVarDecl(
45814587 .{},
45824588 );
45834589 }
4590 } else {
4591 if (!is_extern) {
4592 return astgen.failNode(node, "variables must be initialized", .{});
4593 }
4594 }
45844595
4585 const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0)
4586 try expr(
4587 &block_scope,
4588 &block_scope.base,
4589 coerced_type_ri,
4590 var_decl.ast.type_node,
4591 )
4592 else
4593 .none;
4594
4595 block_scope.anon_name_strategy = .parent;
4596 if (is_extern and var_decl.ast.type_node == 0) {
4597 return astgen.failNode(node, "unable to infer variable type", .{});
4598 }
45964599
4597 const init_inst = try expr(
4598 &block_scope,
4599 &block_scope.base,
4600 if (type_inst != .none) .{ .rl = .{ .ty = type_inst } } else .{ .rl = .none },
4601 var_decl.ast.init_node,
4602 );
4600 assert(var_decl.comptime_token == null); // handled by parser
46034601
4604 if (is_mutable) {
4605 const var_inst = try block_scope.addVar(.{
4606 .var_type = type_inst,
4607 .lib_name = .empty,
4608 .align_inst = .none, // passed via the decls data
4609 .init = init_inst,
4610 .is_extern = false,
4611 .is_const = !is_mutable,
4612 .is_threadlocal = is_threadlocal,
4613 });
4614 break :vi var_inst;
4615 } else {
4616 break :vi init_inst;
4617 }
4618 } else if (!is_extern) {
4619 return astgen.failNode(node, "variables must be initialized", .{});
4620 } else if (var_decl.ast.type_node != 0) vi: {
4621 // Extern variable which has an explicit type.
4622 const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);
4623
4624 block_scope.anon_name_strategy = .parent;
4625
4626 const var_inst = try block_scope.addVar(.{
4627 .var_type = type_inst,
4628 .lib_name = lib_name,
4629 .align_inst = .none, // passed via the decls data
4630 .init = .none,
4631 .is_extern = true,
4632 .is_const = !is_mutable,
4633 .is_threadlocal = is_threadlocal,
4634 });
4635 break :vi var_inst;
4636 } else {
4637 return astgen.failNode(node, "unable to infer variable type", .{});
4602 var type_gz: GenZir = .{
4603 .parent = scope,
4604 .decl_node_index = node,
4605 .decl_line = astgen.source_line,
4606 .astgen = astgen,
4607 .is_comptime = true,
4608 .instructions = gz.instructions,
4609 .instructions_top = gz.instructions.items.len,
46384610 };
4611 defer type_gz.unstack();
4612
4613 if (var_decl.ast.type_node != 0) {
4614 const type_inst = try expr(&type_gz, &type_gz.base, coerced_type_ri, var_decl.ast.type_node);
4615 _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, node);
4616 }
46394617
4640 // We do this at the end so that the instruction index marks the end
4641 // range of a top level declaration.
4642 _ = try block_scope.addBreakWithSrcNode(.break_inline, decl_inst, var_inst, node);
4618 var align_gz = type_gz.makeSubBlock(scope);
4619 defer align_gz.unstack();
46434620
4644 var align_gz = block_scope.makeSubBlock(scope);
46454621 if (var_decl.ast.align_node != 0) {
4646 const align_inst = try fullBodyExpr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node, .normal);
4622 const align_inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node);
46474623 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
46484624 }
46494625
4650 var linksection_gz = align_gz.makeSubBlock(scope);
4626 var linksection_gz = type_gz.makeSubBlock(scope);
4627 defer linksection_gz.unstack();
4628
46514629 if (var_decl.ast.section_node != 0) {
4652 const linksection_inst = try fullBodyExpr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node, .normal);
4630 const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node);
46534631 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
46544632 }
46554633
4656 var addrspace_gz = linksection_gz.makeSubBlock(scope);
4634 var addrspace_gz = type_gz.makeSubBlock(scope);
4635 defer addrspace_gz.unstack();
4636
46574637 if (var_decl.ast.addrspace_node != 0) {
46584638 const addrspace_ty = try addrspace_gz.addBuiltinValue(var_decl.ast.addrspace_node, .address_space);
4659 const addrspace_inst = try fullBodyExpr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, var_decl.ast.addrspace_node, .normal);
4639 const addrspace_inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, var_decl.ast.addrspace_node);
46604640 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
46614641 }
46624642
4643 var init_gz = type_gz.makeSubBlock(scope);
4644 defer init_gz.unstack();
4645
4646 if (var_decl.ast.init_node != 0) {
4647 init_gz.anon_name_strategy = .parent;
4648 const init_ri: ResultInfo = if (var_decl.ast.type_node != 0) .{
4649 .rl = .{ .coerced_ty = decl_inst.toRef() },
4650 } else .{ .rl = .none };
4651 const init_inst = try expr(&init_gz, &init_gz.base, init_ri, var_decl.ast.init_node);
4652 _ = try init_gz.addBreakWithSrcNode(.break_inline, decl_inst, init_inst, node);
4653 }
4654
46634655 var hash: std.zig.SrcHash = undefined;
46644656 astgen.src_hasher.final(&hash);
4665 try setDeclaration(
4666 decl_inst,
4667 hash,
4668 .{ .named = name_token },
4669 block_scope.decl_line,
4670 decl_column,
4671 is_pub,
4672 is_export,
4673 &block_scope,
4674 .{
4675 .align_gz = &align_gz,
4676 .linksection_gz = &linksection_gz,
4677 .addrspace_gz = &addrspace_gz,
4678 },
4679 );
4657 try setDeclaration(decl_inst, .{
4658 .src_hash = hash,
4659 .src_line = type_gz.decl_line,
4660 .src_column = decl_column,
4661
4662 .kind = if (is_mutable) .@"var" else .@"const",
4663 .name = try astgen.identAsString(name_token),
4664 .is_pub = is_pub,
4665 .is_threadlocal = is_threadlocal,
4666 .linkage = if (is_extern) .@"extern" else if (is_export) .@"export" else .normal,
4667 .lib_name = lib_name,
4668
4669 .type_gz = &type_gz,
4670 .align_gz = &align_gz,
4671 .linksection_gz = &linksection_gz,
4672 .addrspace_gz = &addrspace_gz,
4673 .value_gz = &init_gz,
4674 });
46804675}
46814676
46824677fn comptimeDecl(
......@@ -4702,37 +4697,45 @@ fn comptimeDecl(
47024697 wip_members.nextDecl(decl_inst);
47034698 astgen.advanceSourceCursorToNode(node);
47044699
4705 var decl_block: GenZir = .{
4700 // This is just needed for the `setDeclaration` call.
4701 var dummy_gz = gz.makeSubBlock(scope);
4702 defer dummy_gz.unstack();
4703
4704 var comptime_gz: GenZir = .{
47064705 .is_comptime = true,
47074706 .decl_node_index = node,
47084707 .decl_line = astgen.source_line,
47094708 .parent = scope,
47104709 .astgen = astgen,
4711 .instructions = gz.instructions,
4712 .instructions_top = gz.instructions.items.len,
4710 .instructions = dummy_gz.instructions,
4711 .instructions_top = dummy_gz.instructions.items.len,
47134712 };
4714 defer decl_block.unstack();
4713 defer comptime_gz.unstack();
47154714
47164715 const decl_column = astgen.source_column;
47174716
4718 const block_result = try fullBodyExpr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node, .normal);
4719 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {
4720 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
4717 const block_result = try fullBodyExpr(&comptime_gz, &comptime_gz.base, .{ .rl = .none }, body_node, .normal);
4718 if (comptime_gz.isEmpty() or !comptime_gz.refIsNoReturn(block_result)) {
4719 _ = try comptime_gz.addBreak(.break_inline, decl_inst, .void_value);
47214720 }
47224721
47234722 var hash: std.zig.SrcHash = undefined;
47244723 astgen.src_hasher.final(&hash);
4725 try setDeclaration(
4726 decl_inst,
4727 hash,
4728 .@"comptime",
4729 decl_block.decl_line,
4730 decl_column,
4731 false,
4732 false,
4733 &decl_block,
4734 null,
4735 );
4724 try setDeclaration(decl_inst, .{
4725 .src_hash = hash,
4726 .src_line = comptime_gz.decl_line,
4727 .src_column = decl_column,
4728 .kind = .@"comptime",
4729 .name = .empty,
4730 .is_pub = false,
4731 .is_threadlocal = false,
4732 .linkage = .normal,
4733 .type_gz = &dummy_gz,
4734 .align_gz = &dummy_gz,
4735 .linksection_gz = &dummy_gz,
4736 .addrspace_gz = &dummy_gz,
4737 .value_gz = &comptime_gz,
4738 });
47364739}
47374740
47384741fn usingnamespaceDecl(
......@@ -4764,7 +4767,11 @@ fn usingnamespaceDecl(
47644767 wip_members.nextDecl(decl_inst);
47654768 astgen.advanceSourceCursorToNode(node);
47664769
4767 var decl_block: GenZir = .{
4770 // This is just needed for the `setDeclaration` call.
4771 var dummy_gz = gz.makeSubBlock(scope);
4772 defer dummy_gz.unstack();
4773
4774 var usingnamespace_gz: GenZir = .{
47684775 .is_comptime = true,
47694776 .decl_node_index = node,
47704777 .decl_line = astgen.source_line,
......@@ -4773,26 +4780,30 @@ fn usingnamespaceDecl(
47734780 .instructions = gz.instructions,
47744781 .instructions_top = gz.instructions.items.len,
47754782 };
4776 defer decl_block.unstack();
4783 defer usingnamespace_gz.unstack();
47774784
47784785 const decl_column = astgen.source_column;
47794786
4780 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4781 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
4787 const namespace_inst = try typeExpr(&usingnamespace_gz, &usingnamespace_gz.base, type_expr);
4788 _ = try usingnamespace_gz.addBreak(.break_inline, decl_inst, namespace_inst);
47824789
47834790 var hash: std.zig.SrcHash = undefined;
47844791 astgen.src_hasher.final(&hash);
4785 try setDeclaration(
4786 decl_inst,
4787 hash,
4788 .@"usingnamespace",
4789 decl_block.decl_line,
4790 decl_column,
4791 is_pub,
4792 false,
4793 &decl_block,
4794 null,
4795 );
4792 try setDeclaration(decl_inst, .{
4793 .src_hash = hash,
4794 .src_line = usingnamespace_gz.decl_line,
4795 .src_column = decl_column,
4796 .kind = .@"usingnamespace",
4797 .name = .empty,
4798 .is_pub = is_pub,
4799 .is_threadlocal = false,
4800 .linkage = .normal,
4801 .type_gz = &dummy_gz,
4802 .align_gz = &dummy_gz,
4803 .linksection_gz = &dummy_gz,
4804 .addrspace_gz = &dummy_gz,
4805 .value_gz = &usingnamespace_gz,
4806 });
47964807}
47974808
47984809fn testDecl(
......@@ -4819,14 +4830,18 @@ fn testDecl(
48194830 wip_members.nextDecl(decl_inst);
48204831 astgen.advanceSourceCursorToNode(node);
48214832
4833 // This is just needed for the `setDeclaration` call.
4834 var dummy_gz: GenZir = gz.makeSubBlock(scope);
4835 defer dummy_gz.unstack();
4836
48224837 var decl_block: GenZir = .{
48234838 .is_comptime = true,
48244839 .decl_node_index = node,
48254840 .decl_line = astgen.source_line,
48264841 .parent = scope,
48274842 .astgen = astgen,
4828 .instructions = gz.instructions,
4829 .instructions_top = gz.instructions.items.len,
4843 .instructions = dummy_gz.instructions,
4844 .instructions_top = dummy_gz.instructions.items.len,
48304845 };
48314846 defer decl_block.unstack();
48324847
......@@ -4835,11 +4850,21 @@ fn testDecl(
48354850 const main_tokens = tree.nodes.items(.main_token);
48364851 const token_tags = tree.tokens.items(.tag);
48374852 const test_token = main_tokens[node];
4853
48384854 const test_name_token = test_token + 1;
4839 const test_name: DeclarationName = switch (token_tags[test_name_token]) {
4840 else => .unnamed_test,
4841 .string_literal => .{ .named_test = test_name_token },
4842 .identifier => blk: {
4855 const test_name: Zir.NullTerminatedString = switch (token_tags[test_name_token]) {
4856 else => .empty,
4857 .string_literal => name: {
4858 const name = try astgen.strLitAsString(test_name_token);
4859 const slice = astgen.string_bytes.items[@intFromEnum(name.index)..][0..name.len];
4860 if (mem.indexOfScalar(u8, slice, 0) != null) {
4861 return astgen.failTok(test_name_token, "test name cannot contain null bytes", .{});
4862 } else if (slice.len == 0) {
4863 return astgen.failTok(test_name_token, "empty test name must be omitted", .{});
4864 }
4865 break :name name.index;
4866 },
4867 .identifier => name: {
48434868 const ident_name_raw = tree.tokenSlice(test_name_token);
48444869
48454870 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{});
......@@ -4909,7 +4934,7 @@ fn testDecl(
49094934 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
49104935 }
49114936
4912 break :blk .{ .decltest = test_name_token };
4937 break :name try astgen.identAsString(test_name_token);
49134938 },
49144939 };
49154940
......@@ -4965,11 +4990,8 @@ fn testDecl(
49654990 .lbrace_column = lbrace_column,
49664991 .param_block = decl_inst,
49674992 .body_gz = &fn_block,
4968 .lib_name = .empty,
49694993 .is_var_args = false,
49704994 .is_inferred_error = false,
4971 .is_test = true,
4972 .is_extern = false,
49734995 .is_noinline = false,
49744996 .noalias_bits = 0,
49754997
......@@ -4981,17 +5003,27 @@ fn testDecl(
49815003
49825004 var hash: std.zig.SrcHash = undefined;
49835005 astgen.src_hasher.final(&hash);
4984 try setDeclaration(
4985 decl_inst,
4986 hash,
4987 test_name,
4988 decl_block.decl_line,
4989 decl_column,
4990 false,
4991 false,
4992 &decl_block,
4993 null,
4994 );
5006 try setDeclaration(decl_inst, .{
5007 .src_hash = hash,
5008 .src_line = decl_block.decl_line,
5009 .src_column = decl_column,
5010
5011 .kind = switch (token_tags[test_name_token]) {
5012 .string_literal => .@"test",
5013 .identifier => .decltest,
5014 else => .unnamed_test,
5015 },
5016 .name = test_name,
5017 .is_pub = false,
5018 .is_threadlocal = false,
5019 .linkage = .normal,
5020
5021 .type_gz = &dummy_gz,
5022 .align_gz = &dummy_gz,
5023 .linksection_gz = &dummy_gz,
5024 .addrspace_gz = &dummy_gz,
5025 .value_gz = &decl_block,
5026 });
49955027}
49965028
49975029fn structDeclInner(
......@@ -5882,7 +5914,8 @@ fn containerMember(
58825914 try addFailedDeclaration(
58835915 wip_members,
58845916 gz,
5885 .{ .named = full.name_token.? },
5917 .@"const",
5918 try astgen.identAsString(full.name_token.?),
58865919 full.ast.proto_node,
58875920 full.visib_token != null,
58885921 );
......@@ -5904,7 +5937,8 @@ fn containerMember(
59045937 try addFailedDeclaration(
59055938 wip_members,
59065939 gz,
5907 .{ .named = full.ast.mut_token + 1 },
5940 .@"const", // doesn't really matter
5941 try astgen.identAsString(full.ast.mut_token + 1),
59085942 member_node,
59095943 full.visib_token != null,
59105944 );
......@@ -5922,6 +5956,7 @@ fn containerMember(
59225956 wip_members,
59235957 gz,
59245958 .@"comptime",
5959 .empty,
59255960 member_node,
59265961 false,
59275962 );
......@@ -5938,6 +5973,7 @@ fn containerMember(
59385973 wip_members,
59395974 gz,
59405975 .@"usingnamespace",
5976 .empty,
59415977 member_node,
59425978 is_pub: {
59435979 const main_tokens = tree.nodes.items(.main_token);
......@@ -5962,6 +5998,7 @@ fn containerMember(
59625998 wip_members,
59635999 gz,
59646000 .unnamed_test,
6001 .empty,
59656002 member_node,
59666003 false,
59676004 );
......@@ -11670,23 +11707,6 @@ fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice {
1167011707 };
1167111708}
1167211709
11673fn testNameString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !Zir.NullTerminatedString {
11674 const gpa = astgen.gpa;
11675 const string_bytes = &astgen.string_bytes;
11676 const str_index: u32 = @intCast(string_bytes.items.len);
11677 const token_bytes = astgen.tree.tokenSlice(str_lit_token);
11678 try string_bytes.append(gpa, 0); // Indicates this is a test.
11679 try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
11680 const slice = string_bytes.items[str_index + 1 ..];
11681 if (mem.indexOfScalar(u8, slice, 0) != null) {
11682 return astgen.failTok(str_lit_token, "test name cannot contain null bytes", .{});
11683 } else if (slice.len == 0) {
11684 return astgen.failTok(str_lit_token, "empty test name must be omitted", .{});
11685 }
11686 try string_bytes.append(gpa, 0);
11687 return @enumFromInt(str_index);
11688}
11689
1169011710const Scope = struct {
1169111711 tag: Tag,
1169211712
......@@ -12077,12 +12097,9 @@ const GenZir = struct {
1207712097 cc_ref: Zir.Inst.Ref,
1207812098 ret_ref: Zir.Inst.Ref,
1207912099
12080 lib_name: Zir.NullTerminatedString,
1208112100 noalias_bits: u32,
1208212101 is_var_args: bool,
1208312102 is_inferred_error: bool,
12084 is_test: bool,
12085 is_extern: bool,
1208612103 is_noinline: bool,
1208712104
1208812105 /// Ignored if `body_gz == null`.
......@@ -12150,9 +12167,8 @@ const GenZir = struct {
1215012167
1215112168 const body_len = astgen.countBodyLenAfterFixupsExtraRefs(body, args.param_insts);
1215212169
12153 const tag: Zir.Inst.Tag, const payload_index: u32 = if (args.cc_ref != .none or args.lib_name != .empty or
12154 args.is_var_args or args.is_test or args.is_extern or
12155 args.noalias_bits != 0 or args.is_noinline)
12170 const tag: Zir.Inst.Tag, const payload_index: u32 = if (args.cc_ref != .none or
12171 args.is_var_args or args.noalias_bits != 0 or args.is_noinline)
1215612172 inst_info: {
1215712173 try astgen.extra.ensureUnusedCapacity(
1215812174 gpa,
......@@ -12160,7 +12176,6 @@ const GenZir = struct {
1216012176 fancyFnExprExtraLen(astgen, &.{}, cc_body, args.cc_ref) +
1216112177 fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) +
1216212178 body_len + src_locs_and_hash.len +
12163 @intFromBool(args.lib_name != .empty) +
1216412179 @intFromBool(args.noalias_bits != 0),
1216512180 );
1216612181 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{
......@@ -12169,10 +12184,7 @@ const GenZir = struct {
1216912184 .bits = .{
1217012185 .is_var_args = args.is_var_args,
1217112186 .is_inferred_error = args.is_inferred_error,
12172 .is_test = args.is_test,
12173 .is_extern = args.is_extern,
1217412187 .is_noinline = args.is_noinline,
12175 .has_lib_name = args.lib_name != .empty,
1217612188 .has_any_noalias = args.noalias_bits != 0,
1217712189
1217812190 .has_cc_ref = args.cc_ref != .none,
......@@ -12182,9 +12194,6 @@ const GenZir = struct {
1218212194 .has_ret_ty_body = ret_body.len != 0,
1218312195 },
1218412196 });
12185 if (args.lib_name != .empty) {
12186 astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name));
12187 }
1218812197
1218912198 const zir_datas = astgen.instructions.items(.data);
1219012199 if (cc_body.len != 0) {
......@@ -12279,61 +12288,6 @@ const GenZir = struct {
1227912288 @intFromBool(main_body.len > 0 or ref != .none);
1228012289 }
1228112290
12282 fn addVar(gz: *GenZir, args: struct {
12283 align_inst: Zir.Inst.Ref,
12284 lib_name: Zir.NullTerminatedString,
12285 var_type: Zir.Inst.Ref,
12286 init: Zir.Inst.Ref,
12287 is_extern: bool,
12288 is_const: bool,
12289 is_threadlocal: bool,
12290 }) !Zir.Inst.Ref {
12291 const astgen = gz.astgen;
12292 const gpa = astgen.gpa;
12293
12294 try gz.instructions.ensureUnusedCapacity(gpa, 1);
12295 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
12296
12297 try astgen.extra.ensureUnusedCapacity(
12298 gpa,
12299 @typeInfo(Zir.Inst.ExtendedVar).@"struct".fields.len +
12300 @intFromBool(args.lib_name != .empty) +
12301 @intFromBool(args.align_inst != .none) +
12302 @intFromBool(args.init != .none),
12303 );
12304 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{
12305 .var_type = args.var_type,
12306 });
12307 if (args.lib_name != .empty) {
12308 astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name));
12309 }
12310 if (args.align_inst != .none) {
12311 astgen.extra.appendAssumeCapacity(@intFromEnum(args.align_inst));
12312 }
12313 if (args.init != .none) {
12314 astgen.extra.appendAssumeCapacity(@intFromEnum(args.init));
12315 }
12316
12317 const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
12318 astgen.instructions.appendAssumeCapacity(.{
12319 .tag = .extended,
12320 .data = .{ .extended = .{
12321 .opcode = .variable,
12322 .small = @bitCast(Zir.Inst.ExtendedVar.Small{
12323 .has_lib_name = args.lib_name != .empty,
12324 .has_align = args.align_inst != .none,
12325 .has_init = args.init != .none,
12326 .is_extern = args.is_extern,
12327 .is_const = args.is_const,
12328 .is_threadlocal = args.is_threadlocal,
12329 }),
12330 .operand = payload_index,
12331 } },
12332 });
12333 gz.instructions.appendAssumeCapacity(new_index);
12334 return new_index.toRef();
12335 }
12336
1233712291 fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref {
1233812292 return gz.add(.{
1233912293 .tag = .int,
......@@ -13909,14 +13863,18 @@ const DeclarationName = union(enum) {
1390913863fn addFailedDeclaration(
1391013864 wip_members: *WipMembers,
1391113865 gz: *GenZir,
13912 name: DeclarationName,
13866 kind: Zir.Inst.Declaration.Unwrapped.Kind,
13867 name: Zir.NullTerminatedString,
1391313868 src_node: Ast.Node.Index,
1391413869 is_pub: bool,
1391513870) !void {
1391613871 const decl_inst = try gz.makeDeclaration(src_node);
1391713872 wip_members.nextDecl(decl_inst);
13918 var decl_gz = gz.makeSubBlock(&gz.base); // scope doesn't matter here
13919 _ = try decl_gz.add(.{
13873
13874 var dummy_gz = gz.makeSubBlock(&gz.base);
13875
13876 var value_gz = gz.makeSubBlock(&gz.base); // scope doesn't matter here
13877 _ = try value_gz.add(.{
1392013878 .tag = .extended,
1392113879 .data = .{ .extended = .{
1392213880 .opcode = .astgen_error,
......@@ -13924,110 +13882,198 @@ fn addFailedDeclaration(
1392413882 .operand = undefined,
1392513883 } },
1392613884 });
13927 try setDeclaration(
13928 decl_inst,
13929 @splat(0), // use a fixed hash to represent an AstGen failure; we don't care about source changes if AstGen still failed!
13930 name,
13931 gz.astgen.source_line,
13932 gz.astgen.source_column,
13933 is_pub,
13934 false, // we don't care about exports since semantic analysis will fail
13935 &decl_gz,
13936 null,
13937 );
13885
13886 try setDeclaration(decl_inst, .{
13887 .src_hash = @splat(0), // use a fixed hash to represent an AstGen failure; we don't care about source changes if AstGen still failed!
13888 .src_line = gz.astgen.source_line,
13889 .src_column = gz.astgen.source_column,
13890 .kind = kind,
13891 .name = name,
13892 .is_pub = is_pub,
13893 .is_threadlocal = false,
13894 .linkage = .normal,
13895 .type_gz = &dummy_gz,
13896 .align_gz = &dummy_gz,
13897 .linksection_gz = &dummy_gz,
13898 .addrspace_gz = &dummy_gz,
13899 .value_gz = &value_gz,
13900 });
1393813901}
1393913902
1394013903/// Sets all extra data for a `declaration` instruction.
13941/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
13904/// Unstacks `type_gz`, `align_gz`, `linksection_gz`, `addrspace_gz`, and `value_gz`.
1394213905fn setDeclaration(
1394313906 decl_inst: Zir.Inst.Index,
13944 src_hash: std.zig.SrcHash,
13945 name: DeclarationName,
13946 src_line: u32,
13947 src_column: u32,
13948 is_pub: bool,
13949 is_export: bool,
13950 value_gz: *GenZir,
13951 /// May be `null` if all these blocks would be empty.
13952 /// If `null`, then `value_gz` must have nothing stacked on it.
13953 extra_gzs: ?struct {
13954 /// Must be stacked on `value_gz`.
13907 args: struct {
13908 src_hash: std.zig.SrcHash,
13909 src_line: u32,
13910 src_column: u32,
13911
13912 kind: Zir.Inst.Declaration.Unwrapped.Kind,
13913 name: Zir.NullTerminatedString,
13914 is_pub: bool,
13915 is_threadlocal: bool,
13916 linkage: Zir.Inst.Declaration.Unwrapped.Linkage,
13917 lib_name: Zir.NullTerminatedString = .empty,
13918
13919 type_gz: *GenZir,
13920 /// Must be stacked on `type_gz`.
1395513921 align_gz: *GenZir,
1395613922 /// Must be stacked on `align_gz`.
1395713923 linksection_gz: *GenZir,
13958 /// Must be stacked on `linksection_gz`, and have nothing stacked on it.
13924 /// Must be stacked on `linksection_gz`.
1395913925 addrspace_gz: *GenZir,
13926 /// Must be stacked on `addrspace_gz` and have nothing stacked on top of it.
13927 value_gz: *GenZir,
1396013928 },
1396113929) !void {
13962 const astgen = value_gz.astgen;
13930 const astgen = args.value_gz.astgen;
1396313931 const gpa = astgen.gpa;
1396413932
13965 const empty_body: []Zir.Inst.Index = &.{};
13966 const value_body, const align_body, const linksection_body, const addrspace_body = if (extra_gzs) |e| .{
13967 value_gz.instructionsSliceUpto(e.align_gz),
13968 e.align_gz.instructionsSliceUpto(e.linksection_gz),
13969 e.linksection_gz.instructionsSliceUpto(e.addrspace_gz),
13970 e.addrspace_gz.instructionsSlice(),
13971 } else .{ value_gz.instructionsSlice(), empty_body, empty_body, empty_body };
13933 const type_body = args.type_gz.instructionsSliceUpto(args.align_gz);
13934 const align_body = args.align_gz.instructionsSliceUpto(args.linksection_gz);
13935 const linksection_body = args.linksection_gz.instructionsSliceUpto(args.addrspace_gz);
13936 const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.value_gz);
13937 const value_body = args.value_gz.instructionsSlice();
13938
13939 const has_name = args.name != .empty;
13940 const has_lib_name = args.lib_name != .empty;
13941 const has_type_body = type_body.len != 0;
13942 const has_special_body = align_body.len != 0 or linksection_body.len != 0 or addrspace_body.len != 0;
13943 const has_value_body = value_body.len != 0;
13944
13945 const id: Zir.Inst.Declaration.Flags.Id = switch (args.kind) {
13946 .unnamed_test => .unnamed_test,
13947 .@"test" => .@"test",
13948 .decltest => .decltest,
13949 .@"comptime" => .@"comptime",
13950 .@"usingnamespace" => if (args.is_pub) .pub_usingnamespace else .@"usingnamespace",
13951 .@"const" => switch (args.linkage) {
13952 .normal => if (args.is_pub) id: {
13953 if (has_special_body) break :id .pub_const;
13954 if (has_type_body) break :id .pub_const_typed;
13955 break :id .pub_const_simple;
13956 } else id: {
13957 if (has_special_body) break :id .@"const";
13958 if (has_type_body) break :id .const_typed;
13959 break :id .const_simple;
13960 },
13961 .@"extern" => if (args.is_pub) id: {
13962 if (has_lib_name) break :id .pub_extern_const;
13963 if (has_special_body) break :id .pub_extern_const;
13964 break :id .pub_extern_const_simple;
13965 } else id: {
13966 if (has_lib_name) break :id .extern_const;
13967 if (has_special_body) break :id .extern_const;
13968 break :id .extern_const_simple;
13969 },
13970 .@"export" => if (args.is_pub) .pub_export_const else .export_const,
13971 },
13972 .@"var" => switch (args.linkage) {
13973 .normal => if (args.is_pub) id: {
13974 if (args.is_threadlocal) break :id .pub_var_threadlocal;
13975 if (has_special_body) break :id .pub_var;
13976 if (has_type_body) break :id .pub_var;
13977 break :id .pub_var_simple;
13978 } else id: {
13979 if (args.is_threadlocal) break :id .var_threadlocal;
13980 if (has_special_body) break :id .@"var";
13981 if (has_type_body) break :id .@"var";
13982 break :id .var_simple;
13983 },
13984 .@"extern" => if (args.is_pub) id: {
13985 if (args.is_threadlocal) break :id .pub_extern_var_threadlocal;
13986 break :id .pub_extern_var;
13987 } else id: {
13988 if (args.is_threadlocal) break :id .extern_var_threadlocal;
13989 break :id .extern_var;
13990 },
13991 .@"export" => if (args.is_pub) id: {
13992 if (args.is_threadlocal) break :id .pub_export_var_threadlocal;
13993 break :id .pub_export_var;
13994 } else id: {
13995 if (args.is_threadlocal) break :id .export_var_threadlocal;
13996 break :id .export_var;
13997 },
13998 },
13999 };
1397214000
13973 const value_len = astgen.countBodyLenAfterFixups(value_body);
14001 assert(id.hasTypeBody() or !has_type_body);
14002 assert(id.hasSpecialBodies() or !has_special_body);
14003 assert(id.hasValueBody() == has_value_body);
14004 assert(id.linkage() == args.linkage);
14005 assert(id.hasName() == has_name);
14006 assert(id.hasLibName() or !has_lib_name);
14007 assert(id.isPub() == args.is_pub);
14008 assert(id.isThreadlocal() == args.is_threadlocal);
14009
14010 const type_len = astgen.countBodyLenAfterFixups(type_body);
1397414011 const align_len = astgen.countBodyLenAfterFixups(align_body);
1397514012 const linksection_len = astgen.countBodyLenAfterFixups(linksection_body);
1397614013 const addrspace_len = astgen.countBodyLenAfterFixups(addrspace_body);
14014 const value_len = astgen.countBodyLenAfterFixups(value_body);
14015
14016 const src_hash_arr: [4]u32 = @bitCast(args.src_hash);
14017 const flags: Zir.Inst.Declaration.Flags = .{
14018 .src_line = @intCast(args.src_line),
14019 .src_column = @intCast(args.src_column),
14020 .id = id,
14021 };
14022 const flags_arr: [2]u32 = @bitCast(flags);
1397714023
13978 const src_hash_arr: [4]u32 = @bitCast(src_hash);
14024 const need_extra: usize =
14025 @typeInfo(Zir.Inst.Declaration).@"struct".fields.len +
14026 @as(usize, @intFromBool(id.hasName())) +
14027 @as(usize, @intFromBool(id.hasLibName())) +
14028 @as(usize, @intFromBool(id.hasTypeBody())) +
14029 3 * @as(usize, @intFromBool(id.hasSpecialBodies())) +
14030 @as(usize, @intFromBool(id.hasValueBody())) +
14031 type_len + align_len + linksection_len + addrspace_len + value_len;
14032
14033 try astgen.extra.ensureUnusedCapacity(gpa, need_extra);
1397914034
1398014035 const extra: Zir.Inst.Declaration = .{
1398114036 .src_hash_0 = src_hash_arr[0],
1398214037 .src_hash_1 = src_hash_arr[1],
1398314038 .src_hash_2 = src_hash_arr[2],
1398414039 .src_hash_3 = src_hash_arr[3],
13985 .name = switch (name) {
13986 .named => |tok| @enumFromInt(@intFromEnum(try astgen.identAsString(tok))),
13987 .named_test => |tok| @enumFromInt(@intFromEnum(try astgen.testNameString(tok))),
13988 .decltest => |tok| @enumFromInt(str_idx: {
13989 const idx = astgen.string_bytes.items.len;
13990 try astgen.string_bytes.append(gpa, 0); // indicates this is a test
13991 try astgen.appendIdentStr(tok, &astgen.string_bytes);
13992 try astgen.string_bytes.append(gpa, 0); // end of the string
13993 break :str_idx idx;
13994 }),
13995 .unnamed_test => .unnamed_test,
13996 .@"comptime" => .@"comptime",
13997 .@"usingnamespace" => .@"usingnamespace",
13998 },
13999 .src_line = src_line,
14000 .src_column = src_column,
14001 .flags = .{
14002 .value_body_len = @intCast(value_len),
14003 .is_pub = is_pub,
14004 .is_export = is_export,
14005 .test_is_decltest = name == .decltest,
14006 .has_align_linksection_addrspace = align_len != 0 or linksection_len != 0 or addrspace_len != 0,
14007 },
14040 .flags_0 = flags_arr[0],
14041 .flags_1 = flags_arr[1],
1400814042 };
14009 astgen.instructions.items(.data)[@intFromEnum(decl_inst)].declaration.payload_index = try astgen.addExtra(extra);
14010 if (extra.flags.has_align_linksection_addrspace) {
14011 try astgen.extra.appendSlice(gpa, &.{
14043 astgen.instructions.items(.data)[@intFromEnum(decl_inst)].declaration.payload_index =
14044 astgen.addExtraAssumeCapacity(extra);
14045
14046 if (id.hasName()) {
14047 astgen.extra.appendAssumeCapacity(@intFromEnum(args.name));
14048 }
14049 if (id.hasLibName()) {
14050 astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name));
14051 }
14052 if (id.hasTypeBody()) {
14053 astgen.extra.appendAssumeCapacity(type_len);
14054 }
14055 if (id.hasSpecialBodies()) {
14056 astgen.extra.appendSliceAssumeCapacity(&.{
1401214057 align_len,
1401314058 linksection_len,
1401414059 addrspace_len,
1401514060 });
1401614061 }
14017 try astgen.extra.ensureUnusedCapacity(gpa, value_len + align_len + linksection_len + addrspace_len);
14018 astgen.appendBodyWithFixups(value_body);
14019 if (extra.flags.has_align_linksection_addrspace) {
14020 astgen.appendBodyWithFixups(align_body);
14021 astgen.appendBodyWithFixups(linksection_body);
14022 astgen.appendBodyWithFixups(addrspace_body);
14062 if (id.hasValueBody()) {
14063 astgen.extra.appendAssumeCapacity(value_len);
1402314064 }
1402414065
14025 if (extra_gzs) |e| {
14026 e.addrspace_gz.unstack();
14027 e.linksection_gz.unstack();
14028 e.align_gz.unstack();
14029 }
14030 value_gz.unstack();
14066 astgen.appendBodyWithFixups(type_body);
14067 astgen.appendBodyWithFixups(align_body);
14068 astgen.appendBodyWithFixups(linksection_body);
14069 astgen.appendBodyWithFixups(addrspace_body);
14070 astgen.appendBodyWithFixups(value_body);
14071
14072 args.value_gz.unstack();
14073 args.addrspace_gz.unstack();
14074 args.linksection_gz.unstack();
14075 args.align_gz.unstack();
14076 args.type_gz.unstack();
1403114077}
1403214078
1403314079/// Given a list of instructions, returns a list of all instructions which are a `ref` of one of the originals,
lib/std/zig/Zir.zig+392-95
......@@ -1868,10 +1868,6 @@ pub const Inst = struct {
18681868 /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
18691869 /// `noreturn` instructions may not go here; they must be part of the main `Tag` enum.
18701870 pub const Extended = enum(u16) {
1871 /// Declares a global variable.
1872 /// `operand` is payload index to `ExtendedVar`.
1873 /// `small` is `ExtendedVar.Small`.
1874 variable,
18751871 /// A struct type definition. Contains references to ZIR instructions for
18761872 /// the field types, defaults, and alignments.
18771873 /// `operand` is payload index to `StructDecl`.
......@@ -2493,26 +2489,25 @@ pub const Inst = struct {
24932489 };
24942490
24952491 /// Trailing:
2496 /// 0. lib_name: NullTerminatedString, // null terminated string index, if has_lib_name is set
24972492 /// if (has_cc_ref and !has_cc_body) {
2498 /// 1. cc: Ref,
2493 /// 0. cc: Ref,
24992494 /// }
25002495 /// if (has_cc_body) {
2501 /// 2. cc_body_len: u32
2502 /// 3. cc_body: u32 // for each cc_body_len
2496 /// 1. cc_body_len: u32
2497 /// 2. cc_body: u32 // for each cc_body_len
25032498 /// }
25042499 /// if (has_ret_ty_ref and !has_ret_ty_body) {
2505 /// 4. ret_ty: Ref,
2500 /// 3. ret_ty: Ref,
25062501 /// }
25072502 /// if (has_ret_ty_body) {
2508 /// 5. ret_ty_body_len: u32
2509 /// 6. ret_ty_body: u32 // for each ret_ty_body_len
2503 /// 4. ret_ty_body_len: u32
2504 /// 5. ret_ty_body: u32 // for each ret_ty_body_len
25102505 /// }
2511 /// 7. noalias_bits: u32 // if has_any_noalias
2506 /// 6. noalias_bits: u32 // if has_any_noalias
25122507 /// - each bit starting with LSB corresponds to parameter indexes
2513 /// 8. body: Index // for each body_len
2514 /// 9. src_locs: Func.SrcLocs // if body_len != 0
2515 /// 10. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
2508 /// 7. body: Index // for each body_len
2509 /// 8. src_locs: Func.SrcLocs // if body_len != 0
2510 /// 9. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
25162511 pub const FuncFancy = struct {
25172512 /// Points to the block that contains the param instructions for this function.
25182513 /// If this is a `declaration`, it refers to the declaration's value body.
......@@ -2522,38 +2517,16 @@ pub const Inst = struct {
25222517
25232518 /// If both has_cc_ref and has_cc_body are false, it means auto calling convention.
25242519 /// If both has_ret_ty_ref and has_ret_ty_body are false, it means void return type.
2525 pub const Bits = packed struct {
2520 pub const Bits = packed struct(u32) {
25262521 is_var_args: bool,
25272522 is_inferred_error: bool,
2528 is_test: bool,
2529 is_extern: bool,
25302523 is_noinline: bool,
25312524 has_cc_ref: bool,
25322525 has_cc_body: bool,
25332526 has_ret_ty_ref: bool,
25342527 has_ret_ty_body: bool,
2535 has_lib_name: bool,
25362528 has_any_noalias: bool,
2537 _: u21 = undefined,
2538 };
2539 };
2540
2541 /// Trailing:
2542 /// 0. lib_name: NullTerminatedString, // null terminated string index, if has_lib_name is set
2543 /// 1. align: Ref, // if has_align is set
2544 /// 2. init: Ref // if has_init is set
2545 /// The source node is obtained from the containing `block_inline`.
2546 pub const ExtendedVar = struct {
2547 var_type: Ref,
2548
2549 pub const Small = packed struct {
2550 has_lib_name: bool,
2551 has_align: bool,
2552 has_init: bool,
2553 is_extern: bool,
2554 is_const: bool,
2555 is_threadlocal: bool,
2556 _: u10 = undefined,
2529 _: u24 = undefined,
25572530 };
25582531 };
25592532
......@@ -2582,39 +2555,301 @@ pub const Inst = struct {
25822555 };
25832556
25842557 /// Trailing:
2585 /// 0. align_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `align`
2586 /// 1. linksection_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `linksection`
2587 /// 2. addrspace_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `addrspace`
2588 /// 3. value_body_inst: Zir.Inst.Index
2589 /// - for each `value_body_len`
2558 /// 0. name: NullTerminatedString // if `flags.id.hasName()`
2559 /// 1. lib_name: NullTerminatedString // if `flags.id.hasLibName()`
2560 /// 2. type_body_len: u32 // if `flags.id.hasTypeBody()`
2561 /// 3. align_body_len: u32 // if `flags.id.hasSpecialBodies()`
2562 /// 4. linksection_body_len: u32 // if `flags.id.hasSpecialBodies()`
2563 /// 5. addrspace_body_len: u32 // if `flags.id.hasSpecialBodies()`
2564 /// 6. value_body_len: u32 // if `flags.id.hasValueBody()`
2565 /// 7. type_body_inst: Zir.Inst.Index
2566 /// - for each `type_body_len`
25902567 /// - body to be exited via `break_inline` to this `declaration` instruction
2591 /// 4. align_body_inst: Zir.Inst.Index
2568 /// 8. align_body_inst: Zir.Inst.Index
25922569 /// - for each `align_body_len`
25932570 /// - body to be exited via `break_inline` to this `declaration` instruction
2594 /// 5. linksection_body_inst: Zir.Inst.Index
2571 /// 9. linksection_body_inst: Zir.Inst.Index
25952572 /// - for each `linksection_body_len`
25962573 /// - body to be exited via `break_inline` to this `declaration` instruction
2597 /// 6. addrspace_body_inst: Zir.Inst.Index
2574 /// 10. addrspace_body_inst: Zir.Inst.Index
25982575 /// - for each `addrspace_body_len`
25992576 /// - body to be exited via `break_inline` to this `declaration` instruction
2577 /// 11. value_body_inst: Zir.Inst.Index
2578 /// - for each `value_body_len`
2579 /// - body to be exited via `break_inline` to this `declaration` instruction
2580 /// - within this body, the `declaration` instruction refers to the resolved type from the type body
26002581 pub const Declaration = struct {
26012582 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
26022583 src_hash_0: u32,
26032584 src_hash_1: u32,
26042585 src_hash_2: u32,
26052586 src_hash_3: u32,
2606 /// The name of this `Decl`. Also indicates whether it is a test, comptime block, etc.
2607 name: Name,
2608 src_line: u32,
2609 src_column: u32,
2610 flags: Flags,
2587 // These fields should be concatenated and reinterpreted as a `Flags`.
2588 flags_0: u32,
2589 flags_1: u32,
2590
2591 pub const Unwrapped = struct {
2592 pub const Kind = enum {
2593 unnamed_test,
2594 @"test",
2595 decltest,
2596 @"comptime",
2597 @"usingnamespace",
2598 @"const",
2599 @"var",
2600 };
26112601
2612 pub const Flags = packed struct(u32) {
2613 value_body_len: u28,
2602 pub const Linkage = enum {
2603 normal,
2604 @"extern",
2605 @"export",
2606 };
2607
2608 src_node: Ast.Node.Index,
2609
2610 src_line: u32,
2611 src_column: u32,
2612
2613 kind: Kind,
2614 /// Always `.empty` for `kind` of `unnamed_test`, `.@"comptime"`, `.@"usingnamespace"`.
2615 name: NullTerminatedString,
2616 /// Always `false` for `kind` of `unnamed_test`, `.@"test"`, `.decltest`, `.@"comptime"`.
26142617 is_pub: bool,
2615 is_export: bool,
2616 test_is_decltest: bool,
2617 has_align_linksection_addrspace: bool,
2618 /// Always `false` for `kind != .@"var"`.
2619 is_threadlocal: bool,
2620 /// Always `.normal` for `kind != .@"const" and kind != .@"var"`.
2621 linkage: Linkage,
2622 /// Always `.empty` for `linkage != .@"extern"`.
2623 lib_name: NullTerminatedString,
2624
2625 /// Always populated for `linkage == .@"extern".
2626 type_body: ?[]const Inst.Index,
2627 align_body: ?[]const Inst.Index,
2628 linksection_body: ?[]const Inst.Index,
2629 addrspace_body: ?[]const Inst.Index,
2630 /// Always populated for `linkage != .@"extern".
2631 value_body: ?[]const Inst.Index,
2632 };
2633
2634 pub const Flags = packed struct(u64) {
2635 src_line: u30,
2636 src_column: u29,
2637 id: Id,
2638
2639 pub const Id = enum(u5) {
2640 unnamed_test,
2641 @"test",
2642 decltest,
2643 @"comptime",
2644
2645 @"usingnamespace",
2646 pub_usingnamespace,
2647
2648 const_simple,
2649 const_typed,
2650 @"const",
2651 pub_const_simple,
2652 pub_const_typed,
2653 pub_const,
2654
2655 extern_const_simple,
2656 extern_const,
2657 pub_extern_const_simple,
2658 pub_extern_const,
2659
2660 export_const,
2661 pub_export_const,
2662
2663 var_simple,
2664 @"var",
2665 var_threadlocal,
2666 pub_var_simple,
2667 pub_var,
2668 pub_var_threadlocal,
2669
2670 extern_var,
2671 extern_var_threadlocal,
2672 pub_extern_var,
2673 pub_extern_var_threadlocal,
2674
2675 export_var,
2676 export_var_threadlocal,
2677 pub_export_var,
2678 pub_export_var_threadlocal,
2679
2680 pub fn hasName(id: Id) bool {
2681 return switch (id) {
2682 .unnamed_test,
2683 .@"comptime",
2684 .@"usingnamespace",
2685 .pub_usingnamespace,
2686 => false,
2687 else => true,
2688 };
2689 }
2690
2691 pub fn hasLibName(id: Id) bool {
2692 return switch (id) {
2693 .extern_const,
2694 .pub_extern_const,
2695 .extern_var,
2696 .extern_var_threadlocal,
2697 .pub_extern_var,
2698 .pub_extern_var_threadlocal,
2699 => true,
2700 else => false,
2701 };
2702 }
2703
2704 pub fn hasTypeBody(id: Id) bool {
2705 return switch (id) {
2706 .unnamed_test,
2707 .@"test",
2708 .decltest,
2709 .@"comptime",
2710 .@"usingnamespace",
2711 .pub_usingnamespace,
2712 => false, // these constructs are untyped
2713 .const_simple,
2714 .pub_const_simple,
2715 .var_simple,
2716 .pub_var_simple,
2717 => false, // these reprs omit type bodies
2718 else => true,
2719 };
2720 }
2721
2722 pub fn hasValueBody(id: Id) bool {
2723 return switch (id) {
2724 .extern_const_simple,
2725 .extern_const,
2726 .pub_extern_const_simple,
2727 .pub_extern_const,
2728 .extern_var,
2729 .extern_var_threadlocal,
2730 .pub_extern_var,
2731 .pub_extern_var_threadlocal,
2732 => false, // externs do not have values
2733 else => true,
2734 };
2735 }
2736
2737 pub fn hasSpecialBodies(id: Id) bool {
2738 return switch (id) {
2739 .unnamed_test,
2740 .@"test",
2741 .decltest,
2742 .@"comptime",
2743 .@"usingnamespace",
2744 .pub_usingnamespace,
2745 => false, // these constructs are untyped
2746 .const_simple,
2747 .const_typed,
2748 .pub_const_simple,
2749 .pub_const_typed,
2750 .extern_const_simple,
2751 .pub_extern_const_simple,
2752 .var_simple,
2753 .pub_var_simple,
2754 => false, // these reprs omit special bodies
2755 else => true,
2756 };
2757 }
2758
2759 pub fn linkage(id: Id) Declaration.Unwrapped.Linkage {
2760 return switch (id) {
2761 .extern_const_simple,
2762 .extern_const,
2763 .pub_extern_const_simple,
2764 .pub_extern_const,
2765 .extern_var,
2766 .extern_var_threadlocal,
2767 .pub_extern_var,
2768 .pub_extern_var_threadlocal,
2769 => .@"extern",
2770 .export_const,
2771 .pub_export_const,
2772 .export_var,
2773 .export_var_threadlocal,
2774 .pub_export_var,
2775 .pub_export_var_threadlocal,
2776 => .@"export",
2777 else => .normal,
2778 };
2779 }
2780
2781 pub fn kind(id: Id) Declaration.Unwrapped.Kind {
2782 return switch (id) {
2783 .unnamed_test => .unnamed_test,
2784 .@"test" => .@"test",
2785 .decltest => .decltest,
2786 .@"comptime" => .@"comptime",
2787 .@"usingnamespace", .pub_usingnamespace => .@"usingnamespace",
2788 .const_simple,
2789 .const_typed,
2790 .@"const",
2791 .pub_const_simple,
2792 .pub_const_typed,
2793 .pub_const,
2794 .extern_const_simple,
2795 .extern_const,
2796 .pub_extern_const_simple,
2797 .pub_extern_const,
2798 .export_const,
2799 .pub_export_const,
2800 => .@"const",
2801 .var_simple,
2802 .@"var",
2803 .var_threadlocal,
2804 .pub_var_simple,
2805 .pub_var,
2806 .pub_var_threadlocal,
2807 .extern_var,
2808 .extern_var_threadlocal,
2809 .pub_extern_var,
2810 .pub_extern_var_threadlocal,
2811 .export_var,
2812 .export_var_threadlocal,
2813 .pub_export_var,
2814 .pub_export_var_threadlocal,
2815 => .@"var",
2816 };
2817 }
2818
2819 pub fn isPub(id: Id) bool {
2820 return switch (id) {
2821 .pub_usingnamespace,
2822 .pub_const_simple,
2823 .pub_const_typed,
2824 .pub_const,
2825 .pub_extern_const_simple,
2826 .pub_extern_const,
2827 .pub_export_const,
2828 .pub_var_simple,
2829 .pub_var,
2830 .pub_var_threadlocal,
2831 .pub_extern_var,
2832 .pub_extern_var_threadlocal,
2833 .pub_export_var,
2834 .pub_export_var_threadlocal,
2835 => true,
2836 else => false,
2837 };
2838 }
2839
2840 pub fn isThreadlocal(id: Id) bool {
2841 return switch (id) {
2842 .var_threadlocal,
2843 .pub_var_threadlocal,
2844 .extern_var_threadlocal,
2845 .pub_extern_var_threadlocal,
2846 .export_var_threadlocal,
2847 .pub_export_var_threadlocal,
2848 => true,
2849 else => false,
2850 };
2851 }
2852 };
26182853 };
26192854
26202855 pub const Name = enum(u32) {
......@@ -2647,17 +2882,24 @@ pub const Inst = struct {
26472882 };
26482883
26492884 pub const Bodies = struct {
2650 value_body: []const Index,
2885 type_body: ?[]const Index,
26512886 align_body: ?[]const Index,
26522887 linksection_body: ?[]const Index,
26532888 addrspace_body: ?[]const Index,
2889 value_body: ?[]const Index,
26542890 };
26552891
26562892 pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies {
26572893 var extra_index: u32 = extra_end;
2658 const value_body_len = declaration.flags.value_body_len;
2894 const value_body_len = declaration.value_body_len;
2895 const type_body_len: u32 = len: {
2896 if (!declaration.flags().kind.hasTypeBody()) break :len 0;
2897 const len = zir.extra[extra_index];
2898 extra_index += 1;
2899 break :len len;
2900 };
26592901 const align_body_len, const linksection_body_len, const addrspace_body_len = lens: {
2660 if (!declaration.flags.has_align_linksection_addrspace) {
2902 if (!declaration.flags.kind.hasSpecialBodies()) {
26612903 break :lens .{ 0, 0, 0 };
26622904 }
26632905 const lens = zir.extra[extra_index..][0..3].*;
......@@ -2665,21 +2907,30 @@ pub const Inst = struct {
26652907 break :lens lens;
26662908 };
26672909 return .{
2668 .value_body = b: {
2669 defer extra_index += value_body_len;
2670 break :b zir.bodySlice(extra_index, value_body_len);
2910 .type_body = if (type_body_len == 0) null else b: {
2911 const b = zir.bodySlice(extra_index, type_body_len);
2912 extra_index += type_body_len;
2913 break :b b;
26712914 },
26722915 .align_body = if (align_body_len == 0) null else b: {
2673 defer extra_index += align_body_len;
2674 break :b zir.bodySlice(extra_index, align_body_len);
2916 const b = zir.bodySlice(extra_index, align_body_len);
2917 extra_index += align_body_len;
2918 break :b b;
26752919 },
26762920 .linksection_body = if (linksection_body_len == 0) null else b: {
2677 defer extra_index += linksection_body_len;
2678 break :b zir.bodySlice(extra_index, linksection_body_len);
2921 const b = zir.bodySlice(extra_index, linksection_body_len);
2922 extra_index += linksection_body_len;
2923 break :b b;
26792924 },
26802925 .addrspace_body = if (addrspace_body_len == 0) null else b: {
2681 defer extra_index += addrspace_body_len;
2682 break :b zir.bodySlice(extra_index, addrspace_body_len);
2926 const b = zir.bodySlice(extra_index, addrspace_body_len);
2927 extra_index += addrspace_body_len;
2928 break :b b;
2929 },
2930 .value_body = if (value_body_len == 0) null else b: {
2931 const b = zir.bodySlice(extra_index, value_body_len);
2932 extra_index += value_body_len;
2933 break :b b;
26832934 },
26842935 };
26852936 }
......@@ -3711,18 +3962,18 @@ pub const DeclContents = struct {
37113962pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void {
37123963 contents.clear();
37133964
3714 const declaration, const extra_end = zir.getDeclaration(decl_inst);
3715 const bodies = declaration.getBodies(extra_end, zir);
3965 const decl = zir.getDeclaration(decl_inst);
37163966
37173967 // `defer` instructions duplicate the same body arbitrarily many times, but we only want to traverse
37183968 // their contents once per defer. So, we store the extra index of the body here to deduplicate.
37193969 var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
37203970 defer found_defers.deinit(gpa);
37213971
3722 try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
3723 if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3724 if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3725 if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3972 if (decl.type_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3973 if (decl.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3974 if (decl.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3975 if (decl.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
3976 if (decl.value_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
37263977}
37273978
37283979/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
......@@ -3991,7 +4242,6 @@ fn findTrackableInner(
39914242 .value_placeholder => unreachable,
39924243
39934244 // Once again, we start with the boring tags.
3994 .variable,
39954245 .this,
39964246 .ret_addr,
39974247 .builtin_src,
......@@ -4237,7 +4487,6 @@ fn findTrackableInner(
42374487 const inst_data = datas[@intFromEnum(inst)].pl_node;
42384488 const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
42394489 var extra_index: usize = extra.end;
4240 extra_index += @intFromBool(extra.data.bits.has_lib_name);
42414490
42424491 if (extra.data.bits.has_cc_body) {
42434492 const body_len = zir.extra[extra_index];
......@@ -4470,8 +4719,7 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
44704719 return zir.bodySlice(param_block.end, param_block.data.body_len);
44714720 },
44724721 .declaration => {
4473 const decl, const extra_end = zir.getDeclaration(param_block_index);
4474 return decl.getBodies(extra_end, zir).value_body;
4722 return zir.getDeclaration(param_block_index).value_body.?;
44754723 },
44764724 else => unreachable,
44774725 }
......@@ -4526,7 +4774,6 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
45264774 var ret_ty_ref: Inst.Ref = .void_type;
45274775 var ret_ty_body: []const Inst.Index = &.{};
45284776
4529 extra_index += @intFromBool(extra.data.bits.has_lib_name);
45304777 if (extra.data.bits.has_cc_body) {
45314778 extra_index += zir.extra[extra_index] + 1;
45324779 } else if (extra.data.bits.has_cc_ref) {
......@@ -4555,17 +4802,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
45554802 },
45564803 else => unreachable,
45574804 };
4558 const param_body = switch (tags[@intFromEnum(info.param_block)]) {
4559 .block, .block_comptime, .block_inline => param_body: {
4560 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
4561 break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
4562 },
4563 .declaration => param_body: {
4564 const decl, const extra_end = zir.getDeclaration(info.param_block);
4565 break :param_body decl.getBodies(extra_end, zir).value_body;
4566 },
4567 else => unreachable,
4568 };
4805 const param_body = zir.getParamBody(fn_inst);
45694806 var total_params_len: u32 = 0;
45704807 for (param_body) |inst| {
45714808 switch (tags[@intFromEnum(inst)]) {
......@@ -4585,13 +4822,74 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
45854822 };
45864823}
45874824
4588pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } {
4825pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) Inst.Declaration.Unwrapped {
45894826 assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration);
45904827 const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].declaration;
45914828 const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
4829
4830 const flags_vals: [2]u32 = .{ extra.data.flags_0, extra.data.flags_1 };
4831 const flags: Inst.Declaration.Flags = @bitCast(flags_vals);
4832
4833 var extra_index = extra.end;
4834
4835 const name: NullTerminatedString = if (flags.id.hasName()) name: {
4836 const name = zir.extra[extra_index];
4837 extra_index += 1;
4838 break :name @enumFromInt(name);
4839 } else .empty;
4840
4841 const lib_name: NullTerminatedString = if (flags.id.hasLibName()) lib_name: {
4842 const lib_name = zir.extra[extra_index];
4843 extra_index += 1;
4844 break :lib_name @enumFromInt(lib_name);
4845 } else .empty;
4846
4847 const type_body_len: u32 = if (flags.id.hasTypeBody()) len: {
4848 const len = zir.extra[extra_index];
4849 extra_index += 1;
4850 break :len len;
4851 } else 0;
4852 const align_body_len: u32, const linksection_body_len: u32, const addrspace_body_len: u32 = lens: {
4853 if (!flags.id.hasSpecialBodies()) break :lens .{ 0, 0, 0 };
4854 const lens = zir.extra[extra_index..][0..3].*;
4855 extra_index += 3;
4856 break :lens lens;
4857 };
4858 const value_body_len: u32 = if (flags.id.hasValueBody()) len: {
4859 const len = zir.extra[extra_index];
4860 extra_index += 1;
4861 break :len len;
4862 } else 0;
4863
4864 const type_body = zir.bodySlice(extra_index, type_body_len);
4865 extra_index += type_body_len;
4866 const align_body = zir.bodySlice(extra_index, align_body_len);
4867 extra_index += align_body_len;
4868 const linksection_body = zir.bodySlice(extra_index, linksection_body_len);
4869 extra_index += linksection_body_len;
4870 const addrspace_body = zir.bodySlice(extra_index, addrspace_body_len);
4871 extra_index += addrspace_body_len;
4872 const value_body = zir.bodySlice(extra_index, value_body_len);
4873 extra_index += value_body_len;
4874
45924875 return .{
4593 extra.data,
4594 @intCast(extra.end),
4876 .src_node = pl_node.src_node,
4877
4878 .src_line = flags.src_line,
4879 .src_column = flags.src_column,
4880
4881 .kind = flags.id.kind(),
4882 .name = name,
4883 .is_pub = flags.id.isPub(),
4884 .is_threadlocal = flags.id.isThreadlocal(),
4885 .linkage = flags.id.linkage(),
4886 .lib_name = lib_name,
4887
4888 .type_body = if (type_body_len == 0) null else type_body,
4889 .align_body = if (align_body_len == 0) null else align_body,
4890 .linksection_body = if (linksection_body_len == 0) null else linksection_body,
4891 .addrspace_body = if (addrspace_body_len == 0) null else addrspace_body,
4892 .value_body = if (value_body_len == 0) null else value_body,
45954893 };
45964894}
45974895
......@@ -4636,7 +4934,6 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
46364934 }
46374935 const bits = extra.data.bits;
46384936 var extra_index = extra.end;
4639 extra_index += @intFromBool(bits.has_lib_name);
46404937 if (bits.has_cc_body) {
46414938 const body_len = zir.extra[extra_index];
46424939 extra_index += 1 + body_len;
src/Compilation.zig+52-29
......@@ -348,12 +348,15 @@ const Job = union(enum) {
348348 /// Corresponds to the task in `link.Task`.
349349 /// Only needed for backends that haven't yet been updated to not race against Sema.
350350 codegen_type: InternPool.Index,
351 /// The `Cau` must be semantically analyzed (and possibly export itself).
351 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
352 /// This may be its first time being analyzed, or it may be outdated.
353 /// If the unit is a function, a `codegen_func` job will then be queued.
354 analyze_comptime_unit: InternPool.AnalUnit,
355 /// This function must be semantically analyzed.
352356 /// This may be its first time being analyzed, or it may be outdated.
353 analyze_cau: InternPool.Cau.Index,
354 /// Analyze the body of a runtime function.
355357 /// After analysis, a `codegen_func` job will be queued.
356358 /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
359 /// This job is separate from `analyze_comptime_unit` because it has a different priority.
357360 analyze_func: InternPool.Index,
358361 /// The main source file for the module needs to be analyzed.
359362 analyze_mod: *Package.Module,
......@@ -2903,6 +2906,7 @@ const Header = extern struct {
29032906 file_deps_len: u32,
29042907 src_hash_deps_len: u32,
29052908 nav_val_deps_len: u32,
2909 nav_ty_deps_len: u32,
29062910 namespace_deps_len: u32,
29072911 namespace_name_deps_len: u32,
29082912 first_dependency_len: u32,
......@@ -2946,6 +2950,7 @@ pub fn saveState(comp: *Compilation) !void {
29462950 .file_deps_len = @intCast(ip.file_deps.count()),
29472951 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
29482952 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
2953 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
29492954 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
29502955 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
29512956 .first_dependency_len = @intCast(ip.first_dependency.count()),
......@@ -2976,6 +2981,8 @@ pub fn saveState(comp: *Compilation) !void {
29762981 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
29772982 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
29782983 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));
2984 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys()));
2985 addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values()));
29792986 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));
29802987 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));
29812988 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
......@@ -3141,8 +3148,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
31413148 }
31423149
31433150 const file_index = switch (anal_unit.unwrap()) {
3144 .cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
3145 .func => |ip_index| (zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip) orelse continue).file,
3151 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
3152 .nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
3153 .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
3154 .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
31463155 };
31473156
31483157 // Skip errors for AnalUnits within files that had a parse failure.
......@@ -3374,11 +3383,9 @@ pub fn addModuleErrorMsg(
33743383 const rt_file_path = try src.file_scope.fullPath(gpa);
33753384 defer gpa.free(rt_file_path);
33763385 const name = switch (ref.referencer.unwrap()) {
3377 .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
3378 .nav => |nav| ip.getNav(nav).name.toSlice(ip),
3379 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
3380 .none => "comptime",
3381 },
3386 .@"comptime" => "comptime",
3387 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
3388 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
33823389 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
33833390 };
33843391 try ref_traces.append(gpa, .{
......@@ -3641,10 +3648,14 @@ fn performAllTheWorkInner(
36413648 // If there's no work queued, check if there's anything outdated
36423649 // which we need to work on, and queue it if so.
36433650 if (try zcu.findOutdatedToAnalyze()) |outdated| {
3644 switch (outdated.unwrap()) {
3645 .cau => |cau| try comp.queueJob(.{ .analyze_cau = cau }),
3646 .func => |func| try comp.queueJob(.{ .analyze_func = func }),
3647 }
3651 try comp.queueJob(switch (outdated.unwrap()) {
3652 .func => |f| .{ .analyze_func = f },
3653 .@"comptime",
3654 .nav_ty,
3655 .nav_val,
3656 .type,
3657 => .{ .analyze_comptime_unit = outdated },
3658 });
36483659 continue;
36493660 }
36503661 }
......@@ -3667,13 +3678,13 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
36673678 .codegen_nav => |nav_index| {
36683679 const zcu = comp.zcu.?;
36693680 const nav = zcu.intern_pool.getNav(nav_index);
3670 if (nav.analysis_owner.unwrap()) |cau| {
3671 const unit = InternPool.AnalUnit.wrap(.{ .cau = cau });
3681 if (nav.analysis != null) {
3682 const unit: InternPool.AnalUnit = .wrap(.{ .nav_val = nav_index });
36723683 if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) {
36733684 return;
36743685 }
36753686 }
3676 assert(nav.status == .resolved);
3687 assert(nav.status == .fully_resolved);
36773688 comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index });
36783689 },
36793690 .codegen_func => |func| {
......@@ -3688,36 +3699,48 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
36883699
36893700 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
36903701 defer pt.deactivate();
3691 pt.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
3692 error.OutOfMemory => return error.OutOfMemory,
3702
3703 pt.ensureFuncBodyUpToDate(func) catch |err| switch (err) {
3704 error.OutOfMemory => |e| return e,
36933705 error.AnalysisFail => return,
36943706 };
36953707 },
3696 .analyze_cau => |cau_index| {
3708 .analyze_comptime_unit => |unit| {
3709 const named_frame = tracy.namedFrame("analyze_comptime_unit");
3710 defer named_frame.end();
3711
36973712 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
36983713 defer pt.deactivate();
3699 pt.ensureCauAnalyzed(cau_index) catch |err| switch (err) {
3700 error.OutOfMemory => return error.OutOfMemory,
3714
3715 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
3716 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
3717 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
3718 .nav_val => |nav| pt.ensureNavValUpToDate(nav),
3719 .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,
3720 .func => unreachable,
3721 };
3722 maybe_err catch |err| switch (err) {
3723 error.OutOfMemory => |e| return e,
37013724 error.AnalysisFail => return,
37023725 };
3726
37033727 queue_test_analysis: {
37043728 if (!comp.config.is_test) break :queue_test_analysis;
3729 const nav = switch (unit.unwrap()) {
3730 .nav_val => |nav| nav,
3731 else => break :queue_test_analysis,
3732 };
37053733
37063734 // Check if this is a test function.
37073735 const ip = &pt.zcu.intern_pool;
3708 const cau = ip.getCau(cau_index);
3709 const nav_index = switch (cau.owner.unwrap()) {
3710 .none, .type => break :queue_test_analysis,
3711 .nav => |nav| nav,
3712 };
3713 if (!pt.zcu.test_functions.contains(nav_index)) {
3736 if (!pt.zcu.test_functions.contains(nav)) {
37143737 break :queue_test_analysis;
37153738 }
37163739
37173740 // Tests are always emitted in test binaries. The decl_refs are created by
37183741 // Zcu.populateTestFunctions, but this will not queue body analysis, so do
37193742 // that now.
3720 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav_index).status.resolved.val);
3743 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val);
37213744 }
37223745 },
37233746 .resolve_type_fully => |ty| {
src/InternPool.zig+355-336
......@@ -34,6 +34,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index),
3434/// Dependencies on the value of a Nav.
3535/// Value is index into `dep_entries` of the first dependency on this Nav value.
3636nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
37/// Dependencies on the type of a Nav.
38/// Value is index into `dep_entries` of the first dependency on this Nav value.
39nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
3740/// Dependencies on an interned value, either:
3841/// * a runtime function (invalidated when its IES changes)
3942/// * a container type requiring resolution (invalidated when the type must be recreated at a new index)
......@@ -80,6 +83,7 @@ pub const empty: InternPool = .{
8083 .file_deps = .empty,
8184 .src_hash_deps = .empty,
8285 .nav_val_deps = .empty,
86 .nav_ty_deps = .empty,
8387 .interned_deps = .empty,
8488 .namespace_deps = .empty,
8589 .namespace_name_deps = .empty,
......@@ -363,33 +367,56 @@ pub fn rehashTrackedInsts(
363367}
364368
365369/// Analysis Unit. Represents a single entity which undergoes semantic analysis.
366/// This is either a `Cau` or a runtime function.
367/// The LSB is used as a tag bit.
368370/// This is the "source" of an incremental dependency edge.
369pub const AnalUnit = packed struct(u32) {
370 kind: enum(u1) { cau, func },
371 index: u31,
372 pub const Unwrapped = union(enum) {
373 cau: Cau.Index,
371pub const AnalUnit = packed struct(u64) {
372 kind: Kind,
373 id: u32,
374
375 pub const Kind = enum(u32) {
376 @"comptime",
377 nav_val,
378 nav_ty,
379 type,
380 func,
381 };
382
383 pub const Unwrapped = union(Kind) {
384 /// This `AnalUnit` analyzes the body of the given `comptime` declaration.
385 @"comptime": ComptimeUnit.Id,
386 /// This `AnalUnit` resolves the value of the given `Nav`.
387 nav_val: Nav.Index,
388 /// This `AnalUnit` resolves the type of the given `Nav`.
389 nav_ty: Nav.Index,
390 /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type.
391 /// Generated tag enums are never used here (they do not undergo type resolution).
392 type: InternPool.Index,
393 /// This `AnalUnit` analyzes the body of the given runtime function.
374394 func: InternPool.Index,
375395 };
376 pub fn unwrap(as: AnalUnit) Unwrapped {
377 return switch (as.kind) {
378 .cau => .{ .cau = @enumFromInt(as.index) },
379 .func => .{ .func = @enumFromInt(as.index) },
396
397 pub fn unwrap(au: AnalUnit) Unwrapped {
398 return switch (au.kind) {
399 inline else => |tag| @unionInit(
400 Unwrapped,
401 @tagName(tag),
402 @enumFromInt(au.id),
403 ),
380404 };
381405 }
382406 pub fn wrap(raw: Unwrapped) AnalUnit {
383407 return switch (raw) {
384 .cau => |cau| .{ .kind = .cau, .index = @intCast(@intFromEnum(cau)) },
385 .func => |func| .{ .kind = .func, .index = @intCast(@intFromEnum(func)) },
408 inline else => |id, tag| .{
409 .kind = tag,
410 .id = @intFromEnum(id),
411 },
386412 };
387413 }
414
388415 pub fn toOptional(as: AnalUnit) Optional {
389 return @enumFromInt(@as(u32, @bitCast(as)));
416 return @enumFromInt(@as(u64, @bitCast(as)));
390417 }
391 pub const Optional = enum(u32) {
392 none = std.math.maxInt(u32),
418 pub const Optional = enum(u64) {
419 none = std.math.maxInt(u64),
393420 _,
394421 pub fn unwrap(opt: Optional) ?AnalUnit {
395422 return switch (opt) {
......@@ -400,97 +427,30 @@ pub const AnalUnit = packed struct(u32) {
400427 };
401428};
402429
403/// Comptime Analysis Unit. This is the "subject" of semantic analysis where the root context is
404/// comptime; every `Sema` is owned by either a `Cau` or a runtime function (see `AnalUnit`).
405/// The state stored here is immutable.
406///
407/// * Every ZIR `declaration` has a `Cau` (post-instantiation) to analyze the declaration body.
408/// * Every `struct`, `union`, and `enum` has a `Cau` for type resolution.
409///
410/// The analysis status of a `Cau` is known only from state in `Zcu`.
411/// An entry in `Zcu.failed_analysis` indicates an analysis failure with associated error message.
412/// An entry in `Zcu.transitive_failed_analysis` indicates a transitive analysis failure.
413///
414/// 12 bytes.
415pub const Cau = struct {
416 /// The `declaration`, `struct_decl`, `enum_decl`, or `union_decl` instruction which this `Cau` analyzes.
430pub const ComptimeUnit = extern struct {
417431 zir_index: TrackedInst.Index,
418 /// The namespace which this `Cau` should be analyzed within.
419432 namespace: NamespaceIndex,
420 /// This field essentially tells us what to do with the information resulting from
421 /// semantic analysis. See `Owner.Unwrapped` for details.
422 owner: Owner,
423
424 /// See `Owner.Unwrapped` for details. In terms of representation, the `InternPool.Index`
425 /// or `Nav.Index` is cast to a `u31` and stored in `index`. As a special case, if
426 /// `@as(u32, @bitCast(owner)) == 0xFFFF_FFFF`, then the value is treated as `.none`.
427 pub const Owner = packed struct(u32) {
428 kind: enum(u1) { type, nav },
429 index: u31,
430
431 pub const Unwrapped = union(enum) {
432 /// This `Cau` exists in isolation. It is a global `comptime` declaration, or (TODO ANYTHING ELSE?).
433 /// After semantic analysis completes, the result is discarded.
434 none,
435 /// This `Cau` is owned by the given type for type resolution.
436 /// This is a `struct`, `union`, or `enum` type.
437 type: InternPool.Index,
438 /// This `Cau` is owned by the given `Nav` to resolve its value.
439 /// When analyzing the `Cau`, the resulting value is stored as the value of this `Nav`.
440 nav: Nav.Index,
441 };
442433
443 pub fn unwrap(owner: Owner) Unwrapped {
444 if (@as(u32, @bitCast(owner)) == std.math.maxInt(u32)) {
445 return .none;
446 }
447 return switch (owner.kind) {
448 .type => .{ .type = @enumFromInt(owner.index) },
449 .nav => .{ .nav = @enumFromInt(owner.index) },
450 };
451 }
452
453 fn wrap(raw: Unwrapped) Owner {
454 return switch (raw) {
455 .none => @bitCast(@as(u32, std.math.maxInt(u32))),
456 .type => |ty| .{ .kind = .type, .index = @intCast(@intFromEnum(ty)) },
457 .nav => |nav| .{ .kind = .nav, .index = @intCast(@intFromEnum(nav)) },
458 };
459 }
460 };
434 comptime {
435 assert(std.meta.hasUniqueRepresentation(ComptimeUnit));
436 }
461437
462 pub const Index = enum(u32) {
438 pub const Id = enum(u32) {
463439 _,
464 pub const Optional = enum(u32) {
465 none = std.math.maxInt(u32),
466 _,
467 pub fn unwrap(opt: Optional) ?Cau.Index {
468 return switch (opt) {
469 .none => null,
470 _ => @enumFromInt(@intFromEnum(opt)),
471 };
472 }
473
474 const debug_state = InternPool.debug_state;
475 };
476 pub fn toOptional(i: Cau.Index) Optional {
477 return @enumFromInt(@intFromEnum(i));
478 }
479440 const Unwrapped = struct {
480441 tid: Zcu.PerThread.Id,
481442 index: u32,
482
483 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) Cau.Index {
443 fn wrap(unwrapped: Unwrapped, ip: *const InternPool) ComptimeUnit.Id {
484444 assert(@intFromEnum(unwrapped.tid) <= ip.getTidMask());
485 assert(unwrapped.index <= ip.getIndexMask(u31));
486 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_31 |
445 assert(unwrapped.index <= ip.getIndexMask(u32));
446 return @enumFromInt(@as(u32, @intFromEnum(unwrapped.tid)) << ip.tid_shift_32 |
487447 unwrapped.index);
488448 }
489449 };
490 fn unwrap(cau_index: Cau.Index, ip: *const InternPool) Unwrapped {
450 fn unwrap(id: Id, ip: *const InternPool) Unwrapped {
491451 return .{
492 .tid = @enumFromInt(@intFromEnum(cau_index) >> ip.tid_shift_31 & ip.getTidMask()),
493 .index = @intFromEnum(cau_index) & ip.getIndexMask(u31),
452 .tid = @enumFromInt(@intFromEnum(id) >> ip.tid_shift_32 & ip.getTidMask()),
453 .index = @intFromEnum(id) & ip.getIndexMask(u31),
494454 };
495455 }
496456
......@@ -507,6 +467,11 @@ pub const Cau = struct {
507467/// * Generic instances have a `Nav` corresponding to the instantiated function.
508468/// * `@extern` calls create a `Nav` whose value is a `.@"extern"`.
509469///
470/// This data structure is optimized for the `analysis_info != null` case, because this is much more
471/// common in practice; the other case is used only for externs and for generic instances. At the time
472/// of writing, in the compiler itself, around 74% of all `Nav`s have `analysis_info != null`.
473/// (Specifically, 104225 / 140923)
474///
510475/// `Nav.Repr` is the in-memory representation.
511476pub const Nav = struct {
512477 /// The unqualified name of this `Nav`. Namespace lookups use this name, and error messages may use it.
......@@ -514,16 +479,31 @@ pub const Nav = struct {
514479 name: NullTerminatedString,
515480 /// The fully-qualified name of this `Nav`.
516481 fqn: NullTerminatedString,
517 /// If the value of this `Nav` is resolved by semantic analysis, it is within this `Cau`.
518 /// If this is `.none`, then `status == .resolved` always.
519 analysis_owner: Cau.Index.Optional,
482 /// This field is populated iff this `Nav` is resolved by semantic analysis.
483 /// If this is `null`, then `status == .resolved` always.
484 analysis: ?struct {
485 namespace: NamespaceIndex,
486 zir_index: TrackedInst.Index,
487 },
520488 /// TODO: this is a hack! If #20663 isn't accepted, let's figure out something a bit better.
521489 is_usingnamespace: bool,
522490 status: union(enum) {
523 /// This `Nav` is pending semantic analysis through `analysis_owner`.
491 /// This `Nav` is pending semantic analysis.
524492 unresolved,
493 /// The type of this `Nav` is resolved; the value is queued for resolution.
494 type_resolved: struct {
495 type: InternPool.Index,
496 alignment: Alignment,
497 @"linksection": OptionalNullTerminatedString,
498 @"addrspace": std.builtin.AddressSpace,
499 is_const: bool,
500 is_threadlocal: bool,
501 /// This field is whether this `Nav` is a literal `extern` definition.
502 /// It does *not* tell you whether this might alias an extern fn (see #21027).
503 is_extern_decl: bool,
504 },
525505 /// The value of this `Nav` is resolved.
526 resolved: struct {
506 fully_resolved: struct {
527507 val: InternPool.Index,
528508 alignment: Alignment,
529509 @"linksection": OptionalNullTerminatedString,
......@@ -531,30 +511,96 @@ pub const Nav = struct {
531511 },
532512 },
533513
534 /// Asserts that `status == .resolved`.
514 /// Asserts that `status != .unresolved`.
535515 pub fn typeOf(nav: Nav, ip: *const InternPool) InternPool.Index {
536 return ip.typeOf(nav.status.resolved.val);
516 return switch (nav.status) {
517 .unresolved => unreachable,
518 .type_resolved => |r| r.type,
519 .fully_resolved => |r| ip.typeOf(r.val),
520 };
521 }
522
523 /// Always returns `null` for `status == .type_resolved`. This function is inteded
524 /// to be used by code generation, since semantic analysis will ensure that any `Nav`
525 /// which is potentially `extern` is fully resolved.
526 /// Asserts that `status != .unresolved`.
527 pub fn getExtern(nav: Nav, ip: *const InternPool) ?Key.Extern {
528 return switch (nav.status) {
529 .unresolved => unreachable,
530 .type_resolved => null,
531 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
532 .@"extern" => |e| e,
533 else => null,
534 },
535 };
537536 }
538537
539 /// Asserts that `status == .resolved`.
540 pub fn isExtern(nav: Nav, ip: *const InternPool) bool {
541 return ip.indexToKey(nav.status.resolved.val) == .@"extern";
538 /// Asserts that `status != .unresolved`.
539 pub fn getAddrspace(nav: Nav) std.builtin.AddressSpace {
540 return switch (nav.status) {
541 .unresolved => unreachable,
542 .type_resolved => |r| r.@"addrspace",
543 .fully_resolved => |r| r.@"addrspace",
544 };
545 }
546
547 /// Asserts that `status != .unresolved`.
548 pub fn getAlignment(nav: Nav) Alignment {
549 return switch (nav.status) {
550 .unresolved => unreachable,
551 .type_resolved => |r| r.alignment,
552 .fully_resolved => |r| r.alignment,
553 };
554 }
555
556 /// Asserts that `status != .unresolved`.
557 pub fn isThreadlocal(nav: Nav, ip: *const InternPool) bool {
558 return switch (nav.status) {
559 .unresolved => unreachable,
560 .type_resolved => |r| r.is_threadlocal,
561 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
562 .@"extern" => |e| e.is_threadlocal,
563 .variable => |v| v.is_threadlocal,
564 else => false,
565 },
566 };
567 }
568
569 /// If this returns `true`, then a pointer to this `Nav` might actually be encoded as a pointer
570 /// to some other `Nav` due to an extern definition or extern alias (see #21027).
571 /// This query is valid on `Nav`s for whom only the type is resolved.
572 /// Asserts that `status != .unresolved`.
573 pub fn isExternOrFn(nav: Nav, ip: *const InternPool) bool {
574 return switch (nav.status) {
575 .unresolved => unreachable,
576 .type_resolved => |r| {
577 if (r.is_extern_decl) return true;
578 const tag = ip.zigTypeTagOrPoison(r.type) catch unreachable;
579 if (tag == .@"fn") return true;
580 return false;
581 },
582 .fully_resolved => |r| {
583 if (ip.indexToKey(r.val) == .@"extern") return true;
584 const tag = ip.zigTypeTagOrPoison(ip.typeOf(r.val)) catch unreachable;
585 if (tag == .@"fn") return true;
586 return false;
587 },
588 };
542589 }
543590
544591 /// Get the ZIR instruction corresponding to this `Nav`, used to resolve source locations.
545592 /// This is a `declaration`.
546593 pub fn srcInst(nav: Nav, ip: *const InternPool) TrackedInst.Index {
547 if (nav.analysis_owner.unwrap()) |cau| {
548 return ip.getCau(cau).zir_index;
594 if (nav.analysis) |a| {
595 return a.zir_index;
549596 }
550 // A `Nav` with no corresponding `Cau` always has a resolved value.
551 return switch (ip.indexToKey(nav.status.resolved.val)) {
597 // A `Nav` which does not undergo analysis always has a resolved value.
598 return switch (ip.indexToKey(nav.status.fully_resolved.val)) {
552599 .func => |func| {
553 // Since there was no `analysis_owner`, this must be an instantiation.
554 // Go up to the generic owner and consult *its* `analysis_owner`.
600 // Since `analysis` was not populated, this must be an instantiation.
601 // Go up to the generic owner and consult *its* `analysis` field.
555602 const go_nav = ip.getNav(ip.indexToKey(func.generic_owner).func.owner_nav);
556 const go_cau = ip.getCau(go_nav.analysis_owner.unwrap().?);
557 return go_cau.zir_index;
603 return go_nav.analysis.?.zir_index;
558604 },
559605 .@"extern" => |@"extern"| @"extern".zir_index, // extern / @extern
560606 else => unreachable,
......@@ -600,24 +646,29 @@ pub const Nav = struct {
600646 };
601647
602648 /// The compact in-memory representation of a `Nav`.
603 /// 18 bytes.
649 /// 26 bytes.
604650 const Repr = struct {
605651 name: NullTerminatedString,
606652 fqn: NullTerminatedString,
607 analysis_owner: Cau.Index.Optional,
608 /// Populated only if `bits.status == .resolved`.
609 val: InternPool.Index,
610 /// Populated only if `bits.status == .resolved`.
653 // The following 1 fields are either both populated, or both `.none`.
654 analysis_namespace: OptionalNamespaceIndex,
655 analysis_zir_index: TrackedInst.Index.Optional,
656 /// Populated only if `bits.status != .unresolved`.
657 type_or_val: InternPool.Index,
658 /// Populated only if `bits.status != .unresolved`.
611659 @"linksection": OptionalNullTerminatedString,
612660 bits: Bits,
613661
614662 const Bits = packed struct(u16) {
615 status: enum(u1) { unresolved, resolved },
616 /// Populated only if `bits.status == .resolved`.
663 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
664 /// Populated only if `bits.status != .unresolved`.
617665 alignment: Alignment,
618 /// Populated only if `bits.status == .resolved`.
666 /// Populated only if `bits.status != .unresolved`.
619667 @"addrspace": std.builtin.AddressSpace,
620 _: u3 = 0,
668 /// Populated only if `bits.status == .type_resolved`.
669 is_const: bool,
670 /// Populated only if `bits.status == .type_resolved`.
671 is_threadlocal: bool,
621672 is_usingnamespace: bool,
622673 };
623674
......@@ -625,12 +676,27 @@ pub const Nav = struct {
625676 return .{
626677 .name = repr.name,
627678 .fqn = repr.fqn,
628 .analysis_owner = repr.analysis_owner,
679 .analysis = if (repr.analysis_namespace.unwrap()) |namespace| .{
680 .namespace = namespace,
681 .zir_index = repr.analysis_zir_index.unwrap().?,
682 } else a: {
683 assert(repr.analysis_zir_index == .none);
684 break :a null;
685 },
629686 .is_usingnamespace = repr.bits.is_usingnamespace,
630687 .status = switch (repr.bits.status) {
631688 .unresolved => .unresolved,
632 .resolved => .{ .resolved = .{
633 .val = repr.val,
689 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
690 .type = repr.type_or_val,
691 .alignment = repr.bits.alignment,
692 .@"linksection" = repr.@"linksection",
693 .@"addrspace" = repr.bits.@"addrspace",
694 .is_const = repr.bits.is_const,
695 .is_threadlocal = repr.bits.is_threadlocal,
696 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
697 } },
698 .fully_resolved => .{ .fully_resolved = .{
699 .val = repr.type_or_val,
634700 .alignment = repr.bits.alignment,
635701 .@"linksection" = repr.@"linksection",
636702 .@"addrspace" = repr.bits.@"addrspace",
......@@ -646,14 +712,17 @@ pub const Nav = struct {
646712 return .{
647713 .name = nav.name,
648714 .fqn = nav.fqn,
649 .analysis_owner = nav.analysis_owner,
650 .val = switch (nav.status) {
715 .analysis_namespace = if (nav.analysis) |a| a.namespace.toOptional() else .none,
716 .analysis_zir_index = if (nav.analysis) |a| a.zir_index.toOptional() else .none,
717 .type_or_val = switch (nav.status) {
651718 .unresolved => .none,
652 .resolved => |r| r.val,
719 .type_resolved => |r| r.type,
720 .fully_resolved => |r| r.val,
653721 },
654722 .@"linksection" = switch (nav.status) {
655723 .unresolved => .none,
656 .resolved => |r| r.@"linksection",
724 .type_resolved => |r| r.@"linksection",
725 .fully_resolved => |r| r.@"linksection",
657726 },
658727 .bits = switch (nav.status) {
659728 .unresolved => .{
......@@ -661,12 +730,24 @@ pub const Nav = struct {
661730 .alignment = .none,
662731 .@"addrspace" = .generic,
663732 .is_usingnamespace = nav.is_usingnamespace,
733 .is_const = false,
734 .is_threadlocal = false,
735 },
736 .type_resolved => |r| .{
737 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
738 .alignment = r.alignment,
739 .@"addrspace" = r.@"addrspace",
740 .is_usingnamespace = nav.is_usingnamespace,
741 .is_const = r.is_const,
742 .is_threadlocal = r.is_threadlocal,
664743 },
665 .resolved => |r| .{
666 .status = .resolved,
744 .fully_resolved => |r| .{
745 .status = .fully_resolved,
667746 .alignment = r.alignment,
668747 .@"addrspace" = r.@"addrspace",
669748 .is_usingnamespace = nav.is_usingnamespace,
749 .is_const = false,
750 .is_threadlocal = false,
670751 },
671752 },
672753 };
......@@ -677,6 +758,7 @@ pub const Dependee = union(enum) {
677758 file: FileIndex,
678759 src_hash: TrackedInst.Index,
679760 nav_val: Nav.Index,
761 nav_ty: Nav.Index,
680762 interned: Index,
681763 namespace: TrackedInst.Index,
682764 namespace_name: NamespaceNameKey,
......@@ -726,6 +808,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
726808 .file => |x| ip.file_deps.get(x),
727809 .src_hash => |x| ip.src_hash_deps.get(x),
728810 .nav_val => |x| ip.nav_val_deps.get(x),
811 .nav_ty => |x| ip.nav_ty_deps.get(x),
729812 .interned => |x| ip.interned_deps.get(x),
730813 .namespace => |x| ip.namespace_deps.get(x),
731814 .namespace_name => |x| ip.namespace_name_deps.get(x),
......@@ -763,6 +846,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
763846 .file => ip.file_deps,
764847 .src_hash => ip.src_hash_deps,
765848 .nav_val => ip.nav_val_deps,
849 .nav_ty => ip.nav_ty_deps,
766850 .interned => ip.interned_deps,
767851 .namespace => ip.namespace_deps,
768852 .namespace_name => ip.namespace_name_deps,
......@@ -862,8 +946,8 @@ const Local = struct {
862946 tracked_insts: ListMutate,
863947 files: ListMutate,
864948 maps: ListMutate,
865 caus: ListMutate,
866949 navs: ListMutate,
950 comptime_units: ListMutate,
867951
868952 namespaces: BucketListMutate,
869953 } align(std.atomic.cache_line),
......@@ -876,8 +960,8 @@ const Local = struct {
876960 tracked_insts: TrackedInsts,
877961 files: List(File),
878962 maps: Maps,
879 caus: Caus,
880963 navs: Navs,
964 comptime_units: ComptimeUnits,
881965
882966 namespaces: Namespaces,
883967
......@@ -899,8 +983,8 @@ const Local = struct {
899983 const Strings = List(struct { u8 });
900984 const TrackedInsts = List(struct { TrackedInst.MaybeLost });
901985 const Maps = List(struct { FieldMap });
902 const Caus = List(struct { Cau });
903986 const Navs = List(Nav.Repr);
987 const ComptimeUnits = List(struct { ComptimeUnit });
904988
905989 const namespaces_bucket_width = 8;
906990 const namespaces_bucket_mask = (1 << namespaces_bucket_width) - 1;
......@@ -1275,21 +1359,21 @@ const Local = struct {
12751359 };
12761360 }
12771361
1278 pub fn getMutableCaus(local: *Local, gpa: Allocator) Caus.Mutable {
1362 pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable {
12791363 return .{
12801364 .gpa = gpa,
12811365 .arena = &local.mutate.arena,
1282 .mutate = &local.mutate.caus,
1283 .list = &local.shared.caus,
1366 .mutate = &local.mutate.navs,
1367 .list = &local.shared.navs,
12841368 };
12851369 }
12861370
1287 pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable {
1371 pub fn getMutableComptimeUnits(local: *Local, gpa: Allocator) ComptimeUnits.Mutable {
12881372 return .{
12891373 .gpa = gpa,
12901374 .arena = &local.mutate.arena,
1291 .mutate = &local.mutate.navs,
1292 .list = &local.shared.navs,
1375 .mutate = &local.mutate.comptime_units,
1376 .list = &local.shared.comptime_units,
12931377 };
12941378 }
12951379
......@@ -2018,7 +2102,6 @@ pub const Key = union(enum) {
20182102 ty: Index,
20192103 init: Index,
20202104 owner_nav: Nav.Index,
2021 lib_name: OptionalNullTerminatedString,
20222105 is_threadlocal: bool,
20232106 is_weak_linkage: bool,
20242107 };
......@@ -2111,36 +2194,36 @@ pub const Key = union(enum) {
21112194 return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered);
21122195 }
21132196
2114 pub fn setAnalysisState(func: Func, ip: *InternPool, state: FuncAnalysis.State) void {
2197 pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void {
21152198 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
21162199 extra_mutex.lock();
21172200 defer extra_mutex.unlock();
21182201
21192202 const analysis_ptr = func.analysisPtr(ip);
21202203 var analysis = analysis_ptr.*;
2121 analysis.state = state;
2204 analysis.calls_or_awaits_errorable_fn = value;
21222205 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
21232206 }
21242207
2125 pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void {
2208 pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void {
21262209 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
21272210 extra_mutex.lock();
21282211 defer extra_mutex.unlock();
21292212
21302213 const analysis_ptr = func.analysisPtr(ip);
21312214 var analysis = analysis_ptr.*;
2132 analysis.calls_or_awaits_errorable_fn = value;
2215 analysis.branch_hint = hint;
21332216 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
21342217 }
21352218
2136 pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void {
2219 pub fn setAnalyzed(func: Func, ip: *InternPool) void {
21372220 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
21382221 extra_mutex.lock();
21392222 defer extra_mutex.unlock();
21402223
21412224 const analysis_ptr = func.analysisPtr(ip);
21422225 var analysis = analysis_ptr.*;
2143 analysis.branch_hint = hint;
2226 analysis.is_analyzed = true;
21442227 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
21452228 }
21462229
......@@ -2741,7 +2824,6 @@ pub const Key = union(enum) {
27412824 return a_info.owner_nav == b_info.owner_nav and
27422825 a_info.ty == b_info.ty and
27432826 a_info.init == b_info.init and
2744 a_info.lib_name == b_info.lib_name and
27452827 a_info.is_threadlocal == b_info.is_threadlocal and
27462828 a_info.is_weak_linkage == b_info.is_weak_linkage;
27472829 },
......@@ -3054,8 +3136,6 @@ pub const LoadedUnionType = struct {
30543136 // TODO: the non-fqn will be needed by the new dwarf structure
30553137 /// The name of this union type.
30563138 name: NullTerminatedString,
3057 /// The `Cau` within which type resolution occurs.
3058 cau: Cau.Index,
30593139 /// Represents the declarations inside this union.
30603140 namespace: NamespaceIndex,
30613141 /// The enum tag type.
......@@ -3372,7 +3452,6 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
33723452 .tid = unwrapped_index.tid,
33733453 .extra_index = data,
33743454 .name = type_union.data.name,
3375 .cau = type_union.data.cau,
33763455 .namespace = type_union.data.namespace,
33773456 .enum_tag_ty = type_union.data.tag_ty,
33783457 .field_types = field_types,
......@@ -3389,8 +3468,6 @@ pub const LoadedStructType = struct {
33893468 // TODO: the non-fqn will be needed by the new dwarf structure
33903469 /// The name of this struct type.
33913470 name: NullTerminatedString,
3392 /// The `Cau` within which type resolution occurs.
3393 cau: Cau.Index,
33943471 namespace: NamespaceIndex,
33953472 /// Index of the `struct_decl` or `reify` ZIR instruction.
33963473 zir_index: TrackedInst.Index,
......@@ -3981,7 +4058,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
39814058 switch (item.tag) {
39824059 .type_struct => {
39834060 const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]);
3984 const cau: Cau.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "cau").?]);
39854061 const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]);
39864062 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);
39874063 const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "fields_len").?];
......@@ -4068,7 +4144,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
40684144 .tid = unwrapped_index.tid,
40694145 .extra_index = item.data,
40704146 .name = name,
4071 .cau = cau,
40724147 .namespace = namespace,
40734148 .zir_index = zir_index,
40744149 .layout = if (flags.is_extern) .@"extern" else .auto,
......@@ -4085,7 +4160,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
40854160 },
40864161 .type_struct_packed, .type_struct_packed_inits => {
40874162 const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?]);
4088 const cau: Cau.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "cau").?]);
40894163 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]);
40904164 const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?];
40914165 const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?]);
......@@ -4132,7 +4206,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
41324206 .tid = unwrapped_index.tid,
41334207 .extra_index = item.data,
41344208 .name = name,
4135 .cau = cau,
41364209 .namespace = namespace,
41374210 .zir_index = zir_index,
41384211 .layout = .@"packed",
......@@ -4155,9 +4228,6 @@ pub const LoadedEnumType = struct {
41554228 // TODO: the non-fqn will be needed by the new dwarf structure
41564229 /// The name of this enum type.
41574230 name: NullTerminatedString,
4158 /// The `Cau` within which type resolution occurs.
4159 /// `null` if this is a generated tag type.
4160 cau: Cau.Index.Optional,
41614231 /// Represents the declarations inside this enum.
41624232 namespace: NamespaceIndex,
41634233 /// An integer type which is used for the numerical value of the enum.
......@@ -4234,21 +4304,15 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
42344304 .type_enum_auto => {
42354305 const extra = extraDataTrail(extra_list, EnumAuto, item.data);
42364306 var extra_index: u32 = @intCast(extra.end);
4237 const cau: Cau.Index.Optional = if (extra.data.zir_index == .none) cau: {
4307 if (extra.data.zir_index == .none) {
42384308 extra_index += 1; // owner_union
4239 break :cau .none;
4240 } else cau: {
4241 const cau: Cau.Index = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
4242 extra_index += 1; // cau
4243 break :cau cau.toOptional();
4244 };
4309 }
42454310 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
42464311 extra_index += 2; // type_hash: PackedU64
42474312 break :c 0;
42484313 } else extra.data.captures_len;
42494314 return .{
42504315 .name = extra.data.name,
4251 .cau = cau,
42524316 .namespace = extra.data.namespace,
42534317 .tag_ty = extra.data.int_tag_type,
42544318 .names = .{
......@@ -4274,21 +4338,15 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
42744338 };
42754339 const extra = extraDataTrail(extra_list, EnumExplicit, item.data);
42764340 var extra_index: u32 = @intCast(extra.end);
4277 const cau: Cau.Index.Optional = if (extra.data.zir_index == .none) cau: {
4341 if (extra.data.zir_index == .none) {
42784342 extra_index += 1; // owner_union
4279 break :cau .none;
4280 } else cau: {
4281 const cau: Cau.Index = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
4282 extra_index += 1; // cau
4283 break :cau cau.toOptional();
4284 };
4343 }
42854344 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {
42864345 extra_index += 2; // type_hash: PackedU64
42874346 break :c 0;
42884347 } else extra.data.captures_len;
42894348 return .{
42904349 .name = extra.data.name,
4291 .cau = cau,
42924350 .namespace = extra.data.namespace,
42934351 .tag_ty = extra.data.int_tag_type,
42944352 .names = .{
......@@ -5258,7 +5316,6 @@ pub const Tag = enum(u8) {
52585316 .payload = EnumExplicit,
52595317 .trailing = struct {
52605318 owner_union: Index,
5261 cau: ?Cau.Index,
52625319 captures: ?[]CaptureValue,
52635320 type_hash: ?u64,
52645321 field_names: []NullTerminatedString,
......@@ -5304,7 +5361,6 @@ pub const Tag = enum(u8) {
53045361 .payload = EnumAuto,
53055362 .trailing = struct {
53065363 owner_union: ?Index,
5307 cau: ?Cau.Index,
53085364 captures: ?[]CaptureValue,
53095365 type_hash: ?u64,
53105366 field_names: []NullTerminatedString,
......@@ -5573,9 +5629,6 @@ pub const Tag = enum(u8) {
55735629 /// May be `none`.
55745630 init: Index,
55755631 owner_nav: Nav.Index,
5576 /// Library name if specified.
5577 /// For example `extern "c" var stderrp = ...` would have 'c' as library name.
5578 lib_name: OptionalNullTerminatedString,
55795632 flags: Flags,
55805633
55815634 pub const Flags = packed struct(u32) {
......@@ -5684,7 +5737,6 @@ pub const Tag = enum(u8) {
56845737 size: u32,
56855738 /// Only valid after .have_layout
56865739 padding: u32,
5687 cau: Cau.Index,
56885740 namespace: NamespaceIndex,
56895741 /// The enum that provides the list of field names and values.
56905742 tag_ty: Index,
......@@ -5715,7 +5767,6 @@ pub const Tag = enum(u8) {
57155767 /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits
57165768 pub const TypeStructPacked = struct {
57175769 name: NullTerminatedString,
5718 cau: Cau.Index,
57195770 zir_index: TrackedInst.Index,
57205771 fields_len: u32,
57215772 namespace: NamespaceIndex,
......@@ -5763,7 +5814,6 @@ pub const Tag = enum(u8) {
57635814 /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved
57645815 pub const TypeStruct = struct {
57655816 name: NullTerminatedString,
5766 cau: Cau.Index,
57675817 zir_index: TrackedInst.Index,
57685818 namespace: NamespaceIndex,
57695819 fields_len: u32,
......@@ -5820,7 +5870,7 @@ pub const Tag = enum(u8) {
58205870/// equality or hashing, except for `inferred_error_set` which is considered
58215871/// to be part of the type of the function.
58225872pub const FuncAnalysis = packed struct(u32) {
5823 state: State,
5873 is_analyzed: bool,
58245874 branch_hint: std.builtin.BranchHint,
58255875 is_noinline: bool,
58265876 calls_or_awaits_errorable_fn: bool,
......@@ -5828,20 +5878,7 @@ pub const FuncAnalysis = packed struct(u32) {
58285878 inferred_error_set: bool,
58295879 disable_instrumentation: bool,
58305880
5831 _: u23 = 0,
5832
5833 pub const State = enum(u2) {
5834 /// The runtime function has never been referenced.
5835 /// As such, it has never been analyzed, nor is it queued for analysis.
5836 unreferenced,
5837 /// The runtime function has been referenced, but has not yet been analyzed.
5838 /// Its semantic analysis is queued.
5839 queued,
5840 /// The runtime function has been (or is currently being) semantically analyzed.
5841 /// To know if analysis succeeded, consult `zcu.[transitive_]failed_analysis`.
5842 /// To know if analysis is up-to-date, consult `zcu.[potentially_]outdated`.
5843 analyzed,
5844 };
5881 _: u24 = 0,
58455882};
58465883
58475884pub const Bytes = struct {
......@@ -6093,11 +6130,10 @@ pub const Array = struct {
60936130
60946131/// Trailing:
60956132/// 0. owner_union: Index // if `zir_index == .none`
6096/// 1. cau: Cau.Index // if `zir_index != .none`
6097/// 2. capture: CaptureValue // for each `captures_len`
6098/// 3. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6099/// 4. field name: NullTerminatedString for each fields_len; declaration order
6100/// 5. tag value: Index for each fields_len; declaration order
6133/// 1. capture: CaptureValue // for each `captures_len`
6134/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6135/// 3. field name: NullTerminatedString for each fields_len; declaration order
6136/// 4. tag value: Index for each fields_len; declaration order
61016137pub const EnumExplicit = struct {
61026138 name: NullTerminatedString,
61036139 /// `std.math.maxInt(u32)` indicates this type is reified.
......@@ -6120,10 +6156,9 @@ pub const EnumExplicit = struct {
61206156
61216157/// Trailing:
61226158/// 0. owner_union: Index // if `zir_index == .none`
6123/// 1. cau: Cau.Index // if `zir_index != .none`
6124/// 2. capture: CaptureValue // for each `captures_len`
6125/// 3. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6126/// 4. field name: NullTerminatedString for each fields_len; declaration order
6159/// 1. capture: CaptureValue // for each `captures_len`
6160/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6161/// 3. field name: NullTerminatedString for each fields_len; declaration order
61276162pub const EnumAuto = struct {
61286163 name: NullTerminatedString,
61296164 /// `std.math.maxInt(u32)` indicates this type is reified.
......@@ -6413,32 +6448,32 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void {
64136448 ip.locals = try gpa.alloc(Local, used_threads);
64146449 @memset(ip.locals, .{
64156450 .shared = .{
6416 .items = Local.List(Item).empty,
6417 .extra = Local.Extra.empty,
6418 .limbs = Local.Limbs.empty,
6419 .strings = Local.Strings.empty,
6420 .tracked_insts = Local.TrackedInsts.empty,
6421 .files = Local.List(File).empty,
6422 .maps = Local.Maps.empty,
6423 .caus = Local.Caus.empty,
6424 .navs = Local.Navs.empty,
6425
6426 .namespaces = Local.Namespaces.empty,
6451 .items = .empty,
6452 .extra = .empty,
6453 .limbs = .empty,
6454 .strings = .empty,
6455 .tracked_insts = .empty,
6456 .files = .empty,
6457 .maps = .empty,
6458 .navs = .empty,
6459 .comptime_units = .empty,
6460
6461 .namespaces = .empty,
64276462 },
64286463 .mutate = .{
64296464 .arena = .{},
64306465
6431 .items = Local.ListMutate.empty,
6432 .extra = Local.ListMutate.empty,
6433 .limbs = Local.ListMutate.empty,
6434 .strings = Local.ListMutate.empty,
6435 .tracked_insts = Local.ListMutate.empty,
6436 .files = Local.ListMutate.empty,
6437 .maps = Local.ListMutate.empty,
6438 .caus = Local.ListMutate.empty,
6439 .navs = Local.ListMutate.empty,
6466 .items = .empty,
6467 .extra = .empty,
6468 .limbs = .empty,
6469 .strings = .empty,
6470 .tracked_insts = .empty,
6471 .files = .empty,
6472 .maps = .empty,
6473 .navs = .empty,
6474 .comptime_units = .empty,
64406475
6441 .namespaces = Local.BucketListMutate.empty,
6476 .namespaces = .empty,
64426477 },
64436478 });
64446479
......@@ -6486,6 +6521,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
64866521 ip.file_deps.deinit(gpa);
64876522 ip.src_hash_deps.deinit(gpa);
64886523 ip.nav_val_deps.deinit(gpa);
6524 ip.nav_ty_deps.deinit(gpa);
64896525 ip.interned_deps.deinit(gpa);
64906526 ip.namespace_deps.deinit(gpa);
64916527 ip.namespace_name_deps.deinit(gpa);
......@@ -6511,7 +6547,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
65116547 namespace.priv_decls.deinit(gpa);
65126548 namespace.pub_usingnamespace.deinit(gpa);
65136549 namespace.priv_usingnamespace.deinit(gpa);
6514 namespace.other_decls.deinit(gpa);
6550 namespace.comptime_decls.deinit(gpa);
6551 namespace.test_decls.deinit(gpa);
65156552 }
65166553 };
65176554 const maps = local.getMutableMaps(gpa);
......@@ -6530,8 +6567,6 @@ pub fn activate(ip: *const InternPool) void {
65306567 _ = OptionalString.debug_state;
65316568 _ = NullTerminatedString.debug_state;
65326569 _ = OptionalNullTerminatedString.debug_state;
6533 _ = Cau.Index.debug_state;
6534 _ = Cau.Index.Optional.debug_state;
65356570 _ = Nav.Index.debug_state;
65366571 _ = Nav.Index.Optional.debug_state;
65376572 std.debug.assert(debug_state.intern_pool == null);
......@@ -6716,14 +6751,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
67166751 if (extra.data.captures_len == std.math.maxInt(u32)) {
67176752 break :ns .{ .reified = .{
67186753 .zir_index = zir_index,
6719 .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(),
6754 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
67206755 } };
67216756 }
67226757 break :ns .{ .declared = .{
67236758 .zir_index = zir_index,
67246759 .captures = .{ .owned = .{
67256760 .tid = unwrapped_index.tid,
6726 .start = extra.end + 1,
6761 .start = extra.end,
67276762 .len = extra.data.captures_len,
67286763 } },
67296764 } };
......@@ -6740,14 +6775,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
67406775 if (extra.data.captures_len == std.math.maxInt(u32)) {
67416776 break :ns .{ .reified = .{
67426777 .zir_index = zir_index,
6743 .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(),
6778 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
67446779 } };
67456780 }
67466781 break :ns .{ .declared = .{
67476782 .zir_index = zir_index,
67486783 .captures = .{ .owned = .{
67496784 .tid = unwrapped_index.tid,
6750 .start = extra.end + 1,
6785 .start = extra.end,
67516786 .len = extra.data.captures_len,
67526787 } },
67536788 } };
......@@ -6928,7 +6963,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
69286963 .ty = extra.ty,
69296964 .init = extra.init,
69306965 .owner_nav = extra.owner_nav,
6931 .lib_name = extra.lib_name,
69326966 .is_threadlocal = extra.flags.is_threadlocal,
69336967 .is_weak_linkage = extra.flags.is_weak_linkage,
69346968 } };
......@@ -6944,8 +6978,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
69446978 .is_threadlocal = extra.flags.is_threadlocal,
69456979 .is_weak_linkage = extra.flags.is_weak_linkage,
69466980 .is_dll_import = extra.flags.is_dll_import,
6947 .alignment = nav.status.resolved.alignment,
6948 .@"addrspace" = nav.status.resolved.@"addrspace",
6981 .alignment = nav.status.fully_resolved.alignment,
6982 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
69496983 .zir_index = extra.zir_index,
69506984 .owner_nav = extra.owner_nav,
69516985 } };
......@@ -7575,7 +7609,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
75757609 .ty = variable.ty,
75767610 .init = variable.init,
75777611 .owner_nav = variable.owner_nav,
7578 .lib_name = variable.lib_name,
75797612 .flags = .{
75807613 .is_const = false,
75817614 .is_threadlocal = variable.is_threadlocal,
......@@ -8330,7 +8363,6 @@ pub fn getUnionType(
83308363 .size = std.math.maxInt(u32),
83318364 .padding = std.math.maxInt(u32),
83328365 .name = undefined, // set by `finish`
8333 .cau = undefined, // set by `finish`
83348366 .namespace = undefined, // set by `finish`
83358367 .tag_ty = ini.enum_tag_ty,
83368368 .zir_index = switch (ini.key) {
......@@ -8382,7 +8414,6 @@ pub fn getUnionType(
83828414 .tid = tid,
83838415 .index = gop.put(),
83848416 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8385 .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "cau").?,
83868417 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
83878418 } };
83888419}
......@@ -8391,7 +8422,6 @@ pub const WipNamespaceType = struct {
83918422 tid: Zcu.PerThread.Id,
83928423 index: Index,
83938424 type_name_extra_index: u32,
8394 cau_extra_index: ?u32,
83958425 namespace_extra_index: u32,
83968426
83978427 pub fn setName(
......@@ -8407,18 +8437,11 @@ pub const WipNamespaceType = struct {
84078437 pub fn finish(
84088438 wip: WipNamespaceType,
84098439 ip: *InternPool,
8410 analysis_owner: Cau.Index.Optional,
84118440 namespace: NamespaceIndex,
84128441 ) Index {
84138442 const extra = ip.getLocalShared(wip.tid).extra.acquire();
84148443 const extra_items = extra.view().items(.@"0");
84158444
8416 if (wip.cau_extra_index) |i| {
8417 extra_items[i] = @intFromEnum(analysis_owner.unwrap().?);
8418 } else {
8419 assert(analysis_owner == .none);
8420 }
8421
84228445 extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
84238446
84248447 return wip.index;
......@@ -8517,7 +8540,6 @@ pub fn getStructType(
85178540 ini.fields_len); // inits
85188541 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
85198542 .name = undefined, // set by `finish`
8520 .cau = undefined, // set by `finish`
85218543 .zir_index = zir_index,
85228544 .fields_len = ini.fields_len,
85238545 .namespace = undefined, // set by `finish`
......@@ -8562,7 +8584,6 @@ pub fn getStructType(
85628584 .tid = tid,
85638585 .index = gop.put(),
85648586 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8565 .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "cau").?,
85668587 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
85678588 } };
85688589 },
......@@ -8585,7 +8606,6 @@ pub fn getStructType(
85858606 1); // names_map
85868607 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
85878608 .name = undefined, // set by `finish`
8588 .cau = undefined, // set by `finish`
85898609 .zir_index = zir_index,
85908610 .namespace = undefined, // set by `finish`
85918611 .fields_len = ini.fields_len,
......@@ -8654,7 +8674,6 @@ pub fn getStructType(
86548674 .tid = tid,
86558675 .index = gop.put(),
86568676 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8657 .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "cau").?,
86588677 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
86598678 } };
86608679}
......@@ -8878,7 +8897,7 @@ pub fn getFuncDecl(
88788897
88798898 const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{
88808899 .analysis = .{
8881 .state = .unreferenced,
8900 .is_analyzed = false,
88828901 .branch_hint = .none,
88838902 .is_noinline = key.is_noinline,
88848903 .calls_or_awaits_errorable_fn = false,
......@@ -8987,7 +9006,7 @@ pub fn getFuncDeclIes(
89879006
89889007 const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{
89899008 .analysis = .{
8990 .state = .unreferenced,
9009 .is_analyzed = false,
89919010 .branch_hint = .none,
89929011 .is_noinline = key.is_noinline,
89939012 .calls_or_awaits_errorable_fn = false,
......@@ -9183,7 +9202,7 @@ pub fn getFuncInstance(
91839202
91849203 const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{
91859204 .analysis = .{
9186 .state = .unreferenced,
9205 .is_analyzed = false,
91879206 .branch_hint = .none,
91889207 .is_noinline = arg.is_noinline,
91899208 .calls_or_awaits_errorable_fn = false,
......@@ -9281,7 +9300,7 @@ pub fn getFuncInstanceIes(
92819300
92829301 const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{
92839302 .analysis = .{
9284 .state = .unreferenced,
9303 .is_analyzed = false,
92859304 .branch_hint = .none,
92869305 .is_noinline = arg.is_noinline,
92879306 .calls_or_awaits_errorable_fn = false,
......@@ -9390,7 +9409,7 @@ fn finishFuncInstance(
93909409 func_extra_index: u32,
93919410) Allocator.Error!void {
93929411 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);
9393 const fn_namespace = ip.getCau(fn_owner_nav.analysis_owner.unwrap().?).namespace;
9412 const fn_namespace = fn_owner_nav.analysis.?.namespace;
93949413
93959414 // TODO: improve this name
93969415 const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{}__anon_{d}", .{
......@@ -9400,9 +9419,9 @@ fn finishFuncInstance(
94009419 .name = nav_name,
94019420 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
94029421 .val = func_index,
9403 .alignment = fn_owner_nav.status.resolved.alignment,
9404 .@"linksection" = fn_owner_nav.status.resolved.@"linksection",
9405 .@"addrspace" = fn_owner_nav.status.resolved.@"addrspace",
9422 .alignment = fn_owner_nav.status.fully_resolved.alignment,
9423 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
9424 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
94069425 });
94079426
94089427 // Populate the owner_nav field which was left undefined until now.
......@@ -9436,7 +9455,6 @@ pub const WipEnumType = struct {
94369455 index: Index,
94379456 tag_ty_index: u32,
94389457 type_name_extra_index: u32,
9439 cau_extra_index: u32,
94409458 namespace_extra_index: u32,
94419459 names_map: MapIndex,
94429460 names_start: u32,
......@@ -9456,13 +9474,11 @@ pub const WipEnumType = struct {
94569474 pub fn prepare(
94579475 wip: WipEnumType,
94589476 ip: *InternPool,
9459 analysis_owner: Cau.Index,
94609477 namespace: NamespaceIndex,
94619478 ) void {
94629479 const extra = ip.getLocalShared(wip.tid).extra.acquire();
94639480 const extra_items = extra.view().items(.@"0");
94649481
9465 extra_items[wip.cau_extra_index] = @intFromEnum(analysis_owner);
94669482 extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
94679483 }
94689484
......@@ -9563,7 +9579,6 @@ pub fn getEnumType(
95639579 .reified => 2, // type_hash: PackedU64
95649580 } +
95659581 // zig fmt: on
9566 1 + // cau
95679582 ini.fields_len); // field types
95689583
95699584 const extra_index = addExtraAssumeCapacity(extra, EnumAuto{
......@@ -9584,8 +9599,6 @@ pub fn getEnumType(
95849599 .tag = .type_enum_auto,
95859600 .data = extra_index,
95869601 });
9587 const cau_extra_index = extra.view().len;
9588 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`
95899602 switch (ini.key) {
95909603 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
95919604 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
......@@ -9598,7 +9611,6 @@ pub fn getEnumType(
95989611 .index = gop.put(),
95999612 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
96009613 .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?,
9601 .cau_extra_index = @intCast(cau_extra_index),
96029614 .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?,
96039615 .names_map = names_map,
96049616 .names_start = @intCast(names_start),
......@@ -9623,7 +9635,6 @@ pub fn getEnumType(
96239635 .reified => 2, // type_hash: PackedU64
96249636 } +
96259637 // zig fmt: on
9626 1 + // cau
96279638 ini.fields_len + // field types
96289639 ini.fields_len * @intFromBool(ini.has_values)); // field values
96299640
......@@ -9650,8 +9661,6 @@ pub fn getEnumType(
96509661 },
96519662 .data = extra_index,
96529663 });
9653 const cau_extra_index = extra.view().len;
9654 extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish`
96559664 switch (ini.key) {
96569665 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
96579666 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
......@@ -9668,7 +9677,6 @@ pub fn getEnumType(
96689677 .index = gop.put(),
96699678 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
96709679 .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?,
9671 .cau_extra_index = @intCast(cau_extra_index),
96729680 .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?,
96739681 .names_map = names_map,
96749682 .names_start = @intCast(names_start),
......@@ -9865,7 +9873,6 @@ pub fn getOpaqueType(
98659873 .tid = tid,
98669874 .index = gop.put(),
98679875 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
9868 .cau_extra_index = null, // opaques do not undergo type resolution
98699876 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
98709877 },
98719878 };
......@@ -9981,7 +9988,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
99819988 inline for (@typeInfo(@TypeOf(item)).@"struct".fields) |field| {
99829989 extra.appendAssumeCapacity(.{switch (field.type) {
99839990 Index,
9984 Cau.Index,
99859991 Nav.Index,
99869992 NamespaceIndex,
99879993 OptionalNamespaceIndex,
......@@ -10044,7 +10050,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
1004410050 const extra_item = extra_items[extra_index];
1004510051 @field(result, field.name) = switch (field.type) {
1004610052 Index,
10047 Cau.Index,
1004810053 Nav.Index,
1004910054 NamespaceIndex,
1005010055 OptionalNamespaceIndex,
......@@ -11065,12 +11070,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator)
1106511070 try bw.flush();
1106611071}
1106711072
11068pub fn getCau(ip: *const InternPool, index: Cau.Index) Cau {
11069 const unwrapped = index.unwrap(ip);
11070 const caus = ip.getLocalShared(unwrapped.tid).caus.acquire();
11071 return caus.view().items(.@"0")[unwrapped.index];
11072}
11073
1107411073pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav {
1107511074 const unwrapped = index.unwrap(ip);
1107611075 const navs = ip.getLocalShared(unwrapped.tid).navs.acquire();
......@@ -11084,51 +11083,34 @@ pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Names
1108411083 return &namespaces_bucket[unwrapped_namespace_index.index];
1108511084}
1108611085
11087/// Create a `Cau` associated with the type at the given `InternPool.Index`.
11088pub fn createTypeCau(
11086/// Create a `ComptimeUnit`, forming an `AnalUnit` for a `comptime` declaration.
11087pub fn createComptimeUnit(
1108911088 ip: *InternPool,
1109011089 gpa: Allocator,
1109111090 tid: Zcu.PerThread.Id,
1109211091 zir_index: TrackedInst.Index,
1109311092 namespace: NamespaceIndex,
11094 owner_type: InternPool.Index,
11095) Allocator.Error!Cau.Index {
11096 const caus = ip.getLocal(tid).getMutableCaus(gpa);
11097 const index_unwrapped: Cau.Index.Unwrapped = .{
11093) Allocator.Error!ComptimeUnit.Id {
11094 const comptime_units = ip.getLocal(tid).getMutableComptimeUnits(gpa);
11095 const id_unwrapped: ComptimeUnit.Id.Unwrapped = .{
1109811096 .tid = tid,
11099 .index = caus.mutate.len,
11097 .index = comptime_units.mutate.len,
1110011098 };
11101 try caus.append(.{.{
11099 try comptime_units.append(.{.{
1110211100 .zir_index = zir_index,
1110311101 .namespace = namespace,
11104 .owner = Cau.Owner.wrap(.{ .type = owner_type }),
1110511102 }});
11106 return index_unwrapped.wrap(ip);
11103 return id_unwrapped.wrap(ip);
1110711104}
1110811105
11109/// Create a `Cau` for a `comptime` declaration.
11110pub fn createComptimeCau(
11111 ip: *InternPool,
11112 gpa: Allocator,
11113 tid: Zcu.PerThread.Id,
11114 zir_index: TrackedInst.Index,
11115 namespace: NamespaceIndex,
11116) Allocator.Error!Cau.Index {
11117 const caus = ip.getLocal(tid).getMutableCaus(gpa);
11118 const index_unwrapped: Cau.Index.Unwrapped = .{
11119 .tid = tid,
11120 .index = caus.mutate.len,
11121 };
11122 try caus.append(.{.{
11123 .zir_index = zir_index,
11124 .namespace = namespace,
11125 .owner = Cau.Owner.wrap(.none),
11126 }});
11127 return index_unwrapped.wrap(ip);
11106pub fn getComptimeUnit(ip: *const InternPool, id: ComptimeUnit.Id) ComptimeUnit {
11107 const unwrapped = id.unwrap(ip);
11108 const comptime_units = ip.getLocalShared(unwrapped.tid).comptime_units.acquire();
11109 return comptime_units.view().items(.@"0")[unwrapped.index];
1112811110}
1112911111
11130/// Create a `Nav` not associated with any `Cau`.
11131/// Since there is no analysis owner, the `Nav`'s value must be known at creation time.
11112/// Create a `Nav` which does not undergo semantic analysis.
11113/// Since it is never analyzed, the `Nav`'s value must be known at creation time.
1113211114pub fn createNav(
1113311115 ip: *InternPool,
1113411116 gpa: Allocator,
......@@ -11150,8 +11132,8 @@ pub fn createNav(
1115011132 try navs.append(Nav.pack(.{
1115111133 .name = opts.name,
1115211134 .fqn = opts.fqn,
11153 .analysis_owner = .none,
11154 .status = .{ .resolved = .{
11135 .analysis = null,
11136 .status = .{ .fully_resolved = .{
1115511137 .val = opts.val,
1115611138 .alignment = opts.alignment,
1115711139 .@"linksection" = opts.@"linksection",
......@@ -11162,10 +11144,9 @@ pub fn createNav(
1116211144 return index_unwrapped.wrap(ip);
1116311145}
1116411146
11165/// Create a `Cau` and `Nav` which are paired. The value of the `Nav` is
11166/// determined by semantic analysis of the `Cau`. The value of the `Nav`
11167/// is initially unresolved.
11168pub fn createPairedCauNav(
11147/// Create a `Nav` which undergoes semantic analysis because it corresponds to a source declaration.
11148/// The value of the `Nav` is initially unresolved.
11149pub fn createDeclNav(
1116911150 ip: *InternPool,
1117011151 gpa: Allocator,
1117111152 tid: Zcu.PerThread.Id,
......@@ -11175,36 +11156,72 @@ pub fn createPairedCauNav(
1117511156 namespace: NamespaceIndex,
1117611157 /// TODO: this is hacky! See `Nav.is_usingnamespace`.
1117711158 is_usingnamespace: bool,
11178) Allocator.Error!struct { Cau.Index, Nav.Index } {
11179 const caus = ip.getLocal(tid).getMutableCaus(gpa);
11159) Allocator.Error!Nav.Index {
1118011160 const navs = ip.getLocal(tid).getMutableNavs(gpa);
1118111161
11182 try caus.ensureUnusedCapacity(1);
1118311162 try navs.ensureUnusedCapacity(1);
1118411163
11185 const cau = Cau.Index.Unwrapped.wrap(.{
11186 .tid = tid,
11187 .index = caus.mutate.len,
11188 }, ip);
1118911164 const nav = Nav.Index.Unwrapped.wrap(.{
1119011165 .tid = tid,
1119111166 .index = navs.mutate.len,
1119211167 }, ip);
1119311168
11194 caus.appendAssumeCapacity(.{.{
11195 .zir_index = zir_index,
11196 .namespace = namespace,
11197 .owner = Cau.Owner.wrap(.{ .nav = nav }),
11198 }});
1119911169 navs.appendAssumeCapacity(Nav.pack(.{
1120011170 .name = name,
1120111171 .fqn = fqn,
11202 .analysis_owner = cau.toOptional(),
11172 .analysis = .{
11173 .namespace = namespace,
11174 .zir_index = zir_index,
11175 },
1120311176 .status = .unresolved,
1120411177 .is_usingnamespace = is_usingnamespace,
1120511178 }));
1120611179
11207 return .{ cau, nav };
11180 return nav;
11181}
11182
11183/// Resolve the type of a `Nav` with an analysis owner.
11184/// If its status is already `resolved`, the old value is discarded.
11185pub fn resolveNavType(
11186 ip: *InternPool,
11187 nav: Nav.Index,
11188 resolved: struct {
11189 type: InternPool.Index,
11190 alignment: Alignment,
11191 @"linksection": OptionalNullTerminatedString,
11192 @"addrspace": std.builtin.AddressSpace,
11193 is_const: bool,
11194 is_threadlocal: bool,
11195 is_extern_decl: bool,
11196 },
11197) void {
11198 const unwrapped = nav.unwrap(ip);
11199
11200 const local = ip.getLocal(unwrapped.tid);
11201 local.mutate.extra.mutex.lock();
11202 defer local.mutate.extra.mutex.unlock();
11203
11204 const navs = local.shared.navs.view();
11205
11206 const nav_analysis_namespace = navs.items(.analysis_namespace);
11207 const nav_analysis_zir_index = navs.items(.analysis_zir_index);
11208 const nav_types = navs.items(.type_or_val);
11209 const nav_linksections = navs.items(.@"linksection");
11210 const nav_bits = navs.items(.bits);
11211
11212 assert(nav_analysis_namespace[unwrapped.index] != .none);
11213 assert(nav_analysis_zir_index[unwrapped.index] != .none);
11214
11215 @atomicStore(InternPool.Index, &nav_types[unwrapped.index], resolved.type, .release);
11216 @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
11217
11218 var bits = nav_bits[unwrapped.index];
11219 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
11220 bits.alignment = resolved.alignment;
11221 bits.@"addrspace" = resolved.@"addrspace";
11222 bits.is_const = resolved.is_const;
11223 bits.is_threadlocal = resolved.is_threadlocal;
11224 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
1120811225}
1120911226
1121011227/// Resolve the value of a `Nav` with an analysis owner.
......@@ -11227,18 +11244,20 @@ pub fn resolveNavValue(
1122711244
1122811245 const navs = local.shared.navs.view();
1122911246
11230 const nav_analysis_owners = navs.items(.analysis_owner);
11231 const nav_vals = navs.items(.val);
11247 const nav_analysis_namespace = navs.items(.analysis_namespace);
11248 const nav_analysis_zir_index = navs.items(.analysis_zir_index);
11249 const nav_vals = navs.items(.type_or_val);
1123211250 const nav_linksections = navs.items(.@"linksection");
1123311251 const nav_bits = navs.items(.bits);
1123411252
11235 assert(nav_analysis_owners[unwrapped.index] != .none);
11253 assert(nav_analysis_namespace[unwrapped.index] != .none);
11254 assert(nav_analysis_zir_index[unwrapped.index] != .none);
1123611255
1123711256 @atomicStore(InternPool.Index, &nav_vals[unwrapped.index], resolved.val, .release);
1123811257 @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
1123911258
1124011259 var bits = nav_bits[unwrapped.index];
11241 bits.status = .resolved;
11260 bits.status = .fully_resolved;
1124211261 bits.alignment = resolved.alignment;
1124311262 bits.@"addrspace" = resolved.@"addrspace";
1124411263 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
src/Sema.zig+273-404
......@@ -1284,7 +1284,6 @@ fn analyzeBodyInner(
12841284 const extended = datas[@intFromEnum(inst)].extended;
12851285 break :ext switch (extended.opcode) {
12861286 // zig fmt: off
1287 .variable => try sema.zirVarExtended( block, extended),
12881287 .struct_decl => try sema.zirStructDecl( block, extended, inst),
12891288 .enum_decl => try sema.zirEnumDecl( block, extended, inst),
12901289 .union_decl => try sema.zirUnionDecl( block, extended, inst),
......@@ -2114,13 +2113,33 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
21142113}
21152114
21162115/// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value.
2117/// InternPool key `variable` is considered a runtime value.
21182116/// Generic poison causes `error.GenericPoison` to be returned.
21192117fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
2120 const val = (try sema.resolveValueAllowVariables(inst)) orelse return null;
2121 if (val.isGenericPoison()) return error.GenericPoison;
2122 if (sema.pt.zcu.intern_pool.isVariable(val.toIntern())) return null;
2123 return val;
2118 const zcu = sema.pt.zcu;
2119 assert(inst != .none);
2120
2121 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
2122 return opv;
2123 }
2124
2125 if (inst.toInterned()) |ip_index| {
2126 const val: Value = .fromInterned(ip_index);
2127
2128 assert(val.getVariable(zcu) == null);
2129 if (val.isPtrRuntimeValue(zcu)) return null;
2130 if (val.isGenericPoison()) return error.GenericPoison;
2131
2132 return val;
2133 } else {
2134 // Runtime-known value.
2135 const air_tags = sema.air_instructions.items(.tag);
2136 switch (air_tags[@intFromEnum(inst.toIndex().?)]) {
2137 .inferred_alloc => unreachable, // assertion failure
2138 .inferred_alloc_comptime => unreachable, // assertion failure
2139 else => {},
2140 }
2141 return null;
2142 }
21242143}
21252144
21262145/// Like `resolveValue`, but emits an error if the value is not comptime-known.
......@@ -2183,35 +2202,6 @@ fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
21832202 return try sema.resolveLazyValue(val);
21842203}
21852204
2186/// Returns all InternPool keys representing values, including `variable`, `undef`, and `generic_poison`.
2187fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
2188 const pt = sema.pt;
2189 assert(inst != .none);
2190 // First section of indexes correspond to a set number of constant values.
2191 if (@intFromEnum(inst) < InternPool.static_len) {
2192 return Value.fromInterned(@as(InternPool.Index, @enumFromInt(@intFromEnum(inst))));
2193 }
2194
2195 const air_tags = sema.air_instructions.items(.tag);
2196 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
2197 if (inst.toInterned()) |ip_index| {
2198 const val = Value.fromInterned(ip_index);
2199 if (val.getVariable(pt.zcu) != null) return val;
2200 }
2201 return opv;
2202 }
2203 const ip_index = inst.toInterned() orelse {
2204 switch (air_tags[@intFromEnum(inst.toIndex().?)]) {
2205 .inferred_alloc => unreachable,
2206 .inferred_alloc_comptime => unreachable,
2207 else => return null,
2208 }
2209 };
2210 const val = Value.fromInterned(ip_index);
2211 if (val.isPtrRuntimeValue(pt.zcu)) return null;
2212 return val;
2213}
2214
22152205/// Value Tag may be `undef` or `variable`.
22162206pub fn resolveFinalDeclValue(
22172207 sema: *Sema,
......@@ -2221,8 +2211,13 @@ pub fn resolveFinalDeclValue(
22212211) CompileError!Value {
22222212 const zcu = sema.pt.zcu;
22232213
2224 const val = try sema.resolveValueAllowVariables(air_ref) orelse {
2225 const value_comptime_reason: ?[]const u8 = if (air_ref.toInterned()) |_|
2214 const val = try sema.resolveValue(air_ref) orelse {
2215 const is_runtime_ptr = rt_ptr: {
2216 const ip_index = air_ref.toInterned() orelse break :rt_ptr false;
2217 const val: Value = .fromInterned(ip_index);
2218 break :rt_ptr val.isPtrRuntimeValue(zcu);
2219 };
2220 const value_comptime_reason: ?[]const u8 = if (is_runtime_ptr)
22262221 "thread local and dll imported variables have runtime-known addresses"
22272222 else
22282223 null;
......@@ -2232,10 +2227,8 @@ pub fn resolveFinalDeclValue(
22322227 .value_comptime_reason = value_comptime_reason,
22332228 });
22342229 };
2235 if (val.isGenericPoison()) return error.GenericPoison;
22362230
2237 const init_val: Value = if (val.getVariable(zcu)) |v| .fromInterned(v.init) else val;
2238 if (init_val.canMutateComptimeVarState(zcu)) {
2231 if (val.canMutateComptimeVarState(zcu)) {
22392232 return sema.fail(block, src, "global variable contains reference to comptime var", .{});
22402233 }
22412234
......@@ -2877,7 +2870,7 @@ fn zirStructDecl(
28772870 };
28782871 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) {
28792872 .existing => |ty| {
2880 const new_ty = try pt.ensureTypeUpToDate(ty, false);
2873 const new_ty = try pt.ensureTypeUpToDate(ty);
28812874
28822875 // Make sure we update the namespace if the declaration is re-analyzed, to pick
28832876 // up on e.g. changed comptime decls.
......@@ -2907,12 +2900,10 @@ fn zirStructDecl(
29072900 });
29082901 errdefer pt.destroyNamespace(new_namespace_index);
29092902
2910 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
2911
29122903 if (pt.zcu.comp.incremental) {
29132904 try ip.addDependency(
29142905 sema.gpa,
2915 AnalUnit.wrap(.{ .cau = new_cau_index }),
2906 AnalUnit.wrap(.{ .type = wip_ty.index }),
29162907 .{ .src_hash = tracked_inst },
29172908 );
29182909 }
......@@ -2929,7 +2920,7 @@ fn zirStructDecl(
29292920 }
29302921 try sema.declareDependency(.{ .interned = wip_ty.index });
29312922 try sema.addTypeReferenceEntry(src, wip_ty.index);
2932 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
2923 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
29332924}
29342925
29352926fn createTypeName(
......@@ -3107,7 +3098,7 @@ fn zirEnumDecl(
31073098 };
31083099 const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) {
31093100 .existing => |ty| {
3110 const new_ty = try pt.ensureTypeUpToDate(ty, false);
3101 const new_ty = try pt.ensureTypeUpToDate(ty);
31113102
31123103 // Make sure we update the namespace if the declaration is re-analyzed, to pick
31133104 // up on e.g. changed comptime decls.
......@@ -3143,16 +3134,14 @@ fn zirEnumDecl(
31433134 });
31443135 errdefer if (!done) pt.destroyNamespace(new_namespace_index);
31453136
3146 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
3147
31483137 try pt.scanNamespace(new_namespace_index, decls);
31493138
31503139 try sema.declareDependency(.{ .interned = wip_ty.index });
31513140 try sema.addTypeReferenceEntry(src, wip_ty.index);
31523141
31533142 // We've finished the initial construction of this type, and are about to perform analysis.
3154 // Set the Cau and namespace appropriately, and don't destroy anything on failure.
3155 wip_ty.prepare(ip, new_cau_index, new_namespace_index);
3143 // Set the namespace appropriately, and don't destroy anything on failure.
3144 wip_ty.prepare(ip, new_namespace_index);
31563145 done = true;
31573146
31583147 try Sema.resolveDeclaredEnum(
......@@ -3162,7 +3151,6 @@ fn zirEnumDecl(
31623151 tracked_inst,
31633152 new_namespace_index,
31643153 type_name,
3165 new_cau_index,
31663154 small,
31673155 body,
31683156 tag_type_ref,
......@@ -3252,7 +3240,7 @@ fn zirUnionDecl(
32523240 };
32533241 const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) {
32543242 .existing => |ty| {
3255 const new_ty = try pt.ensureTypeUpToDate(ty, false);
3243 const new_ty = try pt.ensureTypeUpToDate(ty);
32563244
32573245 // Make sure we update the namespace if the declaration is re-analyzed, to pick
32583246 // up on e.g. changed comptime decls.
......@@ -3282,12 +3270,10 @@ fn zirUnionDecl(
32823270 });
32833271 errdefer pt.destroyNamespace(new_namespace_index);
32843272
3285 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
3286
32873273 if (pt.zcu.comp.incremental) {
32883274 try zcu.intern_pool.addDependency(
32893275 gpa,
3290 AnalUnit.wrap(.{ .cau = new_cau_index }),
3276 AnalUnit.wrap(.{ .type = wip_ty.index }),
32913277 .{ .src_hash = tracked_inst },
32923278 );
32933279 }
......@@ -3304,7 +3290,7 @@ fn zirUnionDecl(
33043290 }
33053291 try sema.declareDependency(.{ .interned = wip_ty.index });
33063292 try sema.addTypeReferenceEntry(src, wip_ty.index);
3307 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
3293 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
33083294}
33093295
33103296fn zirOpaqueDecl(
......@@ -3389,7 +3375,7 @@ fn zirOpaqueDecl(
33893375 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
33903376 }
33913377 try sema.addTypeReferenceEntry(src, wip_ty.index);
3392 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));
3378 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
33933379}
33943380
33953381fn zirErrorSetDecl(
......@@ -6509,9 +6495,9 @@ pub fn analyzeExport(
65096495 if (options.linkage == .internal)
65106496 return;
65116497
6512 try sema.ensureNavResolved(src, orig_nav_index);
6498 try sema.ensureNavResolved(src, orig_nav_index, .fully);
65136499
6514 const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.resolved.val)) {
6500 const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
65156501 .variable => |v| v.owner_nav,
65166502 .@"extern" => |e| e.owner_nav,
65176503 .func => |f| f.owner_nav,
......@@ -6534,7 +6520,7 @@ pub fn analyzeExport(
65346520 }
65356521
65366522 // TODO: some backends might support re-exporting extern decls
6537 if (exported_nav.isExtern(ip)) {
6523 if (exported_nav.getExtern(ip) != null) {
65386524 return sema.fail(block, src, "export target cannot be extern", .{});
65396525 }
65406526
......@@ -6554,7 +6540,11 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
65546540 const ip = &zcu.intern_pool;
65556541 const func = switch (sema.owner.unwrap()) {
65566542 .func => |func| func,
6557 .cau => return, // does nothing outside a function
6543 .@"comptime",
6544 .nav_val,
6545 .nav_ty,
6546 .type,
6547 => return, // does nothing outside a function
65586548 };
65596549 ip.funcSetDisableInstrumentation(func);
65606550 sema.allow_memoize = false;
......@@ -6865,8 +6855,8 @@ fn lookupInNamespace(
68656855 }
68666856
68676857 for (usingnamespaces.items) |sub_ns_nav| {
6868 try sema.ensureNavResolved(src, sub_ns_nav);
6869 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.resolved.val);
6858 try sema.ensureNavResolved(src, sub_ns_nav, .fully);
6859 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
68706860 const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
68716861 try checked_namespaces.put(gpa, sub_ns, {});
68726862 }
......@@ -6875,11 +6865,8 @@ fn lookupInNamespace(
68756865
68766866 ignore_self: {
68776867 const skip_nav = switch (sema.owner.unwrap()) {
6878 .func => break :ignore_self,
6879 .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
6880 .none, .type => break :ignore_self,
6881 .nav => |nav| nav,
6882 },
6868 .@"comptime", .type, .func => break :ignore_self,
6869 .nav_ty, .nav_val => |nav| nav,
68836870 };
68846871 var i: usize = 0;
68856872 while (i < candidates.items.len) {
......@@ -7139,7 +7126,7 @@ fn zirCall(
71397126 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
71407127
71417128 switch (sema.owner.unwrap()) {
7142 .cau => input_is_error = false,
7129 .@"comptime", .type, .nav_ty, .nav_val => input_is_error = false,
71437130 .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) {
71447131 // No errorable fn actually called; we have no error return trace
71457132 input_is_error = false;
......@@ -7700,12 +7687,13 @@ fn analyzeCall(
77007687 .ptr => |ptr| blk: {
77017688 switch (ptr.base_addr) {
77027689 .nav => |nav_index| if (ptr.byte_offset == 0) {
7690 try sema.ensureNavResolved(call_src, nav_index, .fully);
77037691 const nav = ip.getNav(nav_index);
7704 if (nav.isExtern(ip))
7692 if (nav.getExtern(ip) != null)
77057693 return sema.fail(block, call_src, "{s} call of extern function pointer", .{
77067694 if (is_comptime_call) "comptime" else "inline",
77077695 });
7708 break :blk nav.status.resolved.val;
7696 break :blk nav.status.fully_resolved.val;
77097697 },
77107698 else => {},
77117699 }
......@@ -7754,11 +7742,9 @@ fn analyzeCall(
77547742 // The call site definitely depends on the function's signature.
77557743 try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst });
77567744
7757 // This is not a function instance, so the function's `Nav` has a
7758 // `Cau` -- we don't need to check `generic_owner`.
7745 // This is not a function instance, so the function's `Nav` has analysis
7746 // state -- we don't need to check `generic_owner`.
77597747 const fn_nav = ip.getNav(module_fn.owner_nav);
7760 const fn_cau_index = fn_nav.analysis_owner.unwrap().?;
7761 const fn_cau = ip.getCau(fn_cau_index);
77627748
77637749 // We effectively want a child Sema here, but can't literally do that, because we need AIR
77647750 // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in
......@@ -7766,7 +7752,7 @@ fn analyzeCall(
77667752 // whenever performing an operation where the difference matters.
77677753 var ics = InlineCallSema.init(
77687754 sema,
7769 zcu.cauFileScope(fn_cau_index).zir,
7755 zcu.navFileScope(module_fn.owner_nav).zir,
77707756 module_fn_index,
77717757 block.error_return_trace_index,
77727758 );
......@@ -7776,7 +7762,7 @@ fn analyzeCall(
77767762 .parent = null,
77777763 .sema = sema,
77787764 // The function body exists in the same namespace as the corresponding function declaration.
7779 .namespace = fn_cau.namespace,
7765 .namespace = fn_nav.analysis.?.namespace,
77807766 .instructions = .{},
77817767 .label = null,
77827768 .inlining = &inlining,
......@@ -7787,7 +7773,7 @@ fn analyzeCall(
77877773 .runtime_cond = block.runtime_cond,
77887774 .runtime_loop = block.runtime_loop,
77897775 .runtime_index = block.runtime_index,
7790 .src_base_inst = fn_cau.zir_index,
7776 .src_base_inst = fn_nav.analysis.?.zir_index,
77917777 .type_name_ctx = fn_nav.fqn,
77927778 };
77937779
......@@ -7802,7 +7788,7 @@ fn analyzeCall(
78027788 // mutate comptime state.
78037789 // TODO: comptime call memoization is currently not supported under incremental compilation
78047790 // since dependencies are not marked on callers. If we want to keep this around (we should
7805 // check that it's worthwhile first!), each memoized call needs a `Cau`.
7791 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`.
78067792 var should_memoize = !zcu.comp.incremental;
78077793
78087794 // If it's a comptime function call, we need to memoize it as long as no external
......@@ -7911,7 +7897,7 @@ fn analyzeCall(
79117897
79127898 // Since we're doing an inline call, we depend on the source code of the whole
79137899 // function declaration.
7914 try sema.declareDependency(.{ .src_hash = fn_cau.zir_index });
7900 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });
79157901
79167902 new_fn_info.return_type = sema.fn_ret_ty.toIntern();
79177903 if (!is_comptime_call and !block.is_typeof) {
......@@ -8023,7 +8009,7 @@ fn analyzeCall(
80238009 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
80248010
80258011 switch (sema.owner.unwrap()) {
8026 .cau => {},
8012 .@"comptime", .nav_ty, .nav_val, .type => {},
80278013 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
80288014 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
80298015 },
......@@ -8062,7 +8048,10 @@ fn analyzeCall(
80628048 switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {
80638049 .func => break :skip_safety,
80648050 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
8065 .nav => |nav| if (!ip.getNav(nav).isExtern(ip)) break :skip_safety,
8051 .nav => |nav| {
8052 try sema.ensureNavResolved(call_src, nav, .fully);
8053 if (ip.getNav(nav).getExtern(ip) == null) break :skip_safety;
8054 },
80668055 else => {},
80678056 },
80688057 else => {},
......@@ -8259,7 +8248,7 @@ fn instantiateGenericCall(
82598248 });
82608249 const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {
82618250 .func => func_val.toIntern(),
8262 .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.resolved.val,
8251 .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.fully_resolved.val,
82638252 else => unreachable,
82648253 };
82658254 const generic_owner_func = zcu.intern_pool.indexToKey(generic_owner).func;
......@@ -8275,10 +8264,9 @@ fn instantiateGenericCall(
82758264 // The actual monomorphization happens via adding `func_instance` to
82768265 // `InternPool`.
82778266
8278 // Since we are looking at the generic owner here, it has a `Cau`.
8267 // Since we are looking at the generic owner here, it has analysis state.
82798268 const fn_nav = ip.getNav(generic_owner_func.owner_nav);
8280 const fn_cau = ip.getCau(fn_nav.analysis_owner.unwrap().?);
8281 const fn_zir = zcu.namespacePtr(fn_cau.namespace).fileScope(zcu).zir;
8269 const fn_zir = zcu.navFileScope(generic_owner_func.owner_nav).zir;
82828270 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);
82838271
82848272 const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
......@@ -8319,11 +8307,11 @@ fn instantiateGenericCall(
83198307 var child_block: Block = .{
83208308 .parent = null,
83218309 .sema = &child_sema,
8322 .namespace = fn_cau.namespace,
8310 .namespace = fn_nav.analysis.?.namespace,
83238311 .instructions = .{},
83248312 .inlining = null,
83258313 .is_comptime = true,
8326 .src_base_inst = fn_cau.zir_index,
8314 .src_base_inst = fn_nav.analysis.?.zir_index,
83278315 .type_name_ctx = fn_nav.fqn,
83288316 };
83298317 defer child_block.instructions.deinit(gpa);
......@@ -8488,7 +8476,7 @@ fn instantiateGenericCall(
84888476 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
84898477
84908478 switch (sema.owner.unwrap()) {
8491 .cau => {},
8479 .@"comptime", .nav_ty, .nav_val, .type => {},
84928480 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
84938481 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
84948482 },
......@@ -9517,16 +9505,13 @@ fn zirFunc(
95179505 // the callconv based on whether it is exported. Otherwise, the callconv defaults
95189506 // to `.auto`.
95199507 const cc: std.builtin.CallingConvention = if (has_body) cc: {
9520 const func_decl_cau = if (sema.generic_owner != .none) cau: {
9521 const generic_owner_fn = zcu.funcInfo(sema.generic_owner);
9522 // The generic owner definitely has a `Cau` for the corresponding function declaration.
9523 const generic_owner_nav = ip.getNav(generic_owner_fn.owner_nav);
9524 break :cau generic_owner_nav.analysis_owner.unwrap().?;
9525 } else sema.owner.unwrap().cau;
9508 const func_decl_nav = if (sema.generic_owner != .none) nav: {
9509 break :nav zcu.funcInfo(sema.generic_owner).owner_nav;
9510 } else sema.owner.unwrap().nav_val;
95269511 const fn_is_exported = exported: {
9527 const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip) orelse return error.AnalysisFail;
9528 const zir_decl = sema.code.getDeclaration(decl_inst)[0];
9529 break :exported zir_decl.flags.is_export;
9512 const decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(ip) orelse return error.AnalysisFail;
9513 const zir_decl = sema.code.getDeclaration(decl_inst);
9514 break :exported zir_decl.linkage == .@"export";
95309515 };
95319516 if (fn_is_exported) {
95329517 break :cc target.cCallingConvention() orelse {
......@@ -9557,10 +9542,8 @@ fn zirFunc(
95579542 ret_ty,
95589543 false,
95599544 inferred_error_set,
9560 false,
95619545 has_body,
95629546 src_locs,
9563 null,
95649547 0,
95659548 false,
95669549 );
......@@ -9619,7 +9602,7 @@ fn resolveGenericBody(
96199602/// respective `Decl` (either `ExternFn` or `Var`).
96209603/// The liveness of the duped library name is tied to liveness of `Zcu`.
96219604/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
9622fn handleExternLibName(
9605pub fn handleExternLibName(
96239606 sema: *Sema,
96249607 block: *Block,
96259608 src_loc: LazySrcLoc,
......@@ -9843,10 +9826,8 @@ fn funcCommon(
98439826 bare_return_type: Type,
98449827 var_args: bool,
98459828 inferred_error_set: bool,
9846 is_extern: bool,
98479829 has_body: bool,
98489830 src_locs: Zir.Inst.Func.SrcLocs,
9849 opt_lib_name: ?[]const u8,
98509831 noalias_bits: u32,
98519832 is_noinline: bool,
98529833) CompileError!Air.Inst.Ref {
......@@ -9998,12 +9979,11 @@ fn funcCommon(
99989979 }
99999980
100009981 if (inferred_error_set) {
10001 assert(!is_extern);
100029982 assert(has_body);
100039983 if (!ret_poison)
100049984 try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
100059985 const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{
10006 .owner_nav = sema.getOwnerCauNav(),
9986 .owner_nav = sema.owner.unwrap().nav_val,
100079987
100089988 .param_types = param_types,
100099989 .noalias_bits = noalias_bits,
......@@ -10050,35 +10030,9 @@ fn funcCommon(
1005010030 .is_noinline = is_noinline,
1005110031 });
1005210032
10053 if (is_extern) {
10054 assert(comptime_bits == 0);
10055 assert(!is_generic);
10056 if (opt_lib_name) |lib_name| try sema.handleExternLibName(block, block.src(.{
10057 .node_offset_lib_name = src_node_offset,
10058 }), lib_name);
10059 const extern_func_index = try sema.resolveExternDecl(block, .fromInterned(func_ty), opt_lib_name, true, false);
10060 return finishFunc(
10061 sema,
10062 block,
10063 extern_func_index,
10064 func_ty,
10065 ret_poison,
10066 bare_return_type,
10067 ret_ty_src,
10068 cc,
10069 is_source_decl,
10070 ret_ty_requires_comptime,
10071 func_inst,
10072 cc_src,
10073 is_noinline,
10074 is_generic,
10075 final_is_generic,
10076 );
10077 }
10078
1007910033 if (has_body) {
1008010034 const func_index = try ip.getFuncDecl(gpa, pt.tid, .{
10081 .owner_nav = sema.getOwnerCauNav(),
10035 .owner_nav = sema.owner.unwrap().nav_val,
1008210036 .ty = func_ty,
1008310037 .cc = cc,
1008410038 .is_noinline = is_noinline,
......@@ -17702,7 +17656,7 @@ fn zirAsm(
1770217656 if (is_volatile) {
1770317657 return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{});
1770417658 }
17705 try zcu.addGlobalAssembly(sema.owner.unwrap().cau, asm_source);
17659 try zcu.addGlobalAssembly(sema.owner, asm_source);
1770617660 return .void_value;
1770717661 }
1770817662
......@@ -18193,7 +18147,7 @@ fn zirThis(
1819318147 _ = extended;
1819418148 const pt = sema.pt;
1819518149 const namespace = pt.zcu.namespacePtr(block.namespace);
18196 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type, false);
18150 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
1819718151 switch (pt.zcu.intern_pool.indexToKey(new_ty)) {
1819818152 .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }),
1819918153 .opaque_type => {},
......@@ -19359,13 +19313,11 @@ fn typeInfoNamespaceDecls(
1935919313 }
1936019314
1936119315 for (namespace.pub_usingnamespace.items) |nav| {
19362 if (ip.getNav(nav).analysis_owner.unwrap()) |cau| {
19363 if (zcu.analysis_in_progress.contains(AnalUnit.wrap(.{ .cau = cau }))) {
19364 continue;
19365 }
19316 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
19317 continue;
1936619318 }
19367 try sema.ensureNavResolved(src, nav);
19368 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.resolved.val);
19319 try sema.ensureNavResolved(src, nav, .fully);
19320 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val);
1936919321 try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);
1937019322 }
1937119323}
......@@ -21225,14 +21177,13 @@ fn structInitAnon(
2122521177 .file_scope = block.getFileScopeIndex(zcu),
2122621178 .generation = zcu.generation,
2122721179 });
21228 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip.index);
2122921180 try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });
2123021181 codegen_type: {
2123121182 if (zcu.comp.config.use_llvm) break :codegen_type;
2123221183 if (block.ownerModule().strip) break :codegen_type;
2123321184 try zcu.comp.queueJob(.{ .codegen_type = wip.index });
2123421185 }
21235 break :ty wip.finish(ip, new_cau_index.toOptional(), new_namespace_index);
21186 break :ty wip.finish(ip, new_namespace_index);
2123621187 },
2123721188 .existing => |ty| ty,
2123821189 };
......@@ -21656,7 +21607,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
2165621607 .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) {
2165721608 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
2165821609 },
21659 .cau => {},
21610 .@"comptime", .nav_ty, .nav_val, .type => {},
2166021611 }
2166121612 return Air.internedToRef(try pt.intern(.{ .opt = .{
2166221613 .ty = opt_ptr_stack_trace_ty.toIntern(),
......@@ -22334,7 +22285,7 @@ fn zirReify(
2233422285 });
2233522286
2233622287 try sema.addTypeReferenceEntry(src, wip_ty.index);
22337 return Air.internedToRef(wip_ty.finish(ip, .none, new_namespace_index));
22288 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
2233822289 },
2233922290 .@"union" => {
2234022291 const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
......@@ -22543,11 +22494,9 @@ fn reifyEnum(
2254322494 .generation = zcu.generation,
2254422495 });
2254522496
22546 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
22547
2254822497 try sema.declareDependency(.{ .interned = wip_ty.index });
2254922498 try sema.addTypeReferenceEntry(src, wip_ty.index);
22550 wip_ty.prepare(ip, new_cau_index, new_namespace_index);
22499 wip_ty.prepare(ip, new_namespace_index);
2255122500 wip_ty.setTagTy(ip, tag_ty.toIntern());
2255222501 done = true;
2255322502
......@@ -22849,8 +22798,6 @@ fn reifyUnion(
2284922798 .generation = zcu.generation,
2285022799 });
2285122800
22852 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
22853
2285422801 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
2285522802 codegen_type: {
2285622803 if (zcu.comp.config.use_llvm) break :codegen_type;
......@@ -22860,7 +22807,7 @@ fn reifyUnion(
2286022807 }
2286122808 try sema.declareDependency(.{ .interned = wip_ty.index });
2286222809 try sema.addTypeReferenceEntry(src, wip_ty.index);
22863 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
22810 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
2286422811}
2286522812
2286622813fn reifyTuple(
......@@ -23208,8 +23155,6 @@ fn reifyStruct(
2320823155 .generation = zcu.generation,
2320923156 });
2321023157
23211 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index);
23212
2321323158 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
2321423159 codegen_type: {
2321523160 if (zcu.comp.config.use_llvm) break :codegen_type;
......@@ -23219,7 +23164,7 @@ fn reifyStruct(
2321923164 }
2322023165 try sema.declareDependency(.{ .interned = wip_ty.index });
2322123166 try sema.addTypeReferenceEntry(src, wip_ty.index);
23222 return Air.internedToRef(wip_ty.finish(ip, new_cau_index.toOptional(), new_namespace_index));
23167 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
2322323168}
2322423169
2322523170fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
......@@ -26711,135 +26656,6 @@ fn zirAwaitNosuspend(
2671126656 return sema.failWithUseOfAsync(block, src);
2671226657}
2671326658
26714fn zirVarExtended(
26715 sema: *Sema,
26716 block: *Block,
26717 extended: Zir.Inst.Extended.InstData,
26718) CompileError!Air.Inst.Ref {
26719 const pt = sema.pt;
26720 const zcu = pt.zcu;
26721 const ip = &zcu.intern_pool;
26722 const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
26723 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
26724 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
26725 const small: Zir.Inst.ExtendedVar.Small = @bitCast(extended.small);
26726
26727 var extra_index: usize = extra.end;
26728
26729 const lib_name = if (small.has_lib_name) lib_name: {
26730 const lib_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
26731 const lib_name = sema.code.nullTerminatedString(lib_name_index);
26732 extra_index += 1;
26733 try sema.handleExternLibName(block, ty_src, lib_name);
26734 break :lib_name lib_name;
26735 } else null;
26736
26737 // ZIR supports encoding this information but it is not used; the information
26738 // is encoded via the Decl entry.
26739 assert(!small.has_align);
26740
26741 const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: {
26742 const init_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
26743 extra_index += 1;
26744 break :blk try sema.resolveInst(init_ref);
26745 } else .none;
26746
26747 const have_ty = extra.data.var_type != .none;
26748 const var_ty = if (have_ty)
26749 try sema.resolveType(block, ty_src, extra.data.var_type)
26750 else
26751 sema.typeOf(uncasted_init);
26752
26753 const init_val = if (uncasted_init != .none) blk: {
26754 const init = if (have_ty)
26755 try sema.coerce(block, var_ty, uncasted_init, init_src)
26756 else
26757 uncasted_init;
26758
26759 break :blk ((try sema.resolveValue(init)) orelse {
26760 return sema.failWithNeededComptime(block, init_src, .{
26761 .needed_comptime_reason = "container level variable initializers must be comptime-known",
26762 });
26763 }).toIntern();
26764 } else .none;
26765
26766 try sema.validateVarType(block, ty_src, var_ty, small.is_extern);
26767
26768 if (small.is_extern) {
26769 const extern_val = try sema.resolveExternDecl(block, var_ty, lib_name, small.is_const, small.is_threadlocal);
26770 return Air.internedToRef(extern_val);
26771 }
26772 assert(!small.is_const); // non-const non-extern variable is not legal
26773 return Air.internedToRef(try pt.intern(.{ .variable = .{
26774 .ty = var_ty.toIntern(),
26775 .init = init_val,
26776 .owner_nav = sema.getOwnerCauNav(),
26777 .lib_name = try ip.getOrPutStringOpt(sema.gpa, pt.tid, lib_name, .no_embedded_nulls),
26778 .is_threadlocal = small.is_threadlocal,
26779 .is_weak_linkage = false,
26780 } }));
26781}
26782
26783fn resolveExternDecl(
26784 sema: *Sema,
26785 block: *Block,
26786 ty: Type,
26787 opt_lib_name: ?[]const u8,
26788 is_const: bool,
26789 is_threadlocal: bool,
26790) CompileError!InternPool.Index {
26791 const pt = sema.pt;
26792 const zcu = pt.zcu;
26793 const ip = &zcu.intern_pool;
26794
26795 // We need to resolve the alignment and addrspace early.
26796 // Keep in sync with logic in `Zcu.PerThread.semaCau`.
26797 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
26798 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
26799
26800 const decl_inst, const decl_bodies = decl: {
26801 const decl_inst = sema.getOwnerCauDeclInst().resolve(ip) orelse return error.AnalysisFail;
26802 const zir_decl, const extra_end = sema.code.getDeclaration(decl_inst);
26803 break :decl .{ decl_inst, zir_decl.getBodies(extra_end, sema.code) };
26804 };
26805
26806 const alignment: InternPool.Alignment = a: {
26807 const align_body = decl_bodies.align_body orelse break :a .none;
26808 const align_ref = try sema.resolveInlineBody(block, align_body, decl_inst);
26809 break :a try sema.analyzeAsAlign(block, align_src, align_ref);
26810 };
26811
26812 const @"addrspace": std.builtin.AddressSpace = as: {
26813 const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(ty.toIntern())) {
26814 .func_type => .function,
26815 else => .variable,
26816 };
26817 const target = zcu.getTarget();
26818 const addrspace_body = decl_bodies.addrspace_body orelse break :as switch (addrspace_ctx) {
26819 .function => target_util.defaultAddressSpace(target, .function),
26820 .variable => target_util.defaultAddressSpace(target, .global_mutable),
26821 .constant => target_util.defaultAddressSpace(target, .global_constant),
26822 else => unreachable,
26823 };
26824 const addrspace_ref = try sema.resolveInlineBody(block, addrspace_body, decl_inst);
26825 break :as try sema.analyzeAsAddressSpace(block, addrspace_src, addrspace_ref, addrspace_ctx);
26826 };
26827
26828 return pt.getExtern(.{
26829 .name = sema.getOwnerCauNavName(),
26830 .ty = ty.toIntern(),
26831 .lib_name = try ip.getOrPutStringOpt(sema.gpa, pt.tid, opt_lib_name, .no_embedded_nulls),
26832 .is_const = is_const,
26833 .is_threadlocal = is_threadlocal,
26834 .is_weak_linkage = false,
26835 .is_dll_import = false,
26836 .alignment = alignment,
26837 .@"addrspace" = @"addrspace",
26838 .zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction
26839 .owner_nav = undefined, // ignored by `getExtern`
26840 });
26841}
26842
2684326659fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
2684426660 const tracy = trace(@src());
2684526661 defer tracy.end();
......@@ -26857,13 +26673,6 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2685726673
2685826674 var extra_index: usize = extra.end;
2685926675
26860 const lib_name: ?[]const u8 = if (extra.data.bits.has_lib_name) blk: {
26861 const lib_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
26862 const lib_name = sema.code.nullTerminatedString(lib_name_index);
26863 extra_index += 1;
26864 break :blk lib_name;
26865 } else null;
26866
2686726676 const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
2686826677 const body_len = sema.code.extra[extra_index];
2686926678 extra_index += 1;
......@@ -26887,16 +26696,14 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2688726696 break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val);
2688826697 } else cc: {
2688926698 if (has_body) {
26890 const decl_inst = if (sema.generic_owner != .none) decl_inst: {
26699 const func_decl_nav = if (sema.generic_owner != .none) nav: {
2689126700 // Generic instance -- use the original function declaration to
2689226701 // look for the `export` syntax.
26893 const nav = zcu.intern_pool.getNav(zcu.funcInfo(sema.generic_owner).owner_nav);
26894 const cau = zcu.intern_pool.getCau(nav.analysis_owner.unwrap().?);
26895 break :decl_inst cau.zir_index;
26896 } else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau
26897
26898 const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&zcu.intern_pool) orelse return error.AnalysisFail)[0];
26899 if (zir_decl.flags.is_export) {
26702 break :nav zcu.funcInfo(sema.generic_owner).owner_nav;
26703 } else sema.owner.unwrap().nav_val;
26704 const func_decl_inst = ip.getNav(func_decl_nav).analysis.?.zir_index.resolve(&zcu.intern_pool) orelse return error.AnalysisFail;
26705 const zir_decl = sema.code.getDeclaration(func_decl_inst);
26706 if (zir_decl.linkage == .@"export") {
2690026707 break :cc target.cCallingConvention() orelse {
2690126708 // This target has no default C calling convention. We sometimes trigger a similar
2690226709 // error by trying to evaluate `std.builtin.CallingConvention.c`, so for consistency,
......@@ -26958,7 +26765,6 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2695826765
2695926766 const is_var_args = extra.data.bits.is_var_args;
2696026767 const is_inferred_error = extra.data.bits.is_inferred_error;
26961 const is_extern = extra.data.bits.is_extern;
2696226768 const is_noinline = extra.data.bits.is_noinline;
2696326769
2696426770 return sema.funcCommon(
......@@ -26969,10 +26775,8 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2696926775 ret_ty,
2697026776 is_var_args,
2697126777 is_inferred_error,
26972 is_extern,
2697326778 has_body,
2697426779 src_locs,
26975 lib_name,
2697626780 noalias_bits,
2697726781 is_noinline,
2697826782 );
......@@ -27285,8 +27089,16 @@ fn zirBuiltinExtern(
2728527089 // `builtin_extern` doesn't provide enough information, and isn't currently tracked.
2728627090 // So, for now, just use our containing `declaration`.
2728727091 .zir_index = switch (sema.owner.unwrap()) {
27288 .cau => sema.getOwnerCauDeclInst(),
27289 .func => sema.getOwnerFuncDeclInst(),
27092 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
27093 .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,
27094 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
27095 .func => |func| zir_index: {
27096 const func_info = zcu.funcInfo(func);
27097 const owner_func_info = if (func_info.generic_owner != .none) owner: {
27098 break :owner zcu.funcInfo(func_info.generic_owner);
27099 } else func_info;
27100 break :zir_index ip.getNav(owner_func_info.owner_nav).analysis.?.zir_index;
27101 },
2729027102 },
2729127103 .owner_nav = undefined, // ignored by `getExtern`
2729227104 });
......@@ -27467,7 +27279,7 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
2746727279}
2746827280
2746927281/// Emit a compile error if type cannot be used for a runtime variable.
27470fn validateVarType(
27282pub fn validateVarType(
2747127283 sema: *Sema,
2747227284 block: *Block,
2747327285 src: LazySrcLoc,
......@@ -27934,7 +27746,7 @@ fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.Pan
2793427746 error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
2793527747 error.OutOfMemory => |e| return e,
2793627748 }).?;
27937 try sema.ensureNavResolved(src, msg_nav_index);
27749 try sema.ensureNavResolved(src, msg_nav_index, .fully);
2793827750 zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional();
2793927751 return msg_nav_index;
2794027752}
......@@ -29881,7 +29693,7 @@ fn elemPtrSlice(
2988129693 return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
2988229694}
2988329695
29884fn coerce(
29696pub fn coerce(
2988529697 sema: *Sema,
2988629698 block: *Block,
2988729699 dest_ty_unresolved: Type,
......@@ -32841,34 +32653,45 @@ fn addTypeReferenceEntry(
3284132653 try zcu.addTypeReference(sema.owner, referenced_type, src);
3284232654}
3284332655
32844pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!void {
32656pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
3284532657 const pt = sema.pt;
3284632658 const zcu = pt.zcu;
3284732659 const ip = &zcu.intern_pool;
3284832660
3284932661 const nav = ip.getNav(nav_index);
32850
32851 const cau_index = nav.analysis_owner.unwrap() orelse {
32852 assert(nav.status == .resolved);
32662 if (nav.analysis == null) {
32663 assert(nav.status == .fully_resolved);
3285332664 return;
32854 };
32665 }
3285532666
32856 // Note that even if `nav.status == .resolved`, we must still trigger `ensureCauAnalyzed`
32857 // to make sure the value is up-to-date on incremental updates.
32667 try sema.declareDependency(switch (kind) {
32668 .type => .{ .nav_ty = nav_index },
32669 .fully => .{ .nav_val = nav_index },
32670 });
3285832671
32859 assert(ip.getCau(cau_index).owner.unwrap().nav == nav_index);
32672 // Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`
32673 // to make sure the value is up-to-date on incremental updates.
3286032674
32861 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
32675 const anal_unit: AnalUnit = .wrap(switch (kind) {
32676 .type => .{ .nav_ty = nav_index },
32677 .fully => .{ .nav_val = nav_index },
32678 });
3286232679 try sema.addReferenceEntry(src, anal_unit);
3286332680
3286432681 if (zcu.analysis_in_progress.contains(anal_unit)) {
3286532682 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{
32866 .base_node_inst = ip.getCau(cau_index).zir_index,
32683 .base_node_inst = nav.analysis.?.zir_index,
3286732684 .offset = LazySrcLoc.Offset.nodeOffset(0),
3286832685 }, "dependency loop detected", .{}));
3286932686 }
3287032687
32871 return pt.ensureCauAnalyzed(cau_index);
32688 switch (kind) {
32689 .type => {
32690 try zcu.ensureNavValAnalysisQueued(nav_index);
32691 return pt.ensureNavTypeUpToDate(nav_index);
32692 },
32693 .fully => return pt.ensureNavValUpToDate(nav_index),
32694 }
3287232695}
3287332696
3287432697fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
......@@ -32887,36 +32710,44 @@ fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index)
3288732710 return sema.analyzeNavRefInner(src, nav_index, true);
3288832711}
3288932712
32890/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed, but
32891/// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a
32892/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeNavRef` wraps
32893/// this function with `analyze_fn_body` set to true.
32894fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
32713/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.
32714/// If this pointer will be used directly, `is_ref` must be `true`.
32715/// If this pointer will be immediately loaded (i.e. a `decl_val` instruction), `is_ref` must be `false`.
32716fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref {
3289532717 const pt = sema.pt;
3289632718 const zcu = pt.zcu;
3289732719 const ip = &zcu.intern_pool;
3289832720
32899 // TODO: if this is a `decl_ref` of a non-variable Nav, only depend on Nav type
32900 try sema.declareDependency(.{ .nav_val = orig_nav_index });
32901 try sema.ensureNavResolved(src, orig_nav_index);
32721 try sema.ensureNavResolved(src, orig_nav_index, if (is_ref) .type else .fully);
32722
32723 const nav_index = nav: {
32724 if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
32725 // Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
32726 // We need to resolve the value to know for sure.
32727 if (is_ref) try sema.ensureNavResolved(src, orig_nav_index, .fully);
32728 switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
32729 .func => |f| break :nav f.owner_nav,
32730 .@"extern" => |e| break :nav e.owner_nav,
32731 else => {},
32732 }
32733 }
32734 break :nav orig_nav_index;
32735 };
3290232736
32903 const nav_val = zcu.navValue(orig_nav_index);
32904 const nav_index, const is_const = switch (ip.indexToKey(nav_val.toIntern())) {
32905 .variable => |v| .{ v.owner_nav, false },
32906 .func => |f| .{ f.owner_nav, true },
32907 .@"extern" => |e| .{ e.owner_nav, e.is_const },
32908 else => .{ orig_nav_index, true },
32737 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_index).status) {
32738 .unresolved => unreachable,
32739 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
32740 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
3290932741 };
32910 const nav_info = ip.getNav(nav_index).status.resolved;
3291132742 const ptr_ty = try pt.ptrTypeSema(.{
32912 .child = nav_val.typeOf(zcu).toIntern(),
32743 .child = ty,
3291332744 .flags = .{
32914 .alignment = nav_info.alignment,
32745 .alignment = alignment,
3291532746 .is_const = is_const,
32916 .address_space = nav_info.@"addrspace",
32747 .address_space = @"addrspace",
3291732748 },
3291832749 });
32919 if (analyze_fn_body) {
32750 if (is_ref) {
3292032751 try sema.maybeQueueFuncBodyAnalysis(src, nav_index);
3292132752 }
3292232753 return Air.internedToRef((try pt.intern(.{ .ptr = .{
......@@ -32927,11 +32758,22 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
3292732758}
3292832759
3292932760fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {
32930 const zcu = sema.pt.zcu;
32761 const pt = sema.pt;
32762 const zcu = pt.zcu;
3293132763 const ip = &zcu.intern_pool;
32764
32765 // To avoid forcing too much resolution, let's first resolve the type, and check if it's a function.
32766 // If it is, we can resolve the *value*, and queue analysis as needed.
32767
32768 try sema.ensureNavResolved(src, nav_index, .type);
32769 const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
32770 if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
32771 if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return;
32772
32773 try sema.ensureNavResolved(src, nav_index, .fully);
3293232774 const nav_val = zcu.navValue(nav_index);
3293332775 if (!ip.isFuncBody(nav_val.toIntern())) return;
32934 if (!try nav_val.typeOf(zcu).fnHasRuntimeBitsSema(sema.pt)) return;
32776
3293532777 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));
3293632778 try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
3293732779}
......@@ -35818,7 +35660,7 @@ pub fn resolveStructAlignment(
3581835660 const ip = &zcu.intern_pool;
3581935661 const target = zcu.getTarget();
3582035662
35821 assert(sema.owner.unwrap().cau == struct_type.cau);
35663 assert(sema.owner.unwrap().type == ty);
3582235664
3582335665 assert(struct_type.layout != .@"packed");
3582435666 assert(struct_type.flagsUnordered(ip).alignment == .none);
......@@ -35861,7 +35703,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3586135703 const ip = &zcu.intern_pool;
3586235704 const struct_type = zcu.typeToStruct(ty) orelse return;
3586335705
35864 assert(sema.owner.unwrap().cau == struct_type.cau);
35706 assert(sema.owner.unwrap().type == ty.toIntern());
3586535707
3586635708 if (struct_type.haveLayout(ip))
3586735709 return;
......@@ -36008,15 +35850,13 @@ fn backingIntType(
3600835850 const gpa = zcu.gpa;
3600935851 const ip = &zcu.intern_pool;
3601035852
36011 const cau_index = struct_type.cau;
36012
3601335853 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3601435854 defer analysis_arena.deinit();
3601535855
3601635856 var block: Block = .{
3601735857 .parent = null,
3601835858 .sema = sema,
36019 .namespace = ip.getCau(cau_index).namespace,
35859 .namespace = struct_type.namespace,
3602035860 .instructions = .{},
3602135861 .inlining = null,
3602235862 .is_comptime = true,
......@@ -36148,7 +35988,7 @@ pub fn resolveUnionAlignment(
3614835988 const ip = &zcu.intern_pool;
3614935989 const target = zcu.getTarget();
3615035990
36151 assert(sema.owner.unwrap().cau == union_type.cau);
35991 assert(sema.owner.unwrap().type == ty.toIntern());
3615235992
3615335993 assert(!union_type.haveLayout(ip));
3615435994
......@@ -36188,7 +36028,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3618836028 // Load again, since the tag type might have changed due to resolution.
3618936029 const union_type = ip.loadUnionType(ty.ip_index);
3619036030
36191 assert(sema.owner.unwrap().cau == union_type.cau);
36031 assert(sema.owner.unwrap().type == ty.toIntern());
3619236032
3619336033 const old_flags = union_type.flagsUnordered(ip);
3619436034 switch (old_flags.status) {
......@@ -36303,7 +36143,7 @@ pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void {
3630336143 const ip = &zcu.intern_pool;
3630436144 const struct_type = zcu.typeToStruct(ty).?;
3630536145
36306 assert(sema.owner.unwrap().cau == struct_type.cau);
36146 assert(sema.owner.unwrap().type == ty.toIntern());
3630736147
3630836148 if (struct_type.setFullyResolved(ip)) return;
3630936149 errdefer struct_type.clearFullyResolved(ip);
......@@ -36326,7 +36166,7 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
3632636166 const ip = &zcu.intern_pool;
3632736167 const union_obj = zcu.typeToUnion(ty).?;
3632836168
36329 assert(sema.owner.unwrap().cau == union_obj.cau);
36169 assert(sema.owner.unwrap().type == ty.toIntern());
3633036170
3633136171 switch (union_obj.flagsUnordered(ip).status) {
3633236172 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
......@@ -36361,7 +36201,7 @@ pub fn resolveStructFieldTypes(
3636136201 const zcu = pt.zcu;
3636236202 const ip = &zcu.intern_pool;
3636336203
36364 assert(sema.owner.unwrap().cau == struct_type.cau);
36204 assert(sema.owner.unwrap().type == ty);
3636536205
3636636206 if (struct_type.haveFieldTypes(ip)) return;
3636736207
......@@ -36387,7 +36227,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3638736227 const ip = &zcu.intern_pool;
3638836228 const struct_type = zcu.typeToStruct(ty) orelse return;
3638936229
36390 assert(sema.owner.unwrap().cau == struct_type.cau);
36230 assert(sema.owner.unwrap().type == ty.toIntern());
3639136231
3639236232 // Inits can start as resolved
3639336233 if (struct_type.haveFieldInits(ip)) return;
......@@ -36416,7 +36256,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load
3641636256 const zcu = pt.zcu;
3641736257 const ip = &zcu.intern_pool;
3641836258
36419 assert(sema.owner.unwrap().cau == union_type.cau);
36259 assert(sema.owner.unwrap().type == ty.toIntern());
3642036260
3642136261 switch (union_type.flagsUnordered(ip).status) {
3642236262 .none => {},
......@@ -36492,7 +36332,7 @@ fn resolveInferredErrorSet(
3649236332 // In this case we are dealing with the actual InferredErrorSet object that
3649336333 // corresponds to the function, not one created to track an inline/comptime call.
3649436334 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index }));
36495 try pt.ensureFuncBodyAnalyzed(func_index);
36335 try pt.ensureFuncBodyUpToDate(func_index);
3649636336 }
3649736337
3649836338 // This will now have been resolved by the logic at the end of `Zcu.analyzeFnBody`
......@@ -36649,8 +36489,7 @@ fn structFields(
3664936489 const zcu = pt.zcu;
3665036490 const gpa = zcu.gpa;
3665136491 const ip = &zcu.intern_pool;
36652 const cau_index = struct_type.cau;
36653 const namespace_index = ip.getCau(cau_index).namespace;
36492 const namespace_index = struct_type.namespace;
3665436493 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;
3665536494 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
3665636495
......@@ -36848,8 +36687,7 @@ fn structFieldInits(
3684836687
3684936688 assert(!struct_type.haveFieldInits(ip));
3685036689
36851 const cau_index = struct_type.cau;
36852 const namespace_index = ip.getCau(cau_index).namespace;
36690 const namespace_index = struct_type.namespace;
3685336691 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;
3685436692 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
3685536693 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
......@@ -38650,14 +38488,17 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3865038488 // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would
3865138489 // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve
3865238490 // the loop.
38491 // Note that this also disallows a `nav_val`
3865338492 switch (sema.owner.unwrap()) {
38654 .cau => |cau| switch (dependee) {
38655 .nav_val => |nav| if (zcu.intern_pool.getNav(nav).analysis_owner == cau.toOptional()) {
38656 return;
38657 },
38493 .nav_val => |this_nav| switch (dependee) {
38494 .nav_val => |other_nav| if (this_nav == other_nav) return,
3865838495 else => {},
3865938496 },
38660 .func => {},
38497 .nav_ty => |this_nav| switch (dependee) {
38498 .nav_ty => |other_nav| if (this_nav == other_nav) return,
38499 else => {},
38500 },
38501 else => {},
3866138502 }
3866238503
3866338504 try zcu.intern_pool.addDependency(sema.gpa, sema.owner, dependee);
......@@ -38836,45 +38677,6 @@ pub fn flushExports(sema: *Sema) !void {
3883638677 }
3883738678}
3883838679
38839/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
38840/// the corresponding `Nav`.
38841fn getOwnerCauNav(sema: *Sema) InternPool.Nav.Index {
38842 const cau = sema.owner.unwrap().cau;
38843 return sema.pt.zcu.intern_pool.getCau(cau).owner.unwrap().nav;
38844}
38845
38846/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
38847/// the declaration name from its corresponding `Nav`.
38848fn getOwnerCauNavName(sema: *Sema) InternPool.NullTerminatedString {
38849 const nav = sema.getOwnerCauNav();
38850 return sema.pt.zcu.intern_pool.getNav(nav).name;
38851}
38852
38853/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
38854/// the `TrackedInst` corresponding to this `declaration` instruction.
38855fn getOwnerCauDeclInst(sema: *Sema) InternPool.TrackedInst.Index {
38856 const ip = &sema.pt.zcu.intern_pool;
38857 const cau = ip.getCau(sema.owner.unwrap().cau);
38858 assert(cau.owner.unwrap() == .nav);
38859 return cau.zir_index;
38860}
38861
38862/// Given that this `Sema` is owned by a runtime function, fetches the
38863/// `TrackedInst` corresponding to its `declaration` instruction.
38864fn getOwnerFuncDeclInst(sema: *Sema) InternPool.TrackedInst.Index {
38865 const zcu = sema.pt.zcu;
38866 const ip = &zcu.intern_pool;
38867 const func = sema.owner.unwrap().func;
38868 const func_info = zcu.funcInfo(func);
38869 const cau = if (func_info.generic_owner == .none) cau: {
38870 break :cau ip.getNav(func_info.owner_nav).analysis_owner.unwrap().?;
38871 } else cau: {
38872 const generic_owner = zcu.funcInfo(func_info.generic_owner);
38873 break :cau ip.getNav(generic_owner.owner_nav).analysis_owner.unwrap().?;
38874 };
38875 return ip.getCau(cau).zir_index;
38876}
38877
3887838680/// Called as soon as a `declared` enum type is created.
3887938681/// Resolves the tag type and field inits.
3888038682/// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this.
......@@ -38885,7 +38687,6 @@ pub fn resolveDeclaredEnum(
3888538687 tracked_inst: InternPool.TrackedInst.Index,
3888638688 namespace: InternPool.NamespaceIndex,
3888738689 type_name: InternPool.NullTerminatedString,
38888 enum_cau: InternPool.Cau.Index,
3888938690 small: Zir.Inst.EnumDecl.Small,
3889038691 body: []const Zir.Inst.Index,
3889138692 tag_type_ref: Zir.Inst.Ref,
......@@ -38903,7 +38704,7 @@ pub fn resolveDeclaredEnum(
3890338704 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) };
3890438705 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } };
3890538706
38906 const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau });
38707 const anal_unit = AnalUnit.wrap(.{ .type = wip_ty.index });
3890738708
3890838709 var arena = std.heap.ArenaAllocator.init(gpa);
3890938710 defer arena.deinit();
......@@ -39115,8 +38916,8 @@ fn getBuiltinInnerType(
3911538916 const nav = opt_nav orelse return sema.fail(block, src, "std.builtin.{s} missing {s}", .{
3911638917 compile_error_parent_name, inner_name,
3911738918 });
39118 try sema.ensureNavResolved(src, nav);
39119 const val = Value.fromInterned(ip.getNav(nav).status.resolved.val);
38919 try sema.ensureNavResolved(src, nav, .fully);
38920 const val = Value.fromInterned(ip.getNav(nav).status.fully_resolved.val);
3912038921 const ty = val.toType();
3912138922 try ty.resolveFully(pt);
3912238923 return ty;
......@@ -39127,6 +38928,74 @@ fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref {
3912738928 const zcu = pt.zcu;
3912838929 const ip = &zcu.intern_pool;
3912938930 const nav = try pt.getBuiltinNav(name);
39130 try pt.ensureCauAnalyzed(ip.getNav(nav).analysis_owner.unwrap().?);
39131 return Air.internedToRef(ip.getNav(nav).status.resolved.val);
38931 try pt.ensureNavValUpToDate(nav);
38932 return Air.internedToRef(ip.getNav(nav).status.fully_resolved.val);
38933}
38934
38935pub const NavPtrModifiers = struct {
38936 alignment: Alignment,
38937 @"linksection": InternPool.OptionalNullTerminatedString,
38938 @"addrspace": std.builtin.AddressSpace,
38939};
38940
38941pub fn resolveNavPtrModifiers(
38942 sema: *Sema,
38943 block: *Block,
38944 zir_decl: Zir.Inst.Declaration.Unwrapped,
38945 decl_inst: Zir.Inst.Index,
38946 nav_ty: Type,
38947) CompileError!NavPtrModifiers {
38948 const pt = sema.pt;
38949 const zcu = pt.zcu;
38950 const gpa = zcu.gpa;
38951 const ip = &zcu.intern_pool;
38952
38953 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
38954 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
38955 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
38956
38957 const alignment: InternPool.Alignment = a: {
38958 const align_body = zir_decl.align_body orelse break :a .none;
38959 const align_ref = try sema.resolveInlineBody(block, align_body, decl_inst);
38960 break :a try sema.analyzeAsAlign(block, align_src, align_ref);
38961 };
38962
38963 const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
38964 const linksection_body = zir_decl.linksection_body orelse break :ls .none;
38965 const linksection_ref = try sema.resolveInlineBody(block, linksection_body, decl_inst);
38966 const bytes = try sema.toConstString(block, section_src, linksection_ref, .{
38967 .needed_comptime_reason = "linksection must be comptime-known",
38968 });
38969 if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
38970 return sema.fail(block, section_src, "linksection cannot contain null bytes", .{});
38971 } else if (bytes.len == 0) {
38972 return sema.fail(block, section_src, "linksection cannot be empty", .{});
38973 }
38974 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
38975 };
38976
38977 const @"addrspace": std.builtin.AddressSpace = as: {
38978 const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
38979 .@"var" => .variable,
38980 else => switch (nav_ty.zigTypeTag(zcu)) {
38981 .@"fn" => .function,
38982 else => .constant,
38983 },
38984 };
38985 const target = zcu.getTarget();
38986 const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {
38987 .function => target_util.defaultAddressSpace(target, .function),
38988 .variable => target_util.defaultAddressSpace(target, .global_mutable),
38989 .constant => target_util.defaultAddressSpace(target, .global_constant),
38990 else => unreachable,
38991 };
38992 const addrspace_ref = try sema.resolveInlineBody(block, addrspace_body, decl_inst);
38993 break :as try sema.analyzeAsAddressSpace(block, addrspace_src, addrspace_ref, addrspace_ctx);
38994 };
38995
38996 return .{
38997 .alignment = alignment,
38998 .@"linksection" = @"linksection",
38999 .@"addrspace" = @"addrspace",
39000 };
3913239001}
src/Sema/comptime_ptr_access.zig+2-3
......@@ -219,9 +219,8 @@ fn loadComptimePtrInner(
219219
220220 const base_val: MutableValue = switch (ptr.base_addr) {
221221 .nav => |nav| val: {
222 try sema.declareDependency(.{ .nav_val = nav });
223 try sema.ensureNavResolved(src, nav);
224 const val = ip.getNav(nav).status.resolved.val;
222 try sema.ensureNavResolved(src, nav, .fully);
223 const val = ip.getNav(nav).status.fully_resolved.val;
225224 switch (ip.indexToKey(val)) {
226225 .variable => return .runtime_load,
227226 // We let `.@"extern"` through here if it's a function.
src/Type.zig+2-2
......@@ -3851,7 +3851,7 @@ fn resolveStructInner(
38513851 const gpa = zcu.gpa;
38523852
38533853 const struct_obj = zcu.typeToStruct(ty).?;
3854 const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau });
3854 const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
38553855
38563856 if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
38573857 return error.AnalysisFail;
......@@ -3905,7 +3905,7 @@ fn resolveUnionInner(
39053905 const gpa = zcu.gpa;
39063906
39073907 const union_obj = zcu.typeToUnion(ty).?;
3908 const owner = InternPool.AnalUnit.wrap(.{ .cau = union_obj.cau });
3908 const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
39093909
39103910 if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
39113911 return error.AnalysisFail;
src/Value.zig+6-1
......@@ -1343,7 +1343,12 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {
13431343pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool {
13441344 const ip = &zcu.intern_pool;
13451345 const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;
1346 return switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) {
1346 const nav_val = switch (ip.getNav(nav).status) {
1347 .unresolved => unreachable,
1348 .type_resolved => |r| return r.is_threadlocal,
1349 .fully_resolved => |r| r.val,
1350 };
1351 return switch (ip.indexToKey(nav_val)) {
13471352 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
13481353 .variable => |v| v.is_threadlocal,
13491354 else => false,
src/Zcu.zig+187-147
......@@ -170,6 +170,9 @@ outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
170170/// it as outdated.
171171retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
172172
173func_body_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty,
174nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
175
173176/// These are the modules which we initially queue for analysis in `Compilation.update`.
174177/// `resolveReferences` will use these as the root of its reachability traversal.
175178analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
......@@ -192,7 +195,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .empty,
192195
193196test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
194197
195global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .empty,
198global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty,
196199
197200/// Key is the `AnalUnit` *performing* the reference. This representation allows
198201/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
......@@ -282,7 +285,11 @@ pub const Exported = union(enum) {
282285
283286 pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
284287 return switch (exported) {
285 .nav => |nav| zcu.intern_pool.getNav(nav).status.resolved.alignment,
288 .nav => |nav| switch (zcu.intern_pool.getNav(nav).status) {
289 .unresolved => unreachable,
290 .type_resolved => |r| r.alignment,
291 .fully_resolved => |r| r.alignment,
292 },
286293 .uav => .none,
287294 };
288295 }
......@@ -344,9 +351,12 @@ pub const Namespace = struct {
344351 pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
345352 /// All `usingnamespace` declarations in this namespace which are *not* marked `pub`.
346353 priv_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
347 /// All `comptime` and `test` declarations in this namespace. We store these purely so that
348 /// incremental compilation can re-use the existing `Cau`s when a namespace changes.
349 other_decls: std.ArrayListUnmanaged(InternPool.Cau.Index) = .empty,
354 /// All `comptime` declarations in this namespace. We store these purely so that incremental
355 /// compilation can re-use the existing `ComptimeUnit`s when a namespace changes.
356 comptime_decls: std.ArrayListUnmanaged(InternPool.ComptimeUnit.Id) = .empty,
357 /// All `test` declarations in this namespace. We store these purely so that incremental
358 /// compilation can re-use the existing `Nav`s when a namespace changes.
359 test_decls: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
350360
351361 pub const Index = InternPool.NamespaceIndex;
352362 pub const OptionalIndex = InternPool.OptionalNamespaceIndex;
......@@ -2238,6 +2248,9 @@ pub fn deinit(zcu: *Zcu) void {
22382248 zcu.outdated_ready.deinit(gpa);
22392249 zcu.retryable_failures.deinit(gpa);
22402250
2251 zcu.func_body_analysis_queued.deinit(gpa);
2252 zcu.nav_val_analysis_queued.deinit(gpa);
2253
22412254 zcu.test_functions.deinit(gpa);
22422255
22432256 for (zcu.global_assembly.values()) |s| {
......@@ -2436,11 +2449,10 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
24362449 // If this is a Decl, we must recursively mark dependencies on its tyval
24372450 // as no longer PO.
24382451 switch (depender.unwrap()) {
2439 .cau => |cau| switch (zcu.intern_pool.getCau(cau).owner.unwrap()) {
2440 .nav => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
2441 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
2442 .none => {},
2443 },
2452 .@"comptime" => {},
2453 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
2454 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
2455 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
24442456 .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
24452457 }
24462458 }
......@@ -2451,11 +2463,10 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
24512463fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
24522464 const ip = &zcu.intern_pool;
24532465 const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) {
2454 .cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
2455 .nav => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced
2456 .type => |ty| .{ .interned = ty },
2457 .none => return, // analysis of this `Cau` can't outdate any dependencies
2458 },
2466 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies
2467 .nav_val => |nav| .{ .nav_val = nav },
2468 .nav_ty => |nav| .{ .nav_ty = nav },
2469 .type => |ty| .{ .interned = ty },
24592470 .func => |func_index| .{ .interned = func_index }, // IES
24602471 };
24612472 log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)});
......@@ -2512,14 +2523,14 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
25122523 }
25132524
25142525 // There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some
2515 // Cau with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
2516 // A or B. We should select a Cau, since a Cau is definitely responsible for the loop in the
2517 // dependency graph (since IES dependencies can't have loops). We should also, of course, not
2518 // select a Cau owned by a `comptime` declaration, since you can't depend on those!
2526 // AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
2527 // A or B. We should definitely not select a function, since a function can't be responsible for the
2528 // loop (IES dependencies can't have loops). We should also, of course, not select a `comptime`
2529 // declaration, since you can't depend on those!
25192530
2520 // The choice of this Cau could have a big impact on how much total analysis we perform, since
2531 // The choice of this unit could have a big impact on how much total analysis we perform, since
25212532 // if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit
2522 // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a Decl
2533 // may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit
25232534 // which the most things depend on - the idea is that this will resolve a lot of loops (but this
25242535 // is only a heuristic).
25252536
......@@ -2530,33 +2541,29 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
25302541
25312542 const ip = &zcu.intern_pool;
25322543
2533 var chosen_cau: ?InternPool.Cau.Index = null;
2534 var chosen_cau_dependers: u32 = undefined;
2544 var chosen_unit: ?AnalUnit = null;
2545 var chosen_unit_dependers: u32 = undefined;
25352546
25362547 inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
25372548 for (outdated_units) |unit| {
2538 const cau = switch (unit.unwrap()) {
2539 .cau => |cau| cau,
2540 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
2541 };
2542 const cau_owner = ip.getCau(cau).owner;
2543
25442549 var n: u32 = 0;
2545 var it = ip.dependencyIterator(switch (cau_owner.unwrap()) {
2546 .none => continue, // there can be no dependencies on this `Cau` so it is a terrible choice
2550 var it = ip.dependencyIterator(switch (unit.unwrap()) {
2551 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
2552 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
25472553 .type => |ty| .{ .interned = ty },
2548 .nav => |nav| .{ .nav_val = nav },
2554 .nav_val => |nav| .{ .nav_val = nav },
2555 .nav_ty => |nav| .{ .nav_ty = nav },
25492556 });
25502557 while (it.next()) |_| n += 1;
25512558
2552 if (chosen_cau == null or n > chosen_cau_dependers) {
2553 chosen_cau = cau;
2554 chosen_cau_dependers = n;
2559 if (chosen_unit == null or n > chosen_unit_dependers) {
2560 chosen_unit = unit;
2561 chosen_unit_dependers = n;
25552562 }
25562563 }
25572564 }
25582565
2559 if (chosen_cau == null) {
2566 if (chosen_unit == null) {
25602567 for (zcu.outdated.keys(), zcu.outdated.values()) |o, opod| {
25612568 const func = o.unwrap().func;
25622569 const nav = zcu.funcInfo(func).owner_nav;
......@@ -2570,11 +2577,11 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
25702577 }
25712578
25722579 log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{
2573 zcu.fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? })),
2574 chosen_cau_dependers,
2580 zcu.fmtAnalUnit(chosen_unit.?),
2581 chosen_unit_dependers,
25752582 });
25762583
2577 return AnalUnit.wrap(.{ .cau = chosen_cau.? });
2584 return chosen_unit.?;
25782585}
25792586
25802587/// During an incremental update, before semantic analysis, call this to flush all values from
......@@ -2679,24 +2686,14 @@ pub fn mapOldZirToNew(
26792686 {
26802687 var old_decl_it = old_zir.declIterator(match_item.old_inst);
26812688 while (old_decl_it.next()) |old_decl_inst| {
2682 const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
2683 switch (old_decl.name) {
2689 const old_decl = old_zir.getDeclaration(old_decl_inst);
2690 switch (old_decl.kind) {
26842691 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
26852692 .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
26862693 .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),
2687 _ => {
2688 const name_nts = old_decl.name.toString(old_zir).?;
2689 const name = old_zir.nullTerminatedString(name_nts);
2690 if (old_decl.name.isNamedTest(old_zir)) {
2691 if (old_decl.flags.test_is_decltest) {
2692 try named_decltests.put(gpa, name, old_decl_inst);
2693 } else {
2694 try named_tests.put(gpa, name, old_decl_inst);
2695 }
2696 } else {
2697 try named_decls.put(gpa, name, old_decl_inst);
2698 }
2699 },
2694 .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
2695 .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
2696 .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
27002697 }
27012698 }
27022699 }
......@@ -2707,7 +2704,7 @@ pub fn mapOldZirToNew(
27072704
27082705 var new_decl_it = new_zir.declIterator(match_item.new_inst);
27092706 while (new_decl_it.next()) |new_decl_inst| {
2710 const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
2707 const new_decl = new_zir.getDeclaration(new_decl_inst);
27112708 // Attempt to match this to a declaration in the old ZIR:
27122709 // * For named declarations (`const`/`var`/`fn`), we match based on name.
27132710 // * For named tests (`test "foo"`) and decltests (`test foo`), we also match based on name.
......@@ -2715,7 +2712,7 @@ pub fn mapOldZirToNew(
27152712 // * For comptime blocks, we match based on order.
27162713 // * For usingnamespace decls, we match based on order.
27172714 // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
2718 const old_decl_inst = switch (new_decl.name) {
2715 const old_decl_inst = switch (new_decl.kind) {
27192716 .@"comptime" => inst: {
27202717 if (comptime_decl_idx == comptime_decls.items.len) continue;
27212718 defer comptime_decl_idx += 1;
......@@ -2731,18 +2728,17 @@ pub fn mapOldZirToNew(
27312728 defer unnamed_test_idx += 1;
27322729 break :inst unnamed_tests.items[unnamed_test_idx];
27332730 },
2734 _ => inst: {
2735 const name_nts = new_decl.name.toString(new_zir).?;
2736 const name = new_zir.nullTerminatedString(name_nts);
2737 if (new_decl.name.isNamedTest(new_zir)) {
2738 if (new_decl.flags.test_is_decltest) {
2739 break :inst named_decltests.get(name) orelse continue;
2740 } else {
2741 break :inst named_tests.get(name) orelse continue;
2742 }
2743 } else {
2744 break :inst named_decls.get(name) orelse continue;
2745 }
2731 .@"test" => inst: {
2732 const name = new_zir.nullTerminatedString(new_decl.name);
2733 break :inst named_tests.get(name) orelse continue;
2734 },
2735 .decltest => inst: {
2736 const name = new_zir.nullTerminatedString(new_decl.name);
2737 break :inst named_decltests.get(name) orelse continue;
2738 },
2739 .@"const", .@"var" => inst: {
2740 const name = new_zir.nullTerminatedString(new_decl.name);
2741 break :inst named_decls.get(name) orelse continue;
27462742 },
27472743 };
27482744
......@@ -2797,14 +2793,39 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo
27972793 const ip = &zcu.intern_pool;
27982794 const func = zcu.funcInfo(func_index);
27992795
2800 switch (func.analysisUnordered(ip).state) {
2801 .unreferenced => {}, // We're the first reference!
2802 .queued => return, // Analysis is already queued.
2803 .analyzed => return, // Analysis is complete; if it's out-of-date, it'll be re-analyzed later this update.
2796 if (zcu.func_body_analysis_queued.contains(func_index)) return;
2797
2798 if (func.analysisUnordered(ip).is_analyzed) {
2799 if (!zcu.outdated.contains(.wrap(.{ .func = func_index })) and
2800 !zcu.potentially_outdated.contains(.wrap(.{ .func = func_index })))
2801 {
2802 // This function has been analyzed before and is definitely up-to-date.
2803 return;
2804 }
28042805 }
28052806
2807 try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
28062808 try zcu.comp.queueJob(.{ .analyze_func = func_index });
2807 func.setAnalysisState(ip, .queued);
2809 zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {});
2810}
2811
2812pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void {
2813 const ip = &zcu.intern_pool;
2814
2815 if (zcu.nav_val_analysis_queued.contains(nav_id)) return;
2816
2817 if (ip.getNav(nav_id).status == .fully_resolved) {
2818 if (!zcu.outdated.contains(.wrap(.{ .nav_val = nav_id })) and
2819 !zcu.potentially_outdated.contains(.wrap(.{ .nav_val = nav_id })))
2820 {
2821 // This `Nav` has been analyzed before and is definitely up-to-date.
2822 return;
2823 }
2824 }
2825
2826 try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
2827 try zcu.comp.queueJob(.{ .analyze_comptime_unit = .wrap(.{ .nav_val = nav_id }) });
2828 zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
28082829}
28092830
28102831pub const ImportFileResult = struct {
......@@ -3030,9 +3051,9 @@ pub fn handleUpdateExports(
30303051 };
30313052}
30323053
3033pub fn addGlobalAssembly(zcu: *Zcu, cau: InternPool.Cau.Index, source: []const u8) !void {
3054pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void {
30343055 const gpa = zcu.gpa;
3035 const gop = try zcu.global_assembly.getOrPut(gpa, cau);
3056 const gop = try zcu.global_assembly.getOrPut(gpa, unit);
30363057 if (gop.found_existing) {
30373058 const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
30383059 gpa.free(gop.value_ptr.*);
......@@ -3315,23 +3336,22 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
33153336
33163337 log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
33173338
3318 // If this type has a `Cau` for resolution, it's automatically referenced.
3319 const resolution_cau: InternPool.Cau.Index.Optional = switch (ip.indexToKey(ty)) {
3320 .struct_type => ip.loadStructType(ty).cau.toOptional(),
3321 .union_type => ip.loadUnionType(ty).cau.toOptional(),
3322 .enum_type => ip.loadEnumType(ty).cau,
3323 .opaque_type => .none,
3339 // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced.
3340 const has_resolution: bool = switch (ip.indexToKey(ty)) {
3341 .struct_type, .union_type => true,
3342 .enum_type => |k| k != .generated_tag,
3343 .opaque_type => false,
33243344 else => unreachable,
33253345 };
3326 if (resolution_cau.unwrap()) |cau| {
3346 if (has_resolution) {
33273347 // this should only be referenced by the type
3328 const unit = AnalUnit.wrap(.{ .cau = cau });
3348 const unit: AnalUnit = .wrap(.{ .type = ty });
33293349 assert(!result.contains(unit));
33303350 try unit_queue.putNoClobber(gpa, unit, referencer);
33313351 }
33323352
33333353 // If this is a union with a generated tag, its tag type is automatically referenced.
3334 // We don't add this reference for non-generated tags, as those will already be referenced via the union's `Cau`, with a better source location.
3354 // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location.
33353355 if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| {
33363356 const tag_ty = union_obj.enum_tag_ty;
33373357 if (tag_ty != .none) {
......@@ -3346,53 +3366,61 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
33463366 // Queue any decls within this type which would be automatically analyzed.
33473367 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.
33483368 const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?;
3349 for (zcu.namespacePtr(ns).other_decls.items) |cau| {
3350 // These are `comptime` and `test` declarations.
3351 // `comptime` decls are always analyzed; `test` declarations are analyzed depending on the test filter.
3352 const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
3369 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| {
3370 // `comptime` decls are always analyzed.
3371 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
3372 if (!result.contains(unit)) {
3373 log.debug("type '{}': ref comptime %{}", .{
3374 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
3375 @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
3376 });
3377 try unit_queue.put(gpa, unit, referencer);
3378 }
3379 }
3380 for (zcu.namespacePtr(ns).test_decls.items) |nav_id| {
3381 const nav = ip.getNav(nav_id);
3382 // `test` declarations are analyzed depending on the test filter.
3383 const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;
33533384 const file = zcu.fileByIndex(inst_info.file);
33543385 // If the file failed AstGen, the TrackedInst refers to the old ZIR.
33553386 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
3356 const declaration = zir.getDeclaration(inst_info.inst)[0];
3357 const want_analysis = switch (declaration.name) {
3387 const decl = zir.getDeclaration(inst_info.inst);
3388
3389 if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
3390
3391 const want_analysis = switch (decl.kind) {
33583392 .@"usingnamespace" => unreachable,
3359 .@"comptime" => true,
3360 else => a: {
3361 if (!comp.config.is_test) break :a false;
3362 if (file.mod != zcu.main_mod) break :a false;
3363 if (declaration.name.isNamedTest(zir)) {
3364 const nav = ip.getCau(cau).owner.unwrap().nav;
3365 const fqn_slice = ip.getNav(nav).fqn.toSlice(ip);
3366 for (comp.test_filters) |test_filter| {
3367 if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
3368 } else break :a false;
3369 }
3393 .@"const", .@"var" => unreachable,
3394 .@"comptime" => unreachable,
3395 .unnamed_test => true,
3396 .@"test", .decltest => a: {
3397 const fqn_slice = nav.fqn.toSlice(ip);
3398 for (comp.test_filters) |test_filter| {
3399 if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
3400 } else break :a false;
33703401 break :a true;
33713402 },
33723403 };
33733404 if (want_analysis) {
3374 const unit = AnalUnit.wrap(.{ .cau = cau });
3375 if (!result.contains(unit)) {
3376 log.debug("type '{}': ref cau %{}", .{
3377 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
3378 @intFromEnum(inst_info.inst),
3379 });
3380 try unit_queue.put(gpa, unit, referencer);
3381 }
3405 log.debug("type '{}': ref test %{}", .{
3406 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
3407 @intFromEnum(inst_info.inst),
3408 });
3409 const unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
3410 try unit_queue.put(gpa, unit, referencer);
33823411 }
33833412 }
33843413 for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| {
33853414 // These are named declarations. They are analyzed only if marked `export`.
3386 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3387 const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
3415 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
33883416 const file = zcu.fileByIndex(inst_info.file);
33893417 // If the file failed AstGen, the TrackedInst refers to the old ZIR.
33903418 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
3391 const declaration = zir.getDeclaration(inst_info.inst)[0];
3392 if (declaration.flags.is_export) {
3393 const unit = AnalUnit.wrap(.{ .cau = cau });
3419 const decl = zir.getDeclaration(inst_info.inst);
3420 if (decl.linkage == .@"export") {
3421 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
33943422 if (!result.contains(unit)) {
3395 log.debug("type '{}': ref cau %{}", .{
3423 log.debug("type '{}': ref named %{}", .{
33963424 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
33973425 @intFromEnum(inst_info.inst),
33983426 });
......@@ -3402,16 +3430,15 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
34023430 }
34033431 for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| {
34043432 // These are named declarations. They are analyzed only if marked `export`.
3405 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3406 const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
3433 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
34073434 const file = zcu.fileByIndex(inst_info.file);
34083435 // If the file failed AstGen, the TrackedInst refers to the old ZIR.
34093436 const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
3410 const declaration = zir.getDeclaration(inst_info.inst)[0];
3411 if (declaration.flags.is_export) {
3412 const unit = AnalUnit.wrap(.{ .cau = cau });
3437 const decl = zir.getDeclaration(inst_info.inst);
3438 if (decl.linkage == .@"export") {
3439 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
34133440 if (!result.contains(unit)) {
3414 log.debug("type '{}': ref cau %{}", .{
3441 log.debug("type '{}': ref named %{}", .{
34153442 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
34163443 @intFromEnum(inst_info.inst),
34173444 });
......@@ -3422,13 +3449,11 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
34223449 // Incremental compilation does not support `usingnamespace`.
34233450 // These are only included to keep good reference traces in non-incremental updates.
34243451 for (zcu.namespacePtr(ns).pub_usingnamespace.items) |nav| {
3425 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3426 const unit = AnalUnit.wrap(.{ .cau = cau });
3452 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
34273453 if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
34283454 }
34293455 for (zcu.namespacePtr(ns).priv_usingnamespace.items) |nav| {
3430 const cau = ip.getNav(nav).analysis_owner.unwrap().?;
3431 const unit = AnalUnit.wrap(.{ .cau = cau });
3456 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
34323457 if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
34333458 }
34343459 continue;
......@@ -3437,6 +3462,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
34373462 const unit = kv.key;
34383463 try result.putNoClobber(gpa, unit, kv.value);
34393464
3465 // `nav_val` and `nav_ty` reference each other *implicitly* to save memory.
3466 queue_paired: {
3467 const other: AnalUnit = .wrap(switch (unit.unwrap()) {
3468 .nav_val => |n| .{ .nav_ty = n },
3469 .nav_ty => |n| .{ .nav_val = n },
3470 .@"comptime", .type, .func => break :queue_paired,
3471 });
3472 if (result.contains(other)) break :queue_paired;
3473 try unit_queue.put(gpa, other, kv.value); // same reference location
3474 }
3475
34403476 log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)});
34413477
34423478 if (zcu.reference_table.get(unit)) |first_ref_idx| {
......@@ -3522,13 +3558,11 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
35223558 const ip = &zcu.intern_pool;
35233559 const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?;
35243560 const zir = zcu.fileByIndex(inst_info.file).zir;
3525 const inst = zir.instructions.get(@intFromEnum(inst_info.inst));
3526 assert(inst.tag == .declaration);
3527 return zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
3561 return zir.getDeclaration(inst_info.inst).src_line;
35283562}
35293563
35303564pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
3531 return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
3565 return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.fully_resolved.val);
35323566}
35333567
35343568pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {
......@@ -3540,12 +3574,6 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
35403574 return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
35413575}
35423576
3543pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {
3544 const ip = &zcu.intern_pool;
3545 const file_index = ip.getCau(cau).zir_index.resolveFile(ip);
3546 return zcu.fileByIndex(file_index);
3547}
3548
35493577pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) {
35503578 return .{ .data = .{ .unit = unit, .zcu = zcu } };
35513579}
......@@ -3558,19 +3586,18 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
35583586 const zcu = data.zcu;
35593587 const ip = &zcu.intern_pool;
35603588 switch (data.unit.unwrap()) {
3561 .cau => |cau_index| {
3562 const cau = ip.getCau(cau_index);
3563 switch (cau.owner.unwrap()) {
3564 .nav => |nav| return writer.print("cau(decl='{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
3565 .type => |ty| return writer.print("cau(ty='{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
3566 .none => if (cau.zir_index.resolveFull(ip)) |resolved| {
3567 const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
3568 return writer.print("cau(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) });
3569 } else {
3570 return writer.writeAll("cau(inst=<lost>)");
3571 },
3589 .@"comptime" => |cu_id| {
3590 const cu = ip.getComptimeUnit(cu_id);
3591 if (cu.zir_index.resolveFull(ip)) |resolved| {
3592 const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
3593 return writer.print("comptime(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) });
3594 } else {
3595 return writer.writeAll("comptime(inst=<list>)");
35723596 }
35733597 },
3598 .nav_val => |nav| return writer.print("nav_val('{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
3599 .nav_ty => |nav| return writer.print("nav_ty('{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
3600 .type => |ty| return writer.print("ty('{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
35743601 .func => |func| {
35753602 const nav = zcu.funcInfo(func).owner_nav;
35763603 return writer.print("func('{}')", .{ip.getNav(nav).fqn.fmt(ip)});
......@@ -3595,7 +3622,11 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
35953622 },
35963623 .nav_val => |nav| {
35973624 const fqn = ip.getNav(nav).fqn;
3598 return writer.print("nav('{}')", .{fqn.fmt(ip)});
3625 return writer.print("nav_val('{}')", .{fqn.fmt(ip)});
3626 },
3627 .nav_ty => |nav| {
3628 const fqn = ip.getNav(nav).fqn;
3629 return writer.print("nav_ty('{}')", .{fqn.fmt(ip)});
35993630 },
36003631 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
36013632 .struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),
......@@ -3772,3 +3803,12 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
37723803 if (!backend_ok) return .{ .bad_backend = backend };
37733804 return .ok;
37743805}
3806
3807/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer.
3808pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool {
3809 return switch (zcu.intern_pool.indexToKey(val)) {
3810 .variable => false,
3811 .@"extern" => |e| e.is_const,
3812 else => true,
3813 };
3814}
src/Zcu/PerThread.zig+942-703
......@@ -469,12 +469,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
469469 {
470470 var it = old_zir.declIterator(old_inst);
471471 while (it.next()) |decl_inst| {
472 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
473 switch (decl_name) {
474 .@"comptime", .@"usingnamespace", .unnamed_test => continue,
475 _ => if (decl_name.isNamedTest(old_zir)) continue,
476 }
477 const name_zir = decl_name.toString(old_zir).?;
472 const name_zir = old_zir.getDeclaration(decl_inst).name;
473 if (name_zir == .empty) continue;
478474 const name_ip = try zcu.intern_pool.getOrPutString(
479475 zcu.gpa,
480476 pt.tid,
......@@ -488,12 +484,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
488484 {
489485 var it = new_zir.declIterator(new_inst);
490486 while (it.next()) |decl_inst| {
491 const decl_name = new_zir.getDeclaration(decl_inst)[0].name;
492 switch (decl_name) {
493 .@"comptime", .@"usingnamespace", .unnamed_test => continue,
494 _ => if (decl_name.isNamedTest(new_zir)) continue,
495 }
496 const name_zir = decl_name.toString(new_zir).?;
487 const name_zir = new_zir.getDeclaration(decl_inst).name;
488 if (name_zir == .empty) continue;
497489 const name_ip = try zcu.intern_pool.getOrPutString(
498490 zcu.gpa,
499491 pt.tid,
......@@ -553,118 +545,643 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
553545pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
554546 const file_root_type = pt.zcu.fileRootType(file_index);
555547 if (file_root_type != .none) {
556 _ = try pt.ensureTypeUpToDate(file_root_type, false);
548 _ = try pt.ensureTypeUpToDate(file_root_type);
557549 } else {
558550 return pt.semaFile(file_index);
559551 }
560552}
561553
562/// This ensures that the state of the `Cau`, and of its corresponding `Nav` or type,
563/// is fully up-to-date. Note that the type of the `Nav` may not be fully resolved.
564/// Returns `error.AnalysisFail` if the `Cau` has an error.
565pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu.SemaError!void {
554/// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis
555/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
556/// free to ignore this, since the error is already registered.
557pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void {
566558 const tracy = trace(@src());
567559 defer tracy.end();
568560
569561 const zcu = pt.zcu;
570562 const gpa = zcu.gpa;
571 const ip = &zcu.intern_pool;
572563
573 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
574 const cau = ip.getCau(cau_index);
564 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
575565
576 log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
566 log.debug("ensureComptimeUnitUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
577567
578568 assert(!zcu.analysis_in_progress.contains(anal_unit));
579569
580 // Determine whether or not this Cau is outdated, i.e. requires re-analysis
581 // even if `complete`. If a Cau is PO, we pessismistically assume that it
582 // *does* require re-analysis, to ensure that the Cau is definitely
583 // up-to-date when this function returns.
584
585 // If analysis occurs in a poor order, this could result in over-analysis.
586 // We do our best to avoid this by the other dependency logic in this file
587 // which tries to limit re-analysis to Caus whose previously listed
588 // dependencies are all up-to-date.
570 // Determine whether or not this `ComptimeUnit` is outdated. For this kind of `AnalUnit`, that's
571 // the only indicator as to whether or not analysis is required; when a `ComptimeUnit` is first
572 // created, it's marked as outdated.
573 //
574 // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
575 // ensure that the unit is definitely up-to-date when this function returns. This mechanism could
576 // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
577 // carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
589578
590 const cau_outdated = zcu.outdated.swapRemove(anal_unit) or
579 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
591580 zcu.potentially_outdated.swapRemove(anal_unit);
592581
593 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
594
595 if (cau_outdated) {
582 if (was_outdated) {
596583 _ = zcu.outdated_ready.swapRemove(anal_unit);
584 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
585 if (dev.env.supports(.incremental)) {
586 zcu.deleteUnitExports(anal_unit);
587 zcu.deleteUnitReferences(anal_unit);
588 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
589 kv.value.destroy(gpa);
590 }
591 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
592 }
597593 } else {
598 // We can trust the current information about this `Cau`.
599 if (prev_failed) {
594 // We can trust the current information about this unit.
595 if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
596 if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail;
597 return;
598 }
599
600 const unit_prog_node = zcu.sema_prog_node.start("comptime", 0);
601 defer unit_prog_node.end();
602
603 return pt.analyzeComptimeUnit(cu_id) catch |err| switch (err) {
604 error.AnalysisFail => {
605 if (!zcu.failed_analysis.contains(anal_unit)) {
606 // If this unit caused the error, it would have an entry in `failed_analysis`.
607 // Since it does not, this must be a transitive failure.
608 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
609 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
610 }
600611 return error.AnalysisFail;
612 },
613 error.OutOfMemory => {
614 // TODO: it's unclear how to gracefully handle this.
615 // To report the error cleanly, we need to add a message to `failed_analysis` and a
616 // corresponding entry to `retryable_failures`; but either of these things is quite
617 // likely to OOM at this point.
618 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
619 // for reporting OOM errors without allocating.
620 return error.OutOfMemory;
621 },
622 error.GenericPoison => unreachable,
623 error.ComptimeReturn => unreachable,
624 error.ComptimeBreak => unreachable,
625 };
626}
627
628/// Re-analyzes a `ComptimeUnit`. The unit has already been determined to be out-of-date, and old
629/// side effects (exports/references/etc) have been dropped. If semantic analysis fails, this
630/// function will return `error.AnalysisFail`, and it is the caller's reponsibility to add an entry
631/// to `transitive_failed_analysis` if necessary.
632fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.CompileError!void {
633 const zcu = pt.zcu;
634 const gpa = zcu.gpa;
635 const ip = &zcu.intern_pool;
636
637 const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id });
638 const comptime_unit = ip.getComptimeUnit(cu_id);
639
640 log.debug("analyzeComptimeUnit {}", .{zcu.fmtAnalUnit(anal_unit)});
641
642 const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
643 const file = zcu.fileByIndex(inst_resolved.file);
644 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
645 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
646 // in `ensureComptimeUnitUpToDate`.
647 if (file.status != .success_zir) return error.AnalysisFail;
648 const zir = file.zir;
649
650 // We are about to re-analyze this unit; drop its depenndencies.
651 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
652
653 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
654 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
655
656 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
657 defer analysis_arena.deinit();
658
659 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
660 defer comptime_err_ret_trace.deinit();
661
662 var sema: Sema = .{
663 .pt = pt,
664 .gpa = gpa,
665 .arena = analysis_arena.allocator(),
666 .code = zir,
667 .owner = anal_unit,
668 .func_index = .none,
669 .func_is_naked = false,
670 .fn_ret_ty = .void,
671 .fn_ret_ty_ies = null,
672 .comptime_err_ret_trace = &comptime_err_ret_trace,
673 };
674 defer sema.deinit();
675
676 // The comptime unit declares on the source of the corresponding `comptime` declaration.
677 try sema.declareDependency(.{ .src_hash = comptime_unit.zir_index });
678
679 var block: Sema.Block = .{
680 .parent = null,
681 .sema = &sema,
682 .namespace = comptime_unit.namespace,
683 .instructions = .{},
684 .inlining = null,
685 .is_comptime = true,
686 .src_base_inst = comptime_unit.zir_index,
687 .type_name_ctx = try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{
688 Type.fromInterned(zcu.namespacePtr(comptime_unit.namespace).owner_type).containerTypeName(ip).fmt(ip),
689 }, .no_embedded_nulls),
690 };
691 defer block.instructions.deinit(gpa);
692
693 const zir_decl = zir.getDeclaration(inst_resolved.inst);
694 assert(zir_decl.kind == .@"comptime");
695 assert(zir_decl.type_body == null);
696 assert(zir_decl.align_body == null);
697 assert(zir_decl.linksection_body == null);
698 assert(zir_decl.addrspace_body == null);
699 const value_body = zir_decl.value_body.?;
700
701 const result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
702 assert(result_ref == .void_value); // AstGen should always uphold this
703
704 // Nothing else to do -- for a comptime decl, all we care about are the side effects.
705 // Just make sure to `flushExports`.
706 try sema.flushExports();
707}
708
709/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis
710/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
711/// free to ignore this, since the error is already registered.
712pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {
713 const tracy = trace(@src());
714 defer tracy.end();
715
716 // TODO: document this elsewhere mlugg!
717 // For my own benefit, here's how a namespace update for a normal (non-file-root) type works:
718 // `const S = struct { ... };`
719 // We are adding or removing a declaration within this `struct`.
720 // * `S` registers a dependency on `.{ .src_hash = (declaration of S) }`
721 // * Any change to the `struct` body -- including changing a declaration -- invalidates this
722 // * `S` is re-analyzed, but notes:
723 // * there is an existing struct instance (at this `TrackedInst` with these captures)
724 // * the struct's resolution is up-to-date (because nothing about the fields changed)
725 // * so, it uses the same `struct`
726 // * but this doesn't stop it from updating the namespace!
727 // * we basically do `scanDecls`, updating the namespace as needed
728 // * so everyone lived happily ever after
729
730 const zcu = pt.zcu;
731 const gpa = zcu.gpa;
732 const ip = &zcu.intern_pool;
733
734 _ = zcu.nav_val_analysis_queued.swapRemove(nav_id);
735
736 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
737 const nav = ip.getNav(nav_id);
738
739 log.debug("ensureNavValUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
740
741 // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
742 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
743 // been analyzed so far.
744 //
745 // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
746 // ensure that the unit is definitely up-to-date when this function returns. This mechanism could
747 // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
748 // carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
749
750 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
751 zcu.potentially_outdated.swapRemove(anal_unit);
752
753 const prev_failed = zcu.failed_analysis.contains(anal_unit) or
754 zcu.transitive_failed_analysis.contains(anal_unit);
755
756 if (was_outdated) {
757 dev.check(.incremental);
758 _ = zcu.outdated_ready.swapRemove(anal_unit);
759 zcu.deleteUnitExports(anal_unit);
760 zcu.deleteUnitReferences(anal_unit);
761 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
762 kv.value.destroy(gpa);
601763 }
602 // If it wasn't failed and wasn't marked outdated, then either...
603 // * it is a type and is up-to-date, or
604 // * it is a `comptime` decl and is up-to-date, or
605 // * it is another decl and is EITHER up-to-date OR never-referenced (so unresolved)
606 // We just need to check for that last case.
607 switch (cau.owner.unwrap()) {
608 .type, .none => return,
609 .nav => |nav| if (ip.getNav(nav).status == .resolved) return,
764 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
765 } else {
766 // We can trust the current information about this unit.
767 if (prev_failed) return error.AnalysisFail;
768 switch (nav.status) {
769 .unresolved, .type_resolved => {},
770 .fully_resolved => return,
610771 }
611772 }
612773
613 const sema_result: SemaCauResult, const analysis_fail = if (pt.ensureCauAnalyzedInner(cau_index, cau_outdated)) |result|
614 // This `Cau` has gone from failed to success, so even if the value of the owner `Nav` didn't actually
615 // change, we need to invalidate the dependencies anyway.
616 .{ .{
617 .invalidate_decl_val = result.invalidate_decl_val or prev_failed,
618 .invalidate_decl_ref = result.invalidate_decl_ref or prev_failed,
619 }, false }
620 else |err| switch (err) {
774 const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0);
775 defer unit_prog_node.end();
776
777 const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: {
778 break :res .{
779 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
780 result.val_changed or prev_failed,
781 false,
782 };
783 } else |err| switch (err) {
621784 error.AnalysisFail => res: {
622785 if (!zcu.failed_analysis.contains(anal_unit)) {
623 // If this `Cau` caused the error, it would have an entry in `failed_analysis`.
786 // If this unit caused the error, it would have an entry in `failed_analysis`.
624787 // Since it does not, this must be a transitive failure.
625788 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
626789 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
627790 }
628 // We consider this `Cau` to be outdated if:
629 // * Previous analysis succeeded; in this case, we need to re-analyze dependants to ensure
630 // they hit a transitive error here, rather than reporting a different error later (which
631 // may now be invalid).
632 // * The `Cau` is a type; in this case, the declaration site may require re-analysis to
633 // construct a valid type.
634 const outdated = !prev_failed or cau.owner.unwrap() == .type;
635 break :res .{ .{
636 .invalidate_decl_val = outdated,
637 .invalidate_decl_ref = outdated,
638 }, true };
791 break :res .{ !prev_failed, true };
639792 },
640 error.OutOfMemory => res: {
641 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
642 try zcu.retryable_failures.ensureUnusedCapacity(gpa, 1);
643 const msg = try Zcu.ErrorMsg.create(
644 gpa,
645 .{ .base_node_inst = cau.zir_index, .offset = Zcu.LazySrcLoc.Offset.nodeOffset(0) },
646 "unable to analyze: OutOfMemory",
647 .{},
648 );
649 zcu.retryable_failures.appendAssumeCapacity(anal_unit);
650 zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, msg);
651 break :res .{ .{
652 .invalidate_decl_val = true,
653 .invalidate_decl_ref = true,
654 }, true };
793 error.OutOfMemory => {
794 // TODO: it's unclear how to gracefully handle this.
795 // To report the error cleanly, we need to add a message to `failed_analysis` and a
796 // corresponding entry to `retryable_failures`; but either of these things is quite
797 // likely to OOM at this point.
798 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
799 // for reporting OOM errors without allocating.
800 return error.OutOfMemory;
801 },
802 error.GenericPoison => unreachable,
803 error.ComptimeReturn => unreachable,
804 error.ComptimeBreak => unreachable,
805 };
806
807 if (was_outdated) {
808 const dependee: InternPool.Dependee = .{ .nav_val = nav_id };
809 if (invalidate_value) {
810 // This dependency was marked as PO, meaning dependees were waiting
811 // on its analysis result, and it has turned out to be outdated.
812 // Update dependees accordingly.
813 try zcu.markDependeeOutdated(.marked_po, dependee);
814 } else {
815 // This dependency was previously PO, but turned out to be up-to-date.
816 // We do not need to queue successive analysis.
817 try zcu.markPoDependeeUpToDate(dependee);
818 }
819 }
820
821 if (new_failed) return error.AnalysisFail;
822}
823
824fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { val_changed: bool } {
825 const zcu = pt.zcu;
826 const gpa = zcu.gpa;
827 const ip = &zcu.intern_pool;
828
829 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
830 const old_nav = ip.getNav(nav_id);
831
832 log.debug("analyzeNavVal {}", .{zcu.fmtAnalUnit(anal_unit)});
833
834 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
835 const file = zcu.fileByIndex(inst_resolved.file);
836 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
837 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
838 // in `ensureComptimeUnitUpToDate`.
839 if (file.status != .success_zir) return error.AnalysisFail;
840 const zir = file.zir;
841
842 // We are about to re-analyze this unit; drop its depenndencies.
843 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
844
845 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
846 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
847
848 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
849 defer analysis_arena.deinit();
850
851 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
852 defer comptime_err_ret_trace.deinit();
853
854 var sema: Sema = .{
855 .pt = pt,
856 .gpa = gpa,
857 .arena = analysis_arena.allocator(),
858 .code = zir,
859 .owner = anal_unit,
860 .func_index = .none,
861 .func_is_naked = false,
862 .fn_ret_ty = .void,
863 .fn_ret_ty_ies = null,
864 .comptime_err_ret_trace = &comptime_err_ret_trace,
865 };
866 defer sema.deinit();
867
868 // Every `Nav` declares a dependency on the source of the corresponding declaration.
869 try sema.declareDependency(.{ .src_hash = old_nav.analysis.?.zir_index });
870
871 // In theory, we would also add a reference to the corresponding `nav_val` unit here: there are
872 // always references in both directions between a `nav_val` and `nav_ty`. However, to save memory,
873 // these references are known implicitly. See logic in `Zcu.resolveReferences`.
874
875 var block: Sema.Block = .{
876 .parent = null,
877 .sema = &sema,
878 .namespace = old_nav.analysis.?.namespace,
879 .instructions = .{},
880 .inlining = null,
881 .is_comptime = true,
882 .src_base_inst = old_nav.analysis.?.zir_index,
883 .type_name_ctx = old_nav.fqn,
884 };
885 defer block.instructions.deinit(gpa);
886
887 const zir_decl = zir.getDeclaration(inst_resolved.inst);
888 assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
889
890 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
891 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
892 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
893 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
894 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
895
896 const maybe_ty: ?Type = if (zir_decl.type_body != null) ty: {
897 // Since we have a type body, the type is resolved separately!
898 // Of course, we need to make sure we depend on it properly.
899 try sema.declareDependency(.{ .nav_ty = nav_id });
900 try pt.ensureNavTypeUpToDate(nav_id);
901 break :ty .fromInterned(ip.getNav(nav_id).status.type_resolved.type);
902 } else null;
903
904 const final_val: ?Value = if (zir_decl.value_body) |value_body| val: {
905 if (maybe_ty) |ty| {
906 // Put the resolved type into `inst_map` to be used as the result type of the init.
907 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{inst_resolved.inst});
908 sema.inst_map.putAssumeCapacity(inst_resolved.inst, Air.internedToRef(ty.toIntern()));
909 const uncoerced_result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
910 assert(sema.inst_map.remove(inst_resolved.inst));
911
912 const result_ref = try sema.coerce(&block, ty, uncoerced_result_ref, init_src);
913 break :val try sema.resolveFinalDeclValue(&block, init_src, result_ref);
914 } else {
915 // Just analyze the value; we have no type to offer.
916 const result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
917 break :val try sema.resolveFinalDeclValue(&block, init_src, result_ref);
918 }
919 } else null;
920
921 const nav_ty: Type = maybe_ty orelse final_val.?.typeOf(zcu);
922
923 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
924 // or otherwise, we analyze the value body, populating `early_val` in the process.
925
926 switch (zir_decl.kind) {
927 .@"comptime" => unreachable, // this is not a Nav
928 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),
929 .@"usingnamespace" => {},
930 .@"const" => {},
931 .@"var" => try sema.validateVarType(
932 &block,
933 if (zir_decl.type_body != null) ty_src else init_src,
934 nav_ty,
935 zir_decl.linkage == .@"extern",
936 ),
937 }
938
939 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
940 // the full pointer type of this declaration.
941
942 const modifiers: Sema.NavPtrModifiers = if (zir_decl.type_body != null) m: {
943 // `analyzeNavType` (from the `ensureNavTypeUpToDate` call above) has already populated this data into
944 // the `Nav`. Load the new one, and pull the modifiers out.
945 switch (ip.getNav(nav_id).status) {
946 .unresolved => unreachable, // `analyzeNavType` will never leave us in this state
947 inline .type_resolved, .fully_resolved => |r| break :m .{
948 .alignment = r.alignment,
949 .@"linksection" = r.@"linksection",
950 .@"addrspace" = r.@"addrspace",
951 },
952 }
953 } else m: {
954 // `analyzeNavType` is essentially a stub which calls us. We are responsible for resolving this data.
955 break :m try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, nav_ty);
956 };
957
958 // Lastly, we must figure out the actual interned value to store to the `Nav`.
959 // This isn't necessarily the same as `final_val`!
960
961 const nav_val: Value = switch (zir_decl.linkage) {
962 .normal, .@"export" => switch (zir_decl.kind) {
963 .@"var" => .fromInterned(try pt.intern(.{ .variable = .{
964 .ty = nav_ty.toIntern(),
965 .init = final_val.?.toIntern(),
966 .owner_nav = nav_id,
967 .is_threadlocal = zir_decl.is_threadlocal,
968 .is_weak_linkage = false,
969 } })),
970 else => final_val.?,
971 },
972 .@"extern" => val: {
973 assert(final_val == null); // extern decls do not have a value body
974 const lib_name: ?[]const u8 = if (zir_decl.lib_name != .empty) l: {
975 break :l zir.nullTerminatedString(zir_decl.lib_name);
976 } else null;
977 if (lib_name) |l| {
978 const lib_name_src = block.src(.{ .node_offset_lib_name = 0 });
979 try sema.handleExternLibName(&block, lib_name_src, l);
980 }
981 break :val .fromInterned(try pt.getExtern(.{
982 .name = old_nav.name,
983 .ty = nav_ty.toIntern(),
984 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
985 .is_const = zir_decl.kind == .@"const",
986 .is_threadlocal = zir_decl.is_threadlocal,
987 .is_weak_linkage = false,
988 .is_dll_import = false,
989 .alignment = modifiers.alignment,
990 .@"addrspace" = modifiers.@"addrspace",
991 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
992 .owner_nav = undefined, // ignored by `getExtern`
993 }));
655994 },
656995 };
657996
658 if (cau_outdated) {
659 // TODO: we do not yet have separate dependencies for decl values vs types.
660 const invalidate = sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref;
661 const dependee: InternPool.Dependee = switch (cau.owner.unwrap()) {
662 .none => return, // there are no dependencies on a `comptime` decl!
663 .nav => |nav_index| .{ .nav_val = nav_index },
664 .type => |ty| .{ .interned = ty },
997 switch (nav_val.toIntern()) {
998 .generic_poison => unreachable, // assertion failure
999 .unreachable_value => unreachable, // assertion failure
1000 else => {},
1001 }
1002
1003 // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,
1004 // this resolves the type `type` (which needs no resolution), not the struct itself.
1005 try nav_ty.resolveLayout(pt);
1006
1007 // TODO: this is jank. If #20663 is rejected, let's think about how to better model `usingnamespace`.
1008 if (zir_decl.kind == .@"usingnamespace") {
1009 if (nav_ty.toIntern() != .type_type) {
1010 return sema.fail(&block, ty_src, "expected type, found {}", .{nav_ty.fmt(pt)});
1011 }
1012 if (nav_val.toType().getNamespace(zcu) == .none) {
1013 return sema.fail(&block, ty_src, "type {} has no namespace", .{nav_val.toType().fmt(pt)});
1014 }
1015 ip.resolveNavValue(nav_id, .{
1016 .val = nav_val.toIntern(),
1017 .alignment = .none,
1018 .@"linksection" = .none,
1019 .@"addrspace" = .generic,
1020 });
1021 // TODO: usingnamespace cannot participate in incremental compilation
1022 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1023 return .{ .val_changed = true };
1024 }
1025
1026 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
1027 .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
1028 .variable => |v| .{ v.owner_nav == nav_id, false },
1029 .@"extern" => |e| .{
1030 false,
1031 Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn" and zir_decl.linkage == .@"extern",
1032 },
1033 else => .{ true, false },
1034 };
1035
1036 if (is_owned_fn) {
1037 // linksection etc are legal, except some targets do not support function alignment.
1038 if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
1039 return sema.fail(&block, align_src, "target does not support function alignment", .{});
1040 }
1041 } else if (try nav_ty.comptimeOnlySema(pt)) {
1042 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.
1043 const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {
1044 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
1045 else => "comptime-only type",
1046 };
1047 if (zir_decl.align_body != null) {
1048 return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});
1049 }
1050 if (zir_decl.linksection_body != null) {
1051 return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});
1052 }
1053 if (zir_decl.addrspace_body != null) {
1054 return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});
1055 }
1056 }
1057
1058 ip.resolveNavValue(nav_id, .{
1059 .val = nav_val.toIntern(),
1060 .alignment = modifiers.alignment,
1061 .@"linksection" = modifiers.@"linksection",
1062 .@"addrspace" = modifiers.@"addrspace",
1063 });
1064
1065 // Mark the unit as completed before evaluating the export!
1066 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1067
1068 if (zir_decl.type_body == null) {
1069 // In this situation, it's possible that we were triggered by `analyzeNavType` up the stack. In that
1070 // case, we must also signal that the *type* is now populated to make this export behave correctly.
1071 // An alternative strategy would be to just put something on the job queue to perform the export, but
1072 // this is a little more straightforward, if perhaps less elegant.
1073 _ = zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id }));
1074 }
1075
1076 if (zir_decl.linkage == .@"export") {
1077 const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.is_pub) });
1078 const name_slice = zir.nullTerminatedString(zir_decl.name);
1079 const name_ip = try ip.getOrPutString(gpa, pt.tid, name_slice, .no_embedded_nulls);
1080 try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_id);
1081 }
1082
1083 try sema.flushExports();
1084
1085 queue_codegen: {
1086 if (!queue_linker_work) break :queue_codegen;
1087
1088 if (!try nav_ty.hasRuntimeBitsSema(pt)) {
1089 if (zcu.comp.config.use_llvm) break :queue_codegen;
1090 if (file.mod.strip) break :queue_codegen;
1091 }
1092
1093 // This job depends on any resolve_type_fully jobs queued up before it.
1094 try zcu.comp.queueJob(.{ .codegen_nav = nav_id });
1095 }
1096
1097 switch (old_nav.status) {
1098 .unresolved, .type_resolved => return .{ .val_changed = true },
1099 .fully_resolved => |old| return .{ .val_changed = old.val != nav_val.toIntern() },
1100 }
1101}
1102
1103pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {
1104 const tracy = trace(@src());
1105 defer tracy.end();
1106
1107 const zcu = pt.zcu;
1108 const gpa = zcu.gpa;
1109 const ip = &zcu.intern_pool;
1110
1111 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
1112 const nav = ip.getNav(nav_id);
1113
1114 log.debug("ensureNavTypeUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
1115
1116 // Determine whether or not this `Nav`'s type is outdated. This also includes checking if the
1117 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
1118 // been analyzed so far.
1119 //
1120 // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
1121 // ensure that the unit is definitely up-to-date when this function returns. This mechanism could
1122 // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
1123 // carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
1124
1125 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1126 zcu.potentially_outdated.swapRemove(anal_unit);
1127
1128 const prev_failed = zcu.failed_analysis.contains(anal_unit) or
1129 zcu.transitive_failed_analysis.contains(anal_unit);
1130
1131 if (was_outdated) {
1132 dev.check(.incremental);
1133 _ = zcu.outdated_ready.swapRemove(anal_unit);
1134 zcu.deleteUnitExports(anal_unit);
1135 zcu.deleteUnitReferences(anal_unit);
1136 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1137 kv.value.destroy(gpa);
1138 }
1139 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1140 } else {
1141 // We can trust the current information about this unit.
1142 if (prev_failed) return error.AnalysisFail;
1143 switch (nav.status) {
1144 .unresolved => {},
1145 .type_resolved, .fully_resolved => return,
1146 }
1147 }
1148
1149 const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0);
1150 defer unit_prog_node.end();
1151
1152 const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id)) |result| res: {
1153 break :res .{
1154 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
1155 result.type_changed or prev_failed,
1156 false,
6651157 };
1158 } else |err| switch (err) {
1159 error.AnalysisFail => res: {
1160 if (!zcu.failed_analysis.contains(anal_unit)) {
1161 // If this unit caused the error, it would have an entry in `failed_analysis`.
1162 // Since it does not, this must be a transitive failure.
1163 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1164 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
1165 }
1166 break :res .{ !prev_failed, true };
1167 },
1168 error.OutOfMemory => {
1169 // TODO: it's unclear how to gracefully handle this.
1170 // To report the error cleanly, we need to add a message to `failed_analysis` and a
1171 // corresponding entry to `retryable_failures`; but either of these things is quite
1172 // likely to OOM at this point.
1173 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
1174 // for reporting OOM errors without allocating.
1175 return error.OutOfMemory;
1176 },
1177 error.GenericPoison => unreachable,
1178 error.ComptimeReturn => unreachable,
1179 error.ComptimeBreak => unreachable,
1180 };
6661181
667 if (invalidate) {
1182 if (was_outdated) {
1183 const dependee: InternPool.Dependee = .{ .nav_ty = nav_id };
1184 if (invalidate_type) {
6681185 // This dependency was marked as PO, meaning dependees were waiting
6691186 // on its analysis result, and it has turned out to be outdated.
6701187 // Update dependees accordingly.
......@@ -676,67 +1193,151 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
6761193 }
6771194 }
6781195
679 if (analysis_fail) return error.AnalysisFail;
680}
1196 if (new_failed) return error.AnalysisFail;
1197}
1198
1199fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { type_changed: bool } {
1200 const zcu = pt.zcu;
1201 const gpa = zcu.gpa;
1202 const ip = &zcu.intern_pool;
1203
1204 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
1205 const old_nav = ip.getNav(nav_id);
1206
1207 log.debug("analyzeNavType {}", .{zcu.fmtAnalUnit(anal_unit)});
1208
1209 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1210 const file = zcu.fileByIndex(inst_resolved.file);
1211 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
1212 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
1213 // in `ensureComptimeUnitUpToDate`.
1214 if (file.status != .success_zir) return error.AnalysisFail;
1215 const zir = file.zir;
1216
1217 // We are about to re-analyze this unit; drop its depenndencies.
1218 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1219
1220 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1221 defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
1222
1223 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1224 defer analysis_arena.deinit();
1225
1226 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
1227 defer comptime_err_ret_trace.deinit();
1228
1229 var sema: Sema = .{
1230 .pt = pt,
1231 .gpa = gpa,
1232 .arena = analysis_arena.allocator(),
1233 .code = zir,
1234 .owner = anal_unit,
1235 .func_index = .none,
1236 .func_is_naked = false,
1237 .fn_ret_ty = .void,
1238 .fn_ret_ty_ies = null,
1239 .comptime_err_ret_trace = &comptime_err_ret_trace,
1240 };
1241 defer sema.deinit();
1242
1243 // Every `Nav` declares a dependency on the source of the corresponding declaration.
1244 try sema.declareDependency(.{ .src_hash = old_nav.analysis.?.zir_index });
1245
1246 // In theory, we would also add a reference to the corresponding `nav_val` unit here: there are
1247 // always references in both directions between a `nav_val` and `nav_ty`. However, to save memory,
1248 // these references are known implicitly. See logic in `Zcu.resolveReferences`.
1249
1250 var block: Sema.Block = .{
1251 .parent = null,
1252 .sema = &sema,
1253 .namespace = old_nav.analysis.?.namespace,
1254 .instructions = .{},
1255 .inlining = null,
1256 .is_comptime = true,
1257 .src_base_inst = old_nav.analysis.?.zir_index,
1258 .type_name_ctx = old_nav.fqn,
1259 };
1260 defer block.instructions.deinit(gpa);
1261
1262 const zir_decl = zir.getDeclaration(inst_resolved.inst);
1263 assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
1264
1265 const type_body = zir_decl.type_body orelse {
1266 // The type of this `Nav` is inferred from the value.
1267 // In other words, this `nav_ty` depends on the corresponding `nav_val`.
1268 try sema.declareDependency(.{ .nav_val = nav_id });
1269 try pt.ensureNavValUpToDate(nav_id);
1270 // Note that the above call, if it did any work, has removed our `analysis_in_progress` entry for us.
1271 // (Our `defer` will run anyway, but it does nothing in this case.)
1272
1273 // There's not a great way for us to know whether the type actually changed.
1274 // For instance, perhaps the `nav_val` was already up-to-date, but this `nav_ty` is being
1275 // analyzed because this declaration had a type annotation on the *previous* update.
1276 // However, such cases are rare, and it's not unreasonable to re-analyze in them; and in
1277 // other cases where we get here, it's because the `nav_val` was already re-analyzed and
1278 // is outdated.
1279 return .{ .type_changed = true };
1280 };
6811281
682fn ensureCauAnalyzedInner(
683 pt: Zcu.PerThread,
684 cau_index: InternPool.Cau.Index,
685 cau_outdated: bool,
686) Zcu.SemaError!SemaCauResult {
687 const zcu = pt.zcu;
688 const ip = &zcu.intern_pool;
1282 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
6891283
690 const cau = ip.getCau(cau_index);
691 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
1284 const resolved_ty: Type = ty: {
1285 const uncoerced_type_ref = try sema.resolveInlineBody(&block, type_body, inst_resolved.inst);
1286 const type_ref = try sema.coerce(&block, .type, uncoerced_type_ref, ty_src);
1287 break :ty .fromInterned(type_ref.toInterned().?);
1288 };
6921289
693 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1290 // In the case where the type is specified, this function is also responsible for resolving
1291 // the pointer modifiers, i.e. alignment, linksection, addrspace.
1292 const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);
6941293
695 // TODO: document this elsewhere mlugg!
696 // For my own benefit, here's how a namespace update for a normal (non-file-root) type works:
697 // `const S = struct { ... };`
698 // We are adding or removing a declaration within this `struct`.
699 // * `S` registers a dependency on `.{ .src_hash = (declaration of S) }`
700 // * Any change to the `struct` body -- including changing a declaration -- invalidates this
701 // * `S` is re-analyzed, but notes:
702 // * there is an existing struct instance (at this `TrackedInst` with these captures)
703 // * the struct's `Cau` is up-to-date (because nothing about the fields changed)
704 // * so, it uses the same `struct`
705 // * but this doesn't stop it from updating the namespace!
706 // * we basically do `scanDecls`, updating the namespace as needed
707 // * so everyone lived happily ever after
1294 // Usually, we can infer this information from the resolved `Nav` value; see `Zcu.navValIsConst`.
1295 // However, since we don't have one, we need to quickly check the ZIR to figure this out.
1296 const is_const = switch (zir_decl.kind) {
1297 .@"comptime" => unreachable,
1298 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
1299 .@"var" => false,
1300 };
7081301
709 if (zcu.fileByIndex(inst_info.file).status != .success_zir) {
710 return error.AnalysisFail;
711 }
1302 const is_extern_decl = zir_decl.linkage == .@"extern";
1303
1304 // Now for the question of the day: are the type and modifiers the same as before?
1305 // If they are, then we should actually keep the `Nav` as `fully_resolved` if it currently is.
1306 // That's because `analyzeNavVal` will later want to look at the resolved value to figure out
1307 // whether it's changed: if we threw that data away now, it would have to assume that the value
1308 // had changed, potentially spinning off loads of unnecessary re-analysis!
1309 const changed = switch (old_nav.status) {
1310 .unresolved => true,
1311 .type_resolved => |r| r.type != resolved_ty.toIntern() or
1312 r.alignment != modifiers.alignment or
1313 r.@"linksection" != modifiers.@"linksection" or
1314 r.@"addrspace" != modifiers.@"addrspace" or
1315 r.is_const != is_const or
1316 r.is_extern_decl != is_extern_decl,
1317 .fully_resolved => |r| ip.typeOf(r.val) != resolved_ty.toIntern() or
1318 r.alignment != modifiers.alignment or
1319 r.@"linksection" != modifiers.@"linksection" or
1320 r.@"addrspace" != modifiers.@"addrspace" or
1321 zcu.navValIsConst(r.val) != is_const or
1322 (old_nav.getExtern(ip) != null) != is_extern_decl,
1323 };
7121324
713 // `cau_outdated` can be true in the initial update for `comptime` declarations,
714 // so this isn't a `dev.check`.
715 if (cau_outdated and dev.env.supports(.incremental)) {
716 // The exports this `Cau` performs will be re-discovered, so we remove them here
717 // prior to re-analysis.
718 zcu.deleteUnitExports(anal_unit);
719 zcu.deleteUnitReferences(anal_unit);
720 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
721 kv.value.destroy(zcu.gpa);
722 }
723 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
724 }
1325 if (!changed) return .{ .type_changed = false };
7251326
726 const decl_prog_node = zcu.sema_prog_node.start(switch (cau.owner.unwrap()) {
727 .nav => |nav| ip.getNav(nav).fqn.toSlice(ip),
728 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
729 .none => "comptime",
730 }, 0);
731 defer decl_prog_node.end();
1327 ip.resolveNavType(nav_id, .{
1328 .type = resolved_ty.toIntern(),
1329 .alignment = modifiers.alignment,
1330 .@"linksection" = modifiers.@"linksection",
1331 .@"addrspace" = modifiers.@"addrspace",
1332 .is_const = is_const,
1333 .is_threadlocal = zir_decl.is_threadlocal,
1334 .is_extern_decl = is_extern_decl,
1335 });
7321336
733 return pt.semaCau(cau_index) catch |err| switch (err) {
734 error.GenericPoison, error.ComptimeBreak, error.ComptimeReturn => unreachable,
735 error.AnalysisFail, error.OutOfMemory => |e| return e,
736 };
1337 return .{ .type_changed = true };
7371338}
7381339
739pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {
1340pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {
7401341 dev.check(.sema);
7411342
7421343 const tracy = trace(@src());
......@@ -746,35 +1347,43 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
7461347 const gpa = zcu.gpa;
7471348 const ip = &zcu.intern_pool;
7481349
1350 _ = zcu.func_body_analysis_queued.swapRemove(maybe_coerced_func_index);
1351
7491352 // We only care about the uncoerced function.
7501353 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
751 const anal_unit = AnalUnit.wrap(.{ .func = func_index });
1354 const anal_unit: AnalUnit = .wrap(.{ .func = func_index });
7521355
753 log.debug("ensureFuncBodyAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)});
1356 log.debug("ensureFuncBodyUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
7541357
7551358 const func = zcu.funcInfo(maybe_coerced_func_index);
7561359
757 const func_outdated = zcu.outdated.swapRemove(anal_unit) or
1360 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
7581361 zcu.potentially_outdated.swapRemove(anal_unit);
7591362
7601363 const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
7611364
762 if (func_outdated) {
1365 if (was_outdated) {
1366 dev.check(.incremental);
7631367 _ = zcu.outdated_ready.swapRemove(anal_unit);
1368 zcu.deleteUnitExports(anal_unit);
1369 zcu.deleteUnitReferences(anal_unit);
1370 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1371 kv.value.destroy(gpa);
1372 }
1373 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
7641374 } else {
7651375 // We can trust the current information about this function.
7661376 if (prev_failed) {
7671377 return error.AnalysisFail;
7681378 }
769 switch (func.analysisUnordered(ip).state) {
770 .unreferenced => {}, // this is the first reference
771 .queued => {}, // we're waiting on first-time analysis
772 .analyzed => return, // up-to-date
773 }
1379 if (func.analysisUnordered(ip).is_analyzed) return;
7741380 }
7751381
776 const ies_outdated, const analysis_fail = if (pt.ensureFuncBodyAnalyzedInner(func_index, func_outdated)) |result|
777 .{ result.ies_outdated, false }
1382 const func_prog_node = zcu.sema_prog_node.start(ip.getNav(func.owner_nav).fqn.toSlice(ip), 0);
1383 defer func_prog_node.end();
1384
1385 const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index)) |result|
1386 .{ prev_failed or result.ies_outdated, false }
7781387 else |err| switch (err) {
7791388 error.AnalysisFail => res: {
7801389 if (!zcu.failed_analysis.contains(anal_unit)) {
......@@ -788,10 +1397,18 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
7881397 // a different error later (which may now be invalid).
7891398 break :res .{ !prev_failed, true };
7901399 },
791 error.OutOfMemory => return error.OutOfMemory, // TODO: graceful handling like `ensureCauAnalyzed`
1400 error.OutOfMemory => {
1401 // TODO: it's unclear how to gracefully handle this.
1402 // To report the error cleanly, we need to add a message to `failed_analysis` and a
1403 // corresponding entry to `retryable_failures`; but either of these things is quite
1404 // likely to OOM at this point.
1405 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
1406 // for reporting OOM errors without allocating.
1407 return error.OutOfMemory;
1408 },
7921409 };
7931410
794 if (func_outdated) {
1411 if (was_outdated) {
7951412 if (ies_outdated) {
7961413 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });
7971414 } else {
......@@ -799,13 +1416,12 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
7991416 }
8001417 }
8011418
802 if (analysis_fail) return error.AnalysisFail;
1419 if (new_failed) return error.AnalysisFail;
8031420}
8041421
805fn ensureFuncBodyAnalyzedInner(
1422fn analyzeFuncBody(
8061423 pt: Zcu.PerThread,
8071424 func_index: InternPool.Index,
808 func_outdated: bool,
8091425) Zcu.SemaError!struct { ies_outdated: bool } {
8101426 const zcu = pt.zcu;
8111427 const gpa = zcu.gpa;
......@@ -820,8 +1436,8 @@ fn ensureFuncBodyAnalyzedInner(
8201436
8211437 if (func.generic_owner == .none) {
8221438 // Among another things, this ensures that the function's `zir_body_inst` is correct.
823 try pt.ensureCauAnalyzed(ip.getNav(func.owner_nav).analysis_owner.unwrap().?);
824 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {
1439 try pt.ensureNavValUpToDate(func.owner_nav);
1440 if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {
8251441 // This function is no longer referenced! There's no point in re-analyzing it.
8261442 // Just mark a transitive failure and move on.
8271443 return error.AnalysisFail;
......@@ -829,8 +1445,8 @@ fn ensureFuncBodyAnalyzedInner(
8291445 } else {
8301446 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
8311447 // Among another things, this ensures that the function's `zir_body_inst` is correct.
832 try pt.ensureCauAnalyzed(ip.getNav(go_nav).analysis_owner.unwrap().?);
833 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {
1448 try pt.ensureNavValUpToDate(go_nav);
1449 if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {
8341450 // The generic owner is no longer referenced, so this function is also unreferenced.
8351451 // There's no point in re-analyzing it. Just mark a transitive failure and move on.
8361452 return error.AnalysisFail;
......@@ -844,38 +1460,13 @@ fn ensureFuncBodyAnalyzedInner(
8441460 else
8451461 .none;
8461462
847 if (func_outdated) {
848 dev.check(.incremental);
849 zcu.deleteUnitExports(anal_unit);
850 zcu.deleteUnitReferences(anal_unit);
851 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
852 kv.value.destroy(gpa);
853 }
854 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
855 }
856
857 if (!func_outdated) {
858 // We can trust the current information about this function.
859 if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) {
860 return error.AnalysisFail;
861 }
862 switch (func.analysisUnordered(ip).state) {
863 .unreferenced => {}, // this is the first reference
864 .queued => {}, // we're waiting on first-time analysis
865 .analyzed => return .{ .ies_outdated = false }, // up-to-date
866 }
867 }
868
869 log.debug("analyze and generate fn body {}; reason='{s}'", .{
870 zcu.fmtAnalUnit(anal_unit),
871 if (func_outdated) "outdated" else "never analyzed",
872 });
1463 log.debug("analyze and generate fn body {}", .{zcu.fmtAnalUnit(anal_unit)});
8731464
874 var air = try pt.analyzeFnBody(func_index);
1465 var air = try pt.analyzeFnBodyInner(func_index);
8751466 errdefer air.deinit(gpa);
8761467
877 const ies_outdated = func_outdated and
878 (!func.analysisUnordered(ip).inferred_error_set or func.resolvedErrorSetUnordered(ip) != old_resolved_ies);
1468 const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or
1469 func.resolvedErrorSetUnordered(ip) != old_resolved_ies;
8791470
8801471 const comp = zcu.comp;
8811472
......@@ -1043,12 +1634,11 @@ fn createFileRootStruct(
10431634
10441635 wip_ty.setName(ip, try file.internFullyQualifiedName(pt));
10451636 ip.namespacePtr(namespace_index).owner_type = wip_ty.index;
1046 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, namespace_index, wip_ty.index);
10471637
10481638 if (zcu.comp.incremental) {
10491639 try ip.addDependency(
10501640 gpa,
1051 AnalUnit.wrap(.{ .cau = new_cau_index }),
1641 .wrap(.{ .type = wip_ty.index }),
10521642 .{ .src_hash = tracked_inst },
10531643 );
10541644 }
......@@ -1062,7 +1652,7 @@ fn createFileRootStruct(
10621652 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
10631653 }
10641654 zcu.setFileRootType(file_index, wip_ty.index);
1065 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
1655 return wip_ty.finish(ip, namespace_index);
10661656}
10671657
10681658/// Re-scan the namespace of a file's root struct type on an incremental update.
......@@ -1155,294 +1745,6 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
11551745 }
11561746}
11571747
1158const SemaCauResult = packed struct {
1159 /// Whether the value of a `decl_val` of the corresponding Nav changed.
1160 invalidate_decl_val: bool,
1161 /// Whether the type of a `decl_ref` of the corresponding Nav changed.
1162 invalidate_decl_ref: bool,
1163};
1164
1165/// Performs semantic analysis on the given `Cau`, storing results to its owner `Nav` if needed.
1166/// If analysis fails, returns `error.AnalysisFail`, storing an error in `zcu.failed_analysis` unless
1167/// the error is transitive.
1168/// On success, returns information about whether the `Nav` value changed.
1169fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
1170 const zcu = pt.zcu;
1171 const gpa = zcu.gpa;
1172 const ip = &zcu.intern_pool;
1173
1174 const anal_unit = AnalUnit.wrap(.{ .cau = cau_index });
1175
1176 const cau = ip.getCau(cau_index);
1177 const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1178 const file = zcu.fileByIndex(inst_info.file);
1179 const zir = file.zir;
1180
1181 if (file.status != .success_zir) {
1182 return error.AnalysisFail;
1183 }
1184
1185 // We are about to re-analyze this `Cau`; drop its depenndencies.
1186 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1187
1188 switch (cau.owner.unwrap()) {
1189 .none => {}, // `comptime` decl -- we will re-analyze its body.
1190 .nav => {}, // Other decl -- we will re-analyze its value.
1191 .type => |ty| {
1192 // This is an incremental update, and this type is being re-analyzed because it is outdated.
1193 // Create a new type in its place, and mark the old one as outdated so that use sites will
1194 // be re-analyzed and discover an up-to-date type.
1195 const new_ty = try pt.ensureTypeUpToDate(ty, true);
1196 assert(new_ty != ty);
1197 return .{
1198 .invalidate_decl_val = true,
1199 .invalidate_decl_ref = true,
1200 };
1201 },
1202 }
1203
1204 const is_usingnamespace = switch (cau.owner.unwrap()) {
1205 .nav => |nav| ip.getNav(nav).is_usingnamespace,
1206 .none, .type => false,
1207 };
1208
1209 log.debug("semaCau {}", .{zcu.fmtAnalUnit(anal_unit)});
1210
1211 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1212 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
1213
1214 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
1215 defer analysis_arena.deinit();
1216
1217 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
1218 defer comptime_err_ret_trace.deinit();
1219
1220 var sema: Sema = .{
1221 .pt = pt,
1222 .gpa = gpa,
1223 .arena = analysis_arena.allocator(),
1224 .code = zir,
1225 .owner = anal_unit,
1226 .func_index = .none,
1227 .func_is_naked = false,
1228 .fn_ret_ty = Type.void,
1229 .fn_ret_ty_ies = null,
1230 .comptime_err_ret_trace = &comptime_err_ret_trace,
1231 };
1232 defer sema.deinit();
1233
1234 // Every `Cau` has a dependency on the source of its own ZIR instruction.
1235 try sema.declareDependency(.{ .src_hash = cau.zir_index });
1236
1237 var block: Sema.Block = .{
1238 .parent = null,
1239 .sema = &sema,
1240 .namespace = cau.namespace,
1241 .instructions = .{},
1242 .inlining = null,
1243 .is_comptime = true,
1244 .src_base_inst = cau.zir_index,
1245 .type_name_ctx = switch (cau.owner.unwrap()) {
1246 .nav => |nav| ip.getNav(nav).fqn,
1247 .type => |ty| Type.fromInterned(ty).containerTypeName(ip),
1248 .none => try ip.getOrPutStringFmt(gpa, pt.tid, "{}.comptime", .{
1249 Type.fromInterned(zcu.namespacePtr(cau.namespace).owner_type).containerTypeName(ip).fmt(ip),
1250 }, .no_embedded_nulls),
1251 },
1252 };
1253 defer block.instructions.deinit(gpa);
1254
1255 const zir_decl: Zir.Inst.Declaration, const decl_bodies: Zir.Inst.Declaration.Bodies = decl: {
1256 const decl, const extra_end = zir.getDeclaration(inst_info.inst);
1257 break :decl .{ decl, decl.getBodies(extra_end, zir) };
1258 };
1259
1260 // We have to fetch this state before resolving the body because of the `nav_already_populated`
1261 // case below. We might change the language in future so that align/linksection/etc for functions
1262 // work in a way more in line with other declarations, in which case that logic will go away.
1263 const old_nav_info = switch (cau.owner.unwrap()) {
1264 .none, .type => undefined, // we'll never use `old_nav_info`
1265 .nav => |nav| ip.getNav(nav),
1266 };
1267
1268 const result_ref = try sema.resolveInlineBody(&block, decl_bodies.value_body, inst_info.inst);
1269
1270 const nav_index = switch (cau.owner.unwrap()) {
1271 .none => {
1272 // This is a `comptime` decl, so we are done -- the side effects are all we care about.
1273 // Just make sure to `flushExports`.
1274 try sema.flushExports();
1275 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1276 return .{
1277 .invalidate_decl_val = false,
1278 .invalidate_decl_ref = false,
1279 };
1280 },
1281 .nav => |nav| nav, // We will resolve this `Nav` below.
1282 .type => unreachable, // Handled at top of function.
1283 };
1284
1285 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
1286 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
1287 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
1288 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
1289 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
1290
1291 const decl_val = try sema.resolveFinalDeclValue(&block, init_src, result_ref);
1292 const decl_ty = decl_val.typeOf(zcu);
1293
1294 switch (decl_val.toIntern()) {
1295 .generic_poison => unreachable, // assertion failure
1296 .unreachable_value => unreachable, // assertion failure
1297 else => {},
1298 }
1299
1300 // This resolves the type of the resolved value, not that value itself. If `decl_val` is a struct type,
1301 // this resolves the type `type` (which needs no resolution), not the struct itself.
1302 try decl_ty.resolveLayout(pt);
1303
1304 // TODO: this is jank. If #20663 is rejected, let's think about how to better model `usingnamespace`.
1305 if (is_usingnamespace) {
1306 if (decl_ty.toIntern() != .type_type) {
1307 return sema.fail(&block, ty_src, "expected type, found {}", .{decl_ty.fmt(pt)});
1308 }
1309 if (decl_val.toType().getNamespace(zcu) == .none) {
1310 return sema.fail(&block, ty_src, "type {} has no namespace", .{decl_val.toType().fmt(pt)});
1311 }
1312 ip.resolveNavValue(nav_index, .{
1313 .val = decl_val.toIntern(),
1314 .alignment = .none,
1315 .@"linksection" = .none,
1316 .@"addrspace" = .generic,
1317 });
1318 // TODO: usingnamespace cannot participate in incremental compilation
1319 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1320 return .{
1321 .invalidate_decl_val = true,
1322 .invalidate_decl_ref = true,
1323 };
1324 }
1325
1326 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(decl_val.toIntern())) {
1327 .func => |f| .{ true, f.owner_nav == nav_index }, // note that this lets function aliases reach codegen
1328 .variable => |v| .{ v.owner_nav == nav_index, false },
1329 .@"extern" => |e| .{ false, Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn" },
1330 else => .{ true, false },
1331 };
1332
1333 // Keep in sync with logic in `Sema.zirVarExtended`.
1334 const alignment: InternPool.Alignment = a: {
1335 const align_body = decl_bodies.align_body orelse break :a .none;
1336 const align_ref = try sema.resolveInlineBody(&block, align_body, inst_info.inst);
1337 break :a try sema.analyzeAsAlign(&block, align_src, align_ref);
1338 };
1339
1340 const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
1341 const linksection_body = decl_bodies.linksection_body orelse break :ls .none;
1342 const linksection_ref = try sema.resolveInlineBody(&block, linksection_body, inst_info.inst);
1343 const bytes = try sema.toConstString(&block, section_src, linksection_ref, .{
1344 .needed_comptime_reason = "linksection must be comptime-known",
1345 });
1346 if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
1347 return sema.fail(&block, section_src, "linksection cannot contain null bytes", .{});
1348 } else if (bytes.len == 0) {
1349 return sema.fail(&block, section_src, "linksection cannot be empty", .{});
1350 }
1351 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
1352 };
1353
1354 const @"addrspace": std.builtin.AddressSpace = as: {
1355 const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_val.toIntern())) {
1356 .func => .function,
1357 .variable => .variable,
1358 .@"extern" => |e| if (ip.indexToKey(e.ty) == .func_type)
1359 .function
1360 else
1361 .variable,
1362 else => .constant,
1363 };
1364 const target = zcu.getTarget();
1365 const addrspace_body = decl_bodies.addrspace_body orelse break :as switch (addrspace_ctx) {
1366 .function => target_util.defaultAddressSpace(target, .function),
1367 .variable => target_util.defaultAddressSpace(target, .global_mutable),
1368 .constant => target_util.defaultAddressSpace(target, .global_constant),
1369 else => unreachable,
1370 };
1371 const addrspace_ref = try sema.resolveInlineBody(&block, addrspace_body, inst_info.inst);
1372 break :as try sema.analyzeAsAddressSpace(&block, addrspace_src, addrspace_ref, addrspace_ctx);
1373 };
1374
1375 if (is_owned_fn) {
1376 // linksection etc are legal, except some targets do not support function alignment.
1377 if (decl_bodies.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
1378 return sema.fail(&block, align_src, "target does not support function alignment", .{});
1379 }
1380 } else if (try decl_ty.comptimeOnlySema(pt)) {
1381 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.
1382 const reason: []const u8 = switch (ip.indexToKey(decl_val.toIntern())) {
1383 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
1384 else => "comptime-only type",
1385 };
1386 if (decl_bodies.align_body != null) {
1387 return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});
1388 }
1389 if (decl_bodies.linksection_body != null) {
1390 return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});
1391 }
1392 if (decl_bodies.addrspace_body != null) {
1393 return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});
1394 }
1395 }
1396
1397 ip.resolveNavValue(nav_index, .{
1398 .val = decl_val.toIntern(),
1399 .alignment = alignment,
1400 .@"linksection" = @"linksection",
1401 .@"addrspace" = @"addrspace",
1402 });
1403
1404 // Mark the `Cau` as completed before evaluating the export!
1405 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1406
1407 if (zir_decl.flags.is_export) {
1408 const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.flags.is_pub) });
1409 const name_slice = zir.nullTerminatedString(zir_decl.name.toString(zir).?);
1410 const name_ip = try ip.getOrPutString(gpa, pt.tid, name_slice, .no_embedded_nulls);
1411 try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_index);
1412 }
1413
1414 try sema.flushExports();
1415
1416 queue_codegen: {
1417 if (!queue_linker_work) break :queue_codegen;
1418
1419 if (!try decl_ty.hasRuntimeBitsSema(pt)) {
1420 if (zcu.comp.config.use_llvm) break :queue_codegen;
1421 if (file.mod.strip) break :queue_codegen;
1422 }
1423
1424 // This job depends on any resolve_type_fully jobs queued up before it.
1425 try zcu.comp.queueJob(.{ .codegen_nav = nav_index });
1426 }
1427
1428 switch (old_nav_info.status) {
1429 .unresolved => return .{
1430 .invalidate_decl_val = true,
1431 .invalidate_decl_ref = true,
1432 },
1433 .resolved => |old| {
1434 const new = ip.getNav(nav_index).status.resolved;
1435 return .{
1436 .invalidate_decl_val = new.val != old.val,
1437 .invalidate_decl_ref = ip.typeOf(new.val) != ip.typeOf(old.val) or
1438 new.alignment != old.alignment or
1439 new.@"linksection" != old.@"linksection" or
1440 new.@"addrspace" != old.@"addrspace",
1441 };
1442 },
1443 }
1444}
1445
14461748pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
14471749 const zcu = pt.zcu;
14481750 const gpa = zcu.gpa;
......@@ -1813,45 +2115,42 @@ pub fn scanNamespace(
18132115
18142116 // For incremental updates, `scanDecl` wants to look up existing decls by their ZIR index rather
18152117 // than their name. We'll build an efficient mapping now, then discard the current `decls`.
1816 // We map to the `Cau`, since not every declaration has a `Nav`.
1817 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.Cau.Index) = .empty;
2118 // We map to the `AnalUnit`, since not every declaration has a `Nav`.
2119 var existing_by_inst: std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.AnalUnit) = .empty;
18182120 defer existing_by_inst.deinit(gpa);
18192121
18202122 try existing_by_inst.ensureTotalCapacity(gpa, @intCast(
18212123 namespace.pub_decls.count() + namespace.priv_decls.count() +
18222124 namespace.pub_usingnamespace.items.len + namespace.priv_usingnamespace.items.len +
1823 namespace.other_decls.items.len,
2125 namespace.comptime_decls.items.len +
2126 namespace.test_decls.items.len,
18242127 ));
18252128
18262129 for (namespace.pub_decls.keys()) |nav| {
1827 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1828 const zir_index = ip.getCau(cau_index).zir_index;
1829 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
2130 const zir_index = ip.getNav(nav).analysis.?.zir_index;
2131 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
18302132 }
18312133 for (namespace.priv_decls.keys()) |nav| {
1832 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1833 const zir_index = ip.getCau(cau_index).zir_index;
1834 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
2134 const zir_index = ip.getNav(nav).analysis.?.zir_index;
2135 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
18352136 }
18362137 for (namespace.pub_usingnamespace.items) |nav| {
1837 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1838 const zir_index = ip.getCau(cau_index).zir_index;
1839 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
2138 const zir_index = ip.getNav(nav).analysis.?.zir_index;
2139 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
18402140 }
18412141 for (namespace.priv_usingnamespace.items) |nav| {
1842 const cau_index = ip.getNav(nav).analysis_owner.unwrap().?;
1843 const zir_index = ip.getCau(cau_index).zir_index;
1844 existing_by_inst.putAssumeCapacityNoClobber(zir_index, cau_index);
1845 }
1846 for (namespace.other_decls.items) |cau_index| {
1847 const cau = ip.getCau(cau_index);
1848 existing_by_inst.putAssumeCapacityNoClobber(cau.zir_index, cau_index);
1849 // If this is a test, it'll be re-added to `test_functions` later on
1850 // if still alive. Remove it for now.
1851 switch (cau.owner.unwrap()) {
1852 .none, .type => {},
1853 .nav => |nav| _ = zcu.test_functions.swapRemove(nav),
1854 }
2142 const zir_index = ip.getNav(nav).analysis.?.zir_index;
2143 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
2144 }
2145 for (namespace.comptime_decls.items) |cu| {
2146 const zir_index = ip.getComptimeUnit(cu).zir_index;
2147 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .@"comptime" = cu }));
2148 }
2149 for (namespace.test_decls.items) |nav| {
2150 const zir_index = ip.getNav(nav).analysis.?.zir_index;
2151 existing_by_inst.putAssumeCapacityNoClobber(zir_index, .wrap(.{ .nav_val = nav }));
2152 // This test will be re-added to `test_functions` later on if it's still alive. Remove it for now.
2153 _ = zcu.test_functions.swapRemove(nav);
18552154 }
18562155
18572156 var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;
......@@ -1861,7 +2160,8 @@ pub fn scanNamespace(
18612160 namespace.priv_decls.clearRetainingCapacity();
18622161 namespace.pub_usingnamespace.clearRetainingCapacity();
18632162 namespace.priv_usingnamespace.clearRetainingCapacity();
1864 namespace.other_decls.clearRetainingCapacity();
2163 namespace.comptime_decls.clearRetainingCapacity();
2164 namespace.test_decls.clearRetainingCapacity();
18652165
18662166 var scan_decl_iter: ScanDeclIter = .{
18672167 .pt = pt,
......@@ -1883,7 +2183,7 @@ const ScanDeclIter = struct {
18832183 pt: Zcu.PerThread,
18842184 namespace_index: Zcu.Namespace.Index,
18852185 seen_decls: *std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
1886 existing_by_inst: *const std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.Cau.Index),
2186 existing_by_inst: *const std.AutoHashMapUnmanaged(InternPool.TrackedInst.Index, InternPool.AnalUnit),
18872187 /// Decl scanning is run in two passes, so that we can detect when a generated
18882188 /// name would clash with an explicit name and use a different one.
18892189 pass: enum { named, unnamed },
......@@ -1919,64 +2219,41 @@ const ScanDeclIter = struct {
19192219 const zir = file.zir;
19202220 const ip = &zcu.intern_pool;
19212221
1922 const inst_data = zir.instructions.items(.data)[@intFromEnum(decl_inst)].declaration;
1923 const extra = zir.extraData(Zir.Inst.Declaration, inst_data.payload_index);
1924 const declaration = extra.data;
2222 const decl = zir.getDeclaration(decl_inst);
19252223
1926 const Kind = enum { @"comptime", @"usingnamespace", @"test", named };
1927
1928 const maybe_name: InternPool.OptionalNullTerminatedString, const kind: Kind, const is_named_test: bool = switch (declaration.name) {
1929 .@"comptime" => info: {
2224 const maybe_name: InternPool.OptionalNullTerminatedString = switch (decl.kind) {
2225 .@"comptime" => name: {
19302226 if (iter.pass != .unnamed) return;
1931 break :info .{
1932 .none,
1933 .@"comptime",
1934 false,
1935 };
2227 break :name .none;
19362228 },
1937 .@"usingnamespace" => info: {
2229 .@"usingnamespace" => name: {
19382230 if (iter.pass != .unnamed) return;
19392231 const i = iter.usingnamespace_index;
19402232 iter.usingnamespace_index += 1;
1941 break :info .{
1942 (try iter.avoidNameConflict("usingnamespace_{d}", .{i})).toOptional(),
1943 .@"usingnamespace",
1944 false,
1945 };
2233 break :name (try iter.avoidNameConflict("usingnamespace_{d}", .{i})).toOptional();
19462234 },
1947 .unnamed_test => info: {
2235 .unnamed_test => name: {
19482236 if (iter.pass != .unnamed) return;
19492237 const i = iter.unnamed_test_index;
19502238 iter.unnamed_test_index += 1;
1951 break :info .{
1952 (try iter.avoidNameConflict("test_{d}", .{i})).toOptional(),
1953 .@"test",
1954 false,
1955 };
2239 break :name (try iter.avoidNameConflict("test_{d}", .{i})).toOptional();
19562240 },
1957 _ => if (declaration.name.isNamedTest(zir)) info: {
2241 .@"test", .decltest => |kind| name: {
19582242 // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
19592243 if (iter.pass != .unnamed) return;
1960 const prefix = if (declaration.flags.test_is_decltest) "decltest" else "test";
1961 break :info .{
1962 (try iter.avoidNameConflict("{s}.{s}", .{ prefix, zir.nullTerminatedString(declaration.name.toString(zir).?) })).toOptional(),
1963 .@"test",
1964 true,
1965 };
1966 } else info: {
2244 const prefix = @tagName(kind);
2245 break :name (try iter.avoidNameConflict("{s}.{s}", .{ prefix, zir.nullTerminatedString(decl.name) })).toOptional();
2246 },
2247 .@"const", .@"var" => name: {
19672248 if (iter.pass != .named) return;
19682249 const name = try ip.getOrPutString(
19692250 gpa,
19702251 pt.tid,
1971 zir.nullTerminatedString(declaration.name.toString(zir).?),
2252 zir.nullTerminatedString(decl.name),
19722253 .no_embedded_nulls,
19732254 );
19742255 try iter.seen_decls.putNoClobber(gpa, name, {});
1975 break :info .{
1976 name.toOptional(),
1977 .named,
1978 false,
1979 };
2256 break :name name.toOptional();
19802257 },
19812258 };
19822259
......@@ -1985,60 +2262,59 @@ const ScanDeclIter = struct {
19852262 .inst = decl_inst,
19862263 });
19872264
1988 const existing_cau = iter.existing_by_inst.get(tracked_inst);
2265 const existing_unit = iter.existing_by_inst.get(tracked_inst);
2266
2267 const unit, const want_analysis = switch (decl.kind) {
2268 .@"comptime" => unit: {
2269 const cu = if (existing_unit) |eu|
2270 eu.unwrap().@"comptime"
2271 else
2272 try ip.createComptimeUnit(gpa, pt.tid, tracked_inst, namespace_index);
19892273
1990 const cau, const want_analysis = switch (kind) {
1991 .@"comptime" => cau: {
1992 const cau = existing_cau orelse try ip.createComptimeCau(gpa, pt.tid, tracked_inst, namespace_index);
2274 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
19932275
1994 try namespace.other_decls.append(gpa, cau);
2276 try namespace.comptime_decls.append(gpa, cu);
19952277
1996 if (existing_cau == null) {
1997 // For a `comptime` declaration, whether to analyze is based solely on whether the
1998 // `Cau` is outdated. So, add this one to `outdated` and `outdated_ready` if not already.
1999 const unit = AnalUnit.wrap(.{ .cau = cau });
2000 if (zcu.potentially_outdated.fetchSwapRemove(unit)) |kv| {
2001 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2002 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2003 zcu.outdated.putAssumeCapacityNoClobber(unit, kv.value);
2004 if (kv.value == 0) { // no PO deps
2005 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
2006 }
2007 } else if (!zcu.outdated.contains(unit)) {
2008 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2009 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2010 zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
2011 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
2012 }
2278 if (existing_unit == null) {
2279 // For a `comptime` declaration, whether to analyze is based solely on whether the unit
2280 // is outdated. So, add this fresh one to `outdated` and `outdated_ready`.
2281 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
2282 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
2283 zcu.outdated.putAssumeCapacityNoClobber(unit, 0);
2284 zcu.outdated_ready.putAssumeCapacityNoClobber(unit, {});
20132285 }
20142286
2015 break :cau .{ cau, true };
2287 break :unit .{ unit, true };
20162288 },
2017 else => cau: {
2289 else => unit: {
20182290 const name = maybe_name.unwrap().?;
20192291 const fqn = try namespace.internFullyQualifiedName(ip, gpa, pt.tid, name);
2020 const cau, const nav = if (existing_cau) |cau_index| cau_nav: {
2021 const nav_index = ip.getCau(cau_index).owner.unwrap().nav;
2022 const nav = ip.getNav(nav_index);
2023 assert(nav.name == name);
2024 assert(nav.fqn == fqn);
2025 break :cau_nav .{ cau_index, nav_index };
2026 } else try ip.createPairedCauNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index, kind == .@"usingnamespace");
2027 const want_analysis = switch (kind) {
2292 const nav = if (existing_unit) |eu|
2293 eu.unwrap().nav_val
2294 else
2295 try ip.createDeclNav(gpa, pt.tid, name, fqn, tracked_inst, namespace_index, decl.kind == .@"usingnamespace");
2296
2297 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
2298
2299 assert(ip.getNav(nav).name == name);
2300 assert(ip.getNav(nav).fqn == fqn);
2301
2302 const want_analysis = switch (decl.kind) {
20282303 .@"comptime" => unreachable,
20292304 .@"usingnamespace" => a: {
20302305 if (comp.incremental) {
20312306 @panic("'usingnamespace' is not supported by incremental compilation");
20322307 }
2033 if (declaration.flags.is_pub) {
2308 if (decl.is_pub) {
20342309 try namespace.pub_usingnamespace.append(gpa, nav);
20352310 } else {
20362311 try namespace.priv_usingnamespace.append(gpa, nav);
20372312 }
20382313 break :a true;
20392314 },
2040 .@"test" => a: {
2041 try namespace.other_decls.append(gpa, cau);
2315 .unnamed_test, .@"test", .decltest => a: {
2316 const is_named = decl.kind != .unnamed_test;
2317 try namespace.test_decls.append(gpa, nav);
20422318 // TODO: incremental compilation!
20432319 // * remove from `test_functions` if no longer matching filter
20442320 // * add to `test_functions` if newly passing filter
......@@ -2046,7 +2322,7 @@ const ScanDeclIter = struct {
20462322 // Perhaps we should add all test indiscriminately and filter at the end of the update.
20472323 if (!comp.config.is_test) break :a false;
20482324 if (file.mod != zcu.main_mod) break :a false;
2049 if (is_named_test and comp.test_filters.len > 0) {
2325 if (is_named and comp.test_filters.len > 0) {
20502326 const fqn_slice = fqn.toSlice(ip);
20512327 for (comp.test_filters) |test_filter| {
20522328 if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
......@@ -2055,8 +2331,8 @@ const ScanDeclIter = struct {
20552331 try zcu.test_functions.put(gpa, nav, {});
20562332 break :a true;
20572333 },
2058 .named => a: {
2059 if (declaration.flags.is_pub) {
2334 .@"const", .@"var" => a: {
2335 if (decl.is_pub) {
20602336 try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
20612337 } else {
20622338 try namespace.priv_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
......@@ -2064,23 +2340,23 @@ const ScanDeclIter = struct {
20642340 break :a false;
20652341 },
20662342 };
2067 break :cau .{ cau, want_analysis };
2343 break :unit .{ unit, want_analysis };
20682344 },
20692345 };
20702346
2071 if (existing_cau == null and (want_analysis or declaration.flags.is_export)) {
2347 if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) {
20722348 log.debug(
2073 "scanDecl queue analyze_cau file='{s}' cau_index={d}",
2074 .{ namespace.fileScope(zcu).sub_file_path, cau },
2349 "scanDecl queue analyze_comptime_unit file='{s}' unit={}",
2350 .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) },
20752351 );
2076 try comp.queueJob(.{ .analyze_cau = cau });
2352 try comp.queueJob(.{ .analyze_comptime_unit = unit });
20772353 }
20782354
20792355 // TODO: we used to do line number updates here, but this is an inappropriate place for this logic to live.
20802356 }
20812357};
20822358
2083fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {
2359fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {
20842360 const tracy = trace(@src());
20852361 defer tracy.end();
20862362
......@@ -2097,26 +2373,19 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
20972373 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
20982374 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
20992375
2100 func.setAnalysisState(ip, .analyzed);
2376 func.setAnalyzed(ip);
21012377 if (func.analysisUnordered(ip).inferred_error_set) {
21022378 func.setResolvedErrorSet(ip, .none);
21032379 }
21042380
2105 // This is the `Cau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
2106 const decl_cau = ip.getCau(cau: {
2107 const orig_nav = if (func.generic_owner == .none)
2108 func.owner_nav
2109 else
2110 zcu.funcInfo(func.generic_owner).owner_nav;
2111
2112 break :cau ip.getNav(orig_nav).analysis_owner.unwrap().?;
2113 });
2381 // This is the `Nau` corresponding to the `declaration` instruction which the function or its generic owner originates from.
2382 const decl_nav = ip.getNav(if (func.generic_owner == .none)
2383 func.owner_nav
2384 else
2385 zcu.funcInfo(func.generic_owner).owner_nav);
21142386
21152387 const func_nav = ip.getNav(func.owner_nav);
21162388
2117 const decl_prog_node = zcu.sema_prog_node.start(func_nav.fqn.toSlice(ip), 0);
2118 defer decl_prog_node.end();
2119
21202389 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
21212390
21222391 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
......@@ -2150,7 +2419,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
21502419
21512420 // Every runtime function has a dependency on the source of the Decl it originates from.
21522421 // It also depends on the value of its owner Decl.
2153 try sema.declareDependency(.{ .src_hash = decl_cau.zir_index });
2422 try sema.declareDependency(.{ .src_hash = decl_nav.analysis.?.zir_index });
21542423 try sema.declareDependency(.{ .nav_val = func.owner_nav });
21552424
21562425 if (func.analysisUnordered(ip).inferred_error_set) {
......@@ -2170,11 +2439,11 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
21702439 var inner_block: Sema.Block = .{
21712440 .parent = null,
21722441 .sema = &sema,
2173 .namespace = decl_cau.namespace,
2442 .namespace = decl_nav.analysis.?.namespace,
21742443 .instructions = .{},
21752444 .inlining = null,
21762445 .is_comptime = false,
2177 .src_base_inst = decl_cau.zir_index,
2446 .src_base_inst = decl_nav.analysis.?.zir_index,
21782447 .type_name_ctx = func_nav.fqn,
21792448 };
21802449 defer inner_block.instructions.deinit(gpa);
......@@ -2476,14 +2745,14 @@ fn processExportsInner(
24762745 .nav => |nav_index| if (failed: {
24772746 const nav = ip.getNav(nav_index);
24782747 if (zcu.failed_codegen.contains(nav_index)) break :failed true;
2479 if (nav.analysis_owner.unwrap()) |cau| {
2480 const cau_unit = AnalUnit.wrap(.{ .cau = cau });
2481 if (zcu.failed_analysis.contains(cau_unit)) break :failed true;
2482 if (zcu.transitive_failed_analysis.contains(cau_unit)) break :failed true;
2748 if (nav.analysis != null) {
2749 const unit: AnalUnit = .wrap(.{ .nav_val = nav_index });
2750 if (zcu.failed_analysis.contains(unit)) break :failed true;
2751 if (zcu.transitive_failed_analysis.contains(unit)) break :failed true;
24832752 }
24842753 const val = switch (nav.status) {
2485 .unresolved => break :failed true,
2486 .resolved => |r| Value.fromInterned(r.val),
2754 .unresolved, .type_resolved => break :failed true,
2755 .fully_resolved => |r| Value.fromInterned(r.val),
24872756 };
24882757 // If the value is a function, we also need to check if that function succeeded analysis.
24892758 if (val.typeOf(zcu).zigTypeTag(zcu) == .@"fn") {
......@@ -2527,15 +2796,14 @@ pub fn populateTestFunctions(
25272796 Zcu.Namespace.NameAdapter{ .zcu = zcu },
25282797 ).?;
25292798 {
2530 // We have to call `ensureCauAnalyzed` here in case `builtin.test_functions`
2799 // We have to call `ensureNavValUpToDate` here in case `builtin.test_functions`
25312800 // was not referenced by start code.
25322801 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
25332802 defer {
25342803 zcu.sema_prog_node.end();
25352804 zcu.sema_prog_node = std.Progress.Node.none;
25362805 }
2537 const cau_index = ip.getNav(nav_index).analysis_owner.unwrap().?;
2538 pt.ensureCauAnalyzed(cau_index) catch |err| switch (err) {
2806 pt.ensureNavValUpToDate(nav_index) catch |err| switch (err) {
25392807 error.AnalysisFail => return,
25402808 error.OutOfMemory => return error.OutOfMemory,
25412809 };
......@@ -2556,8 +2824,7 @@ pub fn populateTestFunctions(
25562824 {
25572825 // The test declaration might have failed; if that's the case, just return, as we'll
25582826 // be emitting a compile error anyway.
2559 const cau = test_nav.analysis_owner.unwrap().?;
2560 const anal_unit: AnalUnit = .wrap(.{ .cau = cau });
2827 const anal_unit: AnalUnit = .wrap(.{ .nav_val = test_nav_index });
25612828 if (zcu.failed_analysis.contains(anal_unit) or
25622829 zcu.transitive_failed_analysis.contains(anal_unit))
25632830 {
......@@ -2682,8 +2949,8 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error
26822949 "unable to codegen: {s}",
26832950 .{@errorName(err)},
26842951 ));
2685 if (nav.analysis_owner.unwrap()) |cau| {
2686 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .cau = cau }));
2952 if (nav.analysis != null) {
2953 try zcu.retryable_failures.append(zcu.gpa, .wrap(.{ .nav_val = nav_index }));
26872954 } else {
26882955 // TODO: we don't have a way to indicate that this failure is retryable!
26892956 // Since these are really rare, we could as a cop-out retry the whole build next update.
......@@ -3189,31 +3456,30 @@ pub fn getBuiltinNav(pt: Zcu.PerThread, name: []const u8) Allocator.Error!Intern
31893456 const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
31903457 const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
31913458 @panic("lib/std.zig is corrupt and missing 'builtin'");
3192 pt.ensureCauAnalyzed(ip.getNav(builtin_nav).analysis_owner.unwrap().?) catch @panic("std.builtin is corrupt");
3193 const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.resolved.val);
3459 pt.ensureNavValUpToDate(builtin_nav) catch @panic("std.builtin is corrupt");
3460 const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.fully_resolved.val);
31943461 const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt"));
31953462 const name_str = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
31963463 return builtin_namespace.pub_decls.getKeyAdapted(name_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt");
31973464}
31983465
3199pub fn navPtrType(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Allocator.Error!Type {
3466pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
32003467 const zcu = pt.zcu;
32013468 const ip = &zcu.intern_pool;
3202 const r = ip.getNav(nav_index).status.resolved;
3203 const ty = Value.fromInterned(r.val).typeOf(zcu);
3469 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
3470 .unresolved => unreachable,
3471 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
3472 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
3473 };
32043474 return pt.ptrType(.{
3205 .child = ty.toIntern(),
3475 .child = ty,
32063476 .flags = .{
3207 .alignment = if (r.alignment == ty.abiAlignment(zcu))
3477 .alignment = if (alignment == Type.fromInterned(ty).abiAlignment(zcu))
32083478 .none
32093479 else
3210 r.alignment,
3211 .address_space = r.@"addrspace",
3212 .is_const = switch (ip.indexToKey(r.val)) {
3213 .variable => false,
3214 .@"extern" => |e| e.is_const,
3215 else => true,
3216 },
3480 alignment,
3481 .address_space = @"addrspace",
3482 .is_const = is_const,
32173483 },
32183484 });
32193485}
......@@ -3233,76 +3499,57 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
32333499// TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`.
32343500pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPool.Alignment {
32353501 const zcu = pt.zcu;
3236 const r = zcu.intern_pool.getNav(nav_index).status.resolved;
3237 if (r.alignment != .none) return r.alignment;
3238 return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(zcu);
3502 const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
3503 .unresolved => unreachable,
3504 .type_resolved => |r| .{ .fromInterned(r.type), r.alignment },
3505 .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment },
3506 };
3507 if (alignment != .none) return alignment;
3508 return ty.abiAlignment(zcu);
32393509}
32403510
32413511/// Given a container type requiring resolution, ensures that it is up-to-date.
32423512/// If not, the type is recreated at a new `InternPool.Index`.
32433513/// The new index is returned. This is the same as the old index if the fields were up-to-date.
3244/// If `already_updating` is set, assumes the type is already outdated and undergoing re-analysis rather than checking `zcu.outdated`.
3245pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index {
3514pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index {
32463515 const zcu = pt.zcu;
3516 const gpa = zcu.gpa;
32473517 const ip = &zcu.intern_pool;
3518
3519 const anal_unit: AnalUnit = .wrap(.{ .type = ty });
3520 const outdated = zcu.outdated.swapRemove(anal_unit) or
3521 zcu.potentially_outdated.swapRemove(anal_unit);
3522
3523 if (!outdated) return ty;
3524
3525 // We will recreate the type at a new `InternPool.Index`.
3526
3527 _ = zcu.outdated_ready.swapRemove(anal_unit);
3528 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3529
3530 // Delete old state which is no longer in use. Technically, this is not necessary: these exports,
3531 // references, etc, will be ignored because the type itself is unreferenced. However, it allows
3532 // reusing the memory which is currently being used to track this state.
3533 zcu.deleteUnitExports(anal_unit);
3534 zcu.deleteUnitReferences(anal_unit);
3535 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
3536 kv.value.destroy(gpa);
3537 }
3538 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
3539 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
3540
32483541 switch (ip.indexToKey(ty)) {
3249 .struct_type => |key| {
3250 const struct_obj = ip.loadStructType(ty);
3251 const outdated = already_updating or o: {
3252 const anal_unit = AnalUnit.wrap(.{ .cau = struct_obj.cau });
3253 const o = zcu.outdated.swapRemove(anal_unit) or
3254 zcu.potentially_outdated.swapRemove(anal_unit);
3255 if (o) {
3256 _ = zcu.outdated_ready.swapRemove(anal_unit);
3257 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3258 }
3259 break :o o;
3260 };
3261 if (!outdated) return ty;
3262 return pt.recreateStructType(key, struct_obj);
3263 },
3264 .union_type => |key| {
3265 const union_obj = ip.loadUnionType(ty);
3266 const outdated = already_updating or o: {
3267 const anal_unit = AnalUnit.wrap(.{ .cau = union_obj.cau });
3268 const o = zcu.outdated.swapRemove(anal_unit) or
3269 zcu.potentially_outdated.swapRemove(anal_unit);
3270 if (o) {
3271 _ = zcu.outdated_ready.swapRemove(anal_unit);
3272 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3273 }
3274 break :o o;
3275 };
3276 if (!outdated) return ty;
3277 return pt.recreateUnionType(key, union_obj);
3278 },
3279 .enum_type => |key| {
3280 const enum_obj = ip.loadEnumType(ty);
3281 const outdated = already_updating or o: {
3282 const anal_unit = AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? });
3283 const o = zcu.outdated.swapRemove(anal_unit) or
3284 zcu.potentially_outdated.swapRemove(anal_unit);
3285 if (o) {
3286 _ = zcu.outdated_ready.swapRemove(anal_unit);
3287 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
3288 }
3289 break :o o;
3290 };
3291 if (!outdated) return ty;
3292 return pt.recreateEnumType(key, enum_obj);
3293 },
3294 .opaque_type => {
3295 assert(!already_updating);
3296 return ty;
3297 },
3542 .struct_type => |key| return pt.recreateStructType(ty, key),
3543 .union_type => |key| return pt.recreateUnionType(ty, key),
3544 .enum_type => |key| return pt.recreateEnumType(ty, key),
32983545 else => unreachable,
32993546 }
33003547}
33013548
33023549fn recreateStructType(
33033550 pt: Zcu.PerThread,
3551 old_ty: InternPool.Index,
33043552 full_key: InternPool.Key.NamespaceType,
3305 struct_obj: InternPool.LoadedStructType,
33063553) Zcu.SemaError!InternPool.Index {
33073554 const zcu = pt.zcu;
33083555 const gpa = zcu.gpa;
......@@ -3339,8 +3586,7 @@ fn recreateStructType(
33393586
33403587 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
33413588
3342 // The old type will be unused, so drop its dependency information.
3343 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = struct_obj.cau }));
3589 const struct_obj = ip.loadStructType(old_ty);
33443590
33453591 const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{
33463592 .layout = small.layout,
......@@ -3362,17 +3608,16 @@ fn recreateStructType(
33623608 errdefer wip_ty.cancel(ip, pt.tid);
33633609
33643610 wip_ty.setName(ip, struct_obj.name);
3365 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, struct_obj.namespace, wip_ty.index);
33663611 try ip.addDependency(
33673612 gpa,
3368 AnalUnit.wrap(.{ .cau = new_cau_index }),
3613 .wrap(.{ .type = wip_ty.index }),
33693614 .{ .src_hash = key.zir_index },
33703615 );
33713616 zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index;
33723617 // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive.
33733618 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
33743619
3375 const new_ty = wip_ty.finish(ip, new_cau_index.toOptional(), struct_obj.namespace);
3620 const new_ty = wip_ty.finish(ip, struct_obj.namespace);
33763621 if (inst_info.inst == .main_struct_inst) {
33773622 // This is the root type of a file! Update the reference.
33783623 zcu.setFileRootType(inst_info.file, new_ty);
......@@ -3382,8 +3627,8 @@ fn recreateStructType(
33823627
33833628fn recreateUnionType(
33843629 pt: Zcu.PerThread,
3630 old_ty: InternPool.Index,
33853631 full_key: InternPool.Key.NamespaceType,
3386 union_obj: InternPool.LoadedUnionType,
33873632) Zcu.SemaError!InternPool.Index {
33883633 const zcu = pt.zcu;
33893634 const gpa = zcu.gpa;
......@@ -3422,8 +3667,7 @@ fn recreateUnionType(
34223667
34233668 if (captures_len != key.captures.owned.len) return error.AnalysisFail;
34243669
3425 // The old type will be unused, so drop its dependency information.
3426 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = union_obj.cau }));
3670 const union_obj = ip.loadUnionType(old_ty);
34273671
34283672 const namespace_index = union_obj.namespace;
34293673
......@@ -3460,22 +3704,21 @@ fn recreateUnionType(
34603704 errdefer wip_ty.cancel(ip, pt.tid);
34613705
34623706 wip_ty.setName(ip, union_obj.name);
3463 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
34643707 try ip.addDependency(
34653708 gpa,
3466 AnalUnit.wrap(.{ .cau = new_cau_index }),
3709 .wrap(.{ .type = wip_ty.index }),
34673710 .{ .src_hash = key.zir_index },
34683711 );
34693712 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
34703713 // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive.
34713714 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3472 return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
3715 return wip_ty.finish(ip, namespace_index);
34733716}
34743717
34753718fn recreateEnumType(
34763719 pt: Zcu.PerThread,
3720 old_ty: InternPool.Index,
34773721 full_key: InternPool.Key.NamespaceType,
3478 enum_obj: InternPool.LoadedEnumType,
34793722) Zcu.SemaError!InternPool.Index {
34803723 const zcu = pt.zcu;
34813724 const gpa = zcu.gpa;
......@@ -3544,8 +3787,7 @@ fn recreateEnumType(
35443787 if (bag != 0) break true;
35453788 } else false;
35463789
3547 // The old type will be unused, so drop its dependency information.
3548 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .cau = enum_obj.cau.unwrap().? }));
3790 const enum_obj = ip.loadEnumType(old_ty);
35493791
35503792 const namespace_index = enum_obj.namespace;
35513793
......@@ -3571,12 +3813,10 @@ fn recreateEnumType(
35713813
35723814 wip_ty.setName(ip, enum_obj.name);
35733815
3574 const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index);
3575
35763816 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
35773817 // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive.
35783818
3579 wip_ty.prepare(ip, new_cau_index, namespace_index);
3819 wip_ty.prepare(ip, namespace_index);
35803820 done = true;
35813821
35823822 Sema.resolveDeclaredEnum(
......@@ -3586,7 +3826,6 @@ fn recreateEnumType(
35863826 key.zir_index,
35873827 namespace_index,
35883828 enum_obj.name,
3589 new_cau_index,
35903829 small,
35913830 body,
35923831 tag_type_ref,
src/arch/wasm/CodeGen.zig+1-9
......@@ -3218,15 +3218,7 @@ fn lowerNavRef(func: *CodeGen, nav_index: InternPool.Nav.Index, offset: u32) Inn
32183218 const zcu = pt.zcu;
32193219 const ip = &zcu.intern_pool;
32203220
3221 // check if decl is an alias to a function, in which case we
3222 // want to lower the actual decl, rather than the alias itself.
3223 const owner_nav = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
3224 .func => |function| function.owner_nav,
3225 .variable => |variable| variable.owner_nav,
3226 .@"extern" => |@"extern"| @"extern".owner_nav,
3227 else => nav_index,
3228 };
3229 const nav_ty = ip.getNav(owner_nav).typeOf(ip);
3221 const nav_ty = ip.getNav(nav_index).typeOf(ip);
32303222 if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) {
32313223 return .{ .imm32 = 0xaaaaaaaa };
32323224 }
src/codegen.zig+9-8
......@@ -817,7 +817,7 @@ fn genNavRef(
817817 pt: Zcu.PerThread,
818818 src_loc: Zcu.LazySrcLoc,
819819 val: Value,
820 ref_nav_index: InternPool.Nav.Index,
820 nav_index: InternPool.Nav.Index,
821821 target: std.Target,
822822) CodeGenError!GenResult {
823823 const zcu = pt.zcu;
......@@ -851,14 +851,15 @@ fn genNavRef(
851851 }
852852 }
853853
854 const nav_index, const is_extern, const lib_name, const is_threadlocal = switch (ip.indexToKey(zcu.navValue(ref_nav_index).toIntern())) {
855 .func => |func| .{ func.owner_nav, false, .none, false },
856 .variable => |variable| .{ variable.owner_nav, false, variable.lib_name, variable.is_threadlocal },
857 .@"extern" => |@"extern"| .{ @"extern".owner_nav, true, @"extern".lib_name, @"extern".is_threadlocal },
858 else => .{ ref_nav_index, false, .none, false },
859 };
854 const nav = ip.getNav(nav_index);
855
856 const is_extern, const lib_name, const is_threadlocal = if (nav.getExtern(ip)) |e|
857 .{ true, e.lib_name, e.is_threadlocal }
858 else
859 .{ false, .none, nav.isThreadlocal(ip) };
860
860861 const single_threaded = zcu.navFileScope(nav_index).mod.single_threaded;
861 const name = ip.getNav(nav_index).name;
862 const name = nav.name;
862863 if (lf.cast(.elf)) |elf_file| {
863864 const zo = elf_file.zigObjectPtr().?;
864865 if (is_extern) {
src/codegen/c.zig+32-29
......@@ -770,11 +770,14 @@ pub const DeclGen = struct {
770770 const ctype_pool = &dg.ctype_pool;
771771
772772 // Chase function values in order to be able to reference the original function.
773 const owner_nav = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
774 .variable => |variable| variable.owner_nav,
775 .func => |func| func.owner_nav,
776 .@"extern" => |@"extern"| @"extern".owner_nav,
777 else => nav_index,
773 const owner_nav = switch (ip.getNav(nav_index).status) {
774 .unresolved => unreachable,
775 .type_resolved => nav_index, // this can't be an extern or a function
776 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
777 .func => |f| f.owner_nav,
778 .@"extern" => |e| e.owner_nav,
779 else => nav_index,
780 },
778781 };
779782
780783 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
......@@ -2237,7 +2240,7 @@ pub const DeclGen = struct {
22372240 Type.fromInterned(nav.typeOf(ip)),
22382241 .{ .nav = nav_index },
22392242 CQualifiers.init(.{ .@"const" = flags.is_const }),
2240 nav.status.resolved.alignment,
2243 nav.getAlignment(),
22412244 .complete,
22422245 );
22432246 try fwd.writeAll(";\n");
......@@ -2246,19 +2249,19 @@ pub const DeclGen = struct {
22462249 fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {
22472250 const zcu = dg.pt.zcu;
22482251 const ip = &zcu.intern_pool;
2249 switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
2250 .@"extern" => |@"extern"| try writer.print("{ }", .{
2252 const nav = ip.getNav(nav_index);
2253 if (nav.getExtern(ip)) |@"extern"| {
2254 try writer.print("{ }", .{
22512255 fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
2252 }),
2253 else => {
2254 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
2255 // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
2256 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
2257 try writer.print("{}__{d}", .{
2258 fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
2259 @intFromEnum(nav_index),
2260 });
2261 },
2256 });
2257 } else {
2258 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
2259 // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
2260 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
2261 try writer.print("{}__{d}", .{
2262 fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
2263 @intFromEnum(nav_index),
2264 });
22622265 }
22632266 }
22642267
......@@ -2826,7 +2829,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
28262829
28272830 const fwd = o.dg.fwdDeclWriter();
28282831 try fwd.print("static zig_{s} ", .{@tagName(key)});
2829 try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).status.resolved.alignment, .forward, .{
2832 try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).getAlignment(), .forward, .{
28302833 .fmt_ctype_pool_string = fn_name,
28312834 });
28322835 try fwd.writeAll(";\n");
......@@ -2867,13 +2870,13 @@ pub fn genFunc(f: *Function) !void {
28672870 try o.dg.renderFunctionSignature(
28682871 fwd,
28692872 nav_val,
2870 nav.status.resolved.alignment,
2873 nav.status.fully_resolved.alignment,
28712874 .forward,
28722875 .{ .nav = nav_index },
28732876 );
28742877 try fwd.writeAll(";\n");
28752878
2876 if (nav.status.resolved.@"linksection".toSlice(ip)) |s|
2879 if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
28772880 try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
28782881 try o.dg.renderFunctionSignature(
28792882 o.writer(),
......@@ -2952,7 +2955,7 @@ pub fn genDecl(o: *Object) !void {
29522955 const nav_ty = Type.fromInterned(nav.typeOf(ip));
29532956
29542957 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
2955 switch (ip.indexToKey(nav.status.resolved.val)) {
2958 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
29562959 .@"extern" => |@"extern"| {
29572960 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
29582961 .is_extern = true,
......@@ -2965,8 +2968,8 @@ pub fn genDecl(o: *Object) !void {
29652968 try fwd.writeAll("zig_extern ");
29662969 try o.dg.renderFunctionSignature(
29672970 fwd,
2968 Value.fromInterned(nav.status.resolved.val),
2969 nav.status.resolved.alignment,
2971 Value.fromInterned(nav.status.fully_resolved.val),
2972 nav.status.fully_resolved.alignment,
29702973 .forward,
29712974 .{ .@"export" = .{
29722975 .main_name = nav.name,
......@@ -2985,14 +2988,14 @@ pub fn genDecl(o: *Object) !void {
29852988 const w = o.writer();
29862989 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
29872990 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
2988 if (nav.status.resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
2991 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
29892992 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
29902993 try o.dg.renderTypeAndName(
29912994 w,
29922995 nav_ty,
29932996 .{ .nav = o.dg.pass.nav },
29942997 .{},
2995 nav.status.resolved.alignment,
2998 nav.status.fully_resolved.alignment,
29962999 .complete,
29973000 );
29983001 try w.writeAll(" = ");
......@@ -3002,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
30023005 },
30033006 else => try genDeclValue(
30043007 o,
3005 Value.fromInterned(nav.status.resolved.val),
3008 Value.fromInterned(nav.status.fully_resolved.val),
30063009 .{ .nav = o.dg.pass.nav },
3007 nav.status.resolved.alignment,
3008 nav.status.resolved.@"linksection",
3010 nav.status.fully_resolved.alignment,
3011 nav.status.fully_resolved.@"linksection",
30093012 ),
30103013 }
30113014}
src/codegen/llvm.zig+29-38
......@@ -1476,7 +1476,7 @@ pub const Object = struct {
14761476 } }, &o.builder);
14771477 }
14781478
1479 if (nav.status.resolved.@"linksection".toSlice(ip)) |section|
1479 if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |section|
14801480 function_index.setSection(try o.builder.string(section), &o.builder);
14811481
14821482 var deinit_wip = true;
......@@ -1684,7 +1684,7 @@ pub const Object = struct {
16841684 const file = try o.getDebugFile(file_scope);
16851685
16861686 const line_number = zcu.navSrcLine(func.owner_nav) + 1;
1687 const is_internal_linkage = ip.indexToKey(nav.status.resolved.val) != .@"extern";
1687 const is_internal_linkage = ip.indexToKey(nav.status.fully_resolved.val) != .@"extern";
16881688 const debug_decl_type = try o.lowerDebugType(fn_ty);
16891689
16901690 const subprogram = try o.builder.debugSubprogram(
......@@ -2928,9 +2928,7 @@ pub const Object = struct {
29282928 const gpa = o.gpa;
29292929 const nav = ip.getNav(nav_index);
29302930 const owner_mod = zcu.navFileScope(nav_index).mod;
2931 const resolved = nav.status.resolved;
2932 const val = Value.fromInterned(resolved.val);
2933 const ty = val.typeOf(zcu);
2931 const ty: Type = .fromInterned(nav.typeOf(ip));
29342932 const gop = try o.nav_map.getOrPut(gpa, nav_index);
29352933 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
29362934
......@@ -2938,15 +2936,14 @@ pub const Object = struct {
29382936 const target = owner_mod.resolved_target.result;
29392937 const sret = firstParamSRet(fn_info, zcu, target);
29402938
2941 const is_extern, const lib_name = switch (ip.indexToKey(val.toIntern())) {
2942 .variable => |variable| .{ false, variable.lib_name },
2943 .@"extern" => |@"extern"| .{ true, @"extern".lib_name },
2944 else => .{ false, .none },
2945 };
2939 const is_extern, const lib_name = if (nav.getExtern(ip)) |@"extern"|
2940 .{ true, @"extern".lib_name }
2941 else
2942 .{ false, .none };
29462943 const function_index = try o.builder.addFunction(
29472944 try o.lowerType(ty),
29482945 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
2949 toLlvmAddressSpace(resolved.@"addrspace", target),
2946 toLlvmAddressSpace(nav.getAddrspace(), target),
29502947 );
29512948 gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
29522949
......@@ -3064,8 +3061,8 @@ pub const Object = struct {
30643061 }
30653062 }
30663063
3067 if (resolved.alignment != .none)
3068 function_index.setAlignment(resolved.alignment.toLlvm(), &o.builder);
3064 if (nav.getAlignment() != .none)
3065 function_index.setAlignment(nav.getAlignment().toLlvm(), &o.builder);
30693066
30703067 // Function attributes that are independent of analysis results of the function body.
30713068 try o.addCommonFnAttributes(
......@@ -3250,17 +3247,21 @@ pub const Object = struct {
32503247 const zcu = pt.zcu;
32513248 const ip = &zcu.intern_pool;
32523249 const nav = ip.getNav(nav_index);
3253 const resolved = nav.status.resolved;
3254 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (ip.indexToKey(resolved.val)) {
3255 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
3256 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
3257 else => .{ false, false, false, false },
3250 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
3251 .unresolved => unreachable,
3252 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
3253 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
3254 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
3255 else => .{ false, false, false, false },
3256 },
3257 // This means it's a source declaration which is not `extern`!
3258 .type_resolved => |r| .{ false, r.is_threadlocal, false, false },
32583259 };
32593260
32603261 const variable_index = try o.builder.addVariable(
32613262 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
32623263 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
3263 toLlvmGlobalAddressSpace(resolved.@"addrspace", zcu.getTarget()),
3264 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
32643265 );
32653266 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
32663267
......@@ -4529,20 +4530,10 @@ pub const Object = struct {
45294530 const zcu = pt.zcu;
45304531 const ip = &zcu.intern_pool;
45314532
4532 // In the case of something like:
4533 // fn foo() void {}
4534 // const bar = foo;
4535 // ... &bar;
4536 // `bar` is just an alias and we actually want to lower a reference to `foo`.
4537 const owner_nav_index = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
4538 .func => |func| func.owner_nav,
4539 .@"extern" => |@"extern"| @"extern".owner_nav,
4540 else => nav_index,
4541 };
4542 const owner_nav = ip.getNav(owner_nav_index);
4533 const nav = ip.getNav(nav_index);
45434534
4544 const nav_ty = Type.fromInterned(owner_nav.typeOf(ip));
4545 const ptr_ty = try pt.navPtrType(owner_nav_index);
4535 const nav_ty = Type.fromInterned(nav.typeOf(ip));
4536 const ptr_ty = try pt.navPtrType(nav_index);
45464537
45474538 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
45484539 if ((!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) or
......@@ -4552,13 +4543,13 @@ pub const Object = struct {
45524543 }
45534544
45544545 const llvm_global = if (is_fn_body)
4555 (try o.resolveLlvmFunction(owner_nav_index)).ptrConst(&o.builder).global
4546 (try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global
45564547 else
4557 (try o.resolveGlobalNav(owner_nav_index)).ptrConst(&o.builder).global;
4548 (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global;
45584549
45594550 const llvm_val = try o.builder.convConst(
45604551 llvm_global.toConst(),
4561 try o.builder.ptrType(toLlvmAddressSpace(owner_nav.status.resolved.@"addrspace", zcu.getTarget())),
4552 try o.builder.ptrType(toLlvmAddressSpace(nav.getAddrspace(), zcu.getTarget())),
45624553 );
45634554
45644555 return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty));
......@@ -4800,10 +4791,10 @@ pub const NavGen = struct {
48004791 const ip = &zcu.intern_pool;
48014792 const nav_index = ng.nav_index;
48024793 const nav = ip.getNav(nav_index);
4803 const resolved = nav.status.resolved;
4794 const resolved = nav.status.fully_resolved;
48044795
48054796 const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
4806 .variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
4797 .variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
48074798 .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
48084799 else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
48094800 };
......@@ -5766,7 +5757,7 @@ pub const FuncGen = struct {
57665757 const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?;
57675758 const msg_nav = ip.getNav(msg_nav_index);
57685759 const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu);
5769 const msg_ptr = try o.lowerValue(msg_nav.status.resolved.val);
5760 const msg_ptr = try o.lowerValue(msg_nav.status.fully_resolved.val);
57705761 const null_opt_addr_global = try fg.resolveNullOptUsize();
57715762 const target = zcu.getTarget();
57725763 const llvm_usize = try o.lowerType(Type.usize);
src/codegen/spirv.zig+16-13
......@@ -268,7 +268,7 @@ pub const Object = struct {
268268 // TODO: Extern fn?
269269 const kind: SpvModule.Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip)))
270270 .func
271 else switch (nav.status.resolved.@"addrspace") {
271 else switch (nav.getAddrspace()) {
272272 .generic => .invocation_global,
273273 else => .global,
274274 };
......@@ -1279,17 +1279,20 @@ const NavGen = struct {
12791279 const ip = &zcu.intern_pool;
12801280 const ty_id = try self.resolveType(ty, .direct);
12811281 const nav = ip.getNav(nav_index);
1282 const nav_val = zcu.navValue(nav_index);
1283 const nav_ty = nav_val.typeOf(zcu);
1284
1285 switch (ip.indexToKey(nav_val.toIntern())) {
1286 .func => {
1287 // TODO: Properly lower function pointers. For now we are going to hack around it and
1288 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1289 return try self.spv.constUndef(ty_id);
1282 const nav_ty: Type = .fromInterned(nav.typeOf(ip));
1283
1284 switch (nav.status) {
1285 .unresolved => unreachable,
1286 .type_resolved => {}, // this is not a function or extern
1287 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
1288 .func => {
1289 // TODO: Properly lower function pointers. For now we are going to hack around it and
1290 // just generate an empty pointer. Function pointers are represented by a pointer to usize.
1291 return try self.spv.constUndef(ty_id);
1292 },
1293 .@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) @panic("TODO"),
1294 else => {},
12901295 },
1291 .@"extern" => assert(!ip.isFunctionType(nav_ty.toIntern())), // TODO
1292 else => {},
12931296 }
12941297
12951298 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
......@@ -1305,7 +1308,7 @@ const NavGen = struct {
13051308 .global, .invocation_global => spv_decl.result_id,
13061309 };
13071310
1308 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
1311 const storage_class = self.spvStorageClass(nav.getAddrspace());
13091312 try self.addFunctionDep(spv_decl_index, storage_class);
13101313
13111314 const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class);
......@@ -3182,7 +3185,7 @@ const NavGen = struct {
31823185 };
31833186 assert(maybe_init_val == null); // TODO
31843187
3185 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
3188 const storage_class = self.spvStorageClass(nav.getAddrspace());
31863189 assert(storage_class != .Generic); // These should be instance globals
31873190
31883191 const ptr_ty_id = try self.ptrType(ty, storage_class);
src/link.zig+1-1
......@@ -692,7 +692,7 @@ pub const File = struct {
692692 /// May be called before or after updateExports for any given Nav.
693693 pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
694694 const nav = pt.zcu.intern_pool.getNav(nav_index);
695 assert(nav.status == .resolved);
695 assert(nav.status == .fully_resolved);
696696 switch (base.tag) {
697697 inline else => |tag| {
698698 dev.check(tag.devFeature());
src/link/C.zig+9-11
......@@ -217,7 +217,7 @@ pub fn updateFunc(
217217 .mod = zcu.navFileScope(func.owner_nav).mod,
218218 .error_msg = null,
219219 .pass = .{ .nav = func.owner_nav },
220 .is_naked_fn = zcu.navValue(func.owner_nav).typeOf(zcu).fnCallingConvention(zcu) == .naked,
220 .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
221221 .fwd_decl = fwd_decl.toManaged(gpa),
222222 .ctype_pool = ctype_pool.*,
223223 .scratch = .{},
......@@ -320,11 +320,11 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !
320320 const ip = &zcu.intern_pool;
321321
322322 const nav = ip.getNav(nav_index);
323 const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
323 const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
324324 .func => return,
325325 .@"extern" => .none,
326326 .variable => |variable| variable.init,
327 else => nav.status.resolved.val,
327 else => nav.status.fully_resolved.val,
328328 };
329329 if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) return;
330330
......@@ -499,7 +499,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
499499 av_block,
500500 self.exported_navs.getPtr(nav),
501501 export_names,
502 if (ip.indexToKey(zcu.navValue(nav).toIntern()) == .@"extern")
502 if (ip.getNav(nav).getExtern(ip) != null)
503503 ip.getNav(nav).name.toOptional()
504504 else
505505 .none,
......@@ -544,13 +544,11 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
544544 },
545545 self.getString(av_block.code),
546546 );
547 for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(
548 if (self.exported_navs.contains(nav)) .default else switch (ip.indexToKey(zcu.navValue(nav).toIntern())) {
549 .@"extern" => .zig_extern,
550 else => .static,
551 },
552 self.getString(av_block.code),
553 );
547 for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(storage: {
548 if (self.exported_navs.contains(nav)) break :storage .default;
549 if (ip.getNav(nav).getExtern(ip) != null) break :storage .zig_extern;
550 break :storage .static;
551 }, self.getString(av_block.code));
554552
555553 const file = self.base.file.?;
556554 try file.setEndPos(f.file_size);
src/link/Coff.zig+11-6
......@@ -1110,6 +1110,8 @@ pub fn updateFunc(coff: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
11101110 const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav);
11111111 coff.freeRelocations(atom_index);
11121112
1113 coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?;
1114
11131115 var code_buffer = std.ArrayList(u8).init(gpa);
11141116 defer code_buffer.deinit();
11151117
......@@ -1223,6 +1225,8 @@ pub fn updateNav(
12231225 coff.freeRelocations(atom_index);
12241226 const atom = coff.getAtom(atom_index);
12251227
1228 coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index);
1229
12261230 var code_buffer = std.ArrayList(u8).init(gpa);
12271231 defer code_buffer.deinit();
12281232
......@@ -1342,7 +1346,8 @@ pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom
13421346 if (!gop.found_existing) {
13431347 gop.value_ptr.* = .{
13441348 .atom = try coff.createAtom(),
1345 .section = coff.getNavOutputSection(nav_index),
1349 // If necessary, this will be modified by `updateNav` or `updateFunc`.
1350 .section = coff.rdata_section_index.?,
13461351 .exports = .{},
13471352 };
13481353 }
......@@ -1355,7 +1360,7 @@ fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 {
13551360 const nav = ip.getNav(nav_index);
13561361 const ty = Type.fromInterned(nav.typeOf(ip));
13571362 const zig_ty = ty.zigTypeTag(zcu);
1358 const val = Value.fromInterned(nav.status.resolved.val);
1363 const val = Value.fromInterned(nav.status.fully_resolved.val);
13591364 const index: u16 = blk: {
13601365 if (val.isUndefDeep(zcu)) {
13611366 // TODO in release-fast and release-small, we should put undef in .bss
......@@ -2348,10 +2353,10 @@ pub fn getNavVAddr(
23482353 const ip = &zcu.intern_pool;
23492354 const nav = ip.getNav(nav_index);
23502355 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
2351 const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
2352 .@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
2353 else => coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
2354 };
2356 const sym_index = if (nav.getExtern(ip)) |e|
2357 try coff.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip))
2358 else
2359 coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?;
23552360 const atom_index = coff.getAtomIndexForSymbol(.{
23562361 .sym_index = reloc_info.parent.atom_index,
23572362 .file = null,
src/link/Dwarf.zig+25-61
......@@ -2259,24 +2259,13 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
22592259 switch (ip.indexToKey(nav_val.toIntern())) {
22602260 else => {
22612261 assert(file.zir_loaded);
2262 const decl = file.zir.getDeclaration(inst_info.inst)[0];
2262 const decl = file.zir.getDeclaration(inst_info.inst);
22632263
2264 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2265 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2264 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2265 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
22662266 break :parent .{
22672267 parent_namespace_ptr.owner_type,
2268 switch (decl.name) {
2269 .@"comptime",
2270 .@"usingnamespace",
2271 .unnamed_test,
2272 => DW.ACCESS.private,
2273 _ => if (decl.name.isNamedTest(file.zir))
2274 DW.ACCESS.private
2275 else if (decl.flags.is_pub)
2276 DW.ACCESS.public
2277 else
2278 DW.ACCESS.private,
2279 },
2268 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
22802269 };
22812270 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
22822271
......@@ -2292,7 +2281,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
22922281 const nav_ty = nav_val.typeOf(zcu);
22932282 const nav_ty_reloc_index = try wip_nav.refForward();
22942283 try wip_nav.infoExprloc(.{ .addr = .{ .sym = sym_index } });
2295 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
2284 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
22962285 nav_ty.abiAlignment(zcu).toByteUnits().?);
22972286 try diw.writeByte(@intFromBool(false));
22982287 wip_nav.finishForward(nav_ty_reloc_index);
......@@ -2301,24 +2290,13 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
23012290 },
23022291 .variable => |variable| {
23032292 assert(file.zir_loaded);
2304 const decl = file.zir.getDeclaration(inst_info.inst)[0];
2293 const decl = file.zir.getDeclaration(inst_info.inst);
23052294
2306 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2307 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2295 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2296 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
23082297 break :parent .{
23092298 parent_namespace_ptr.owner_type,
2310 switch (decl.name) {
2311 .@"comptime",
2312 .@"usingnamespace",
2313 .unnamed_test,
2314 => DW.ACCESS.private,
2315 _ => if (decl.name.isNamedTest(file.zir))
2316 DW.ACCESS.private
2317 else if (decl.flags.is_pub)
2318 DW.ACCESS.public
2319 else
2320 DW.ACCESS.private,
2321 },
2299 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
23222300 };
23232301 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
23242302
......@@ -2335,30 +2313,19 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
23352313 try wip_nav.refType(ty);
23362314 const addr: Loc = .{ .addr = .{ .sym = sym_index } };
23372315 try wip_nav.infoExprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
2338 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
2316 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
23392317 ty.abiAlignment(zcu).toByteUnits().?);
23402318 try diw.writeByte(@intFromBool(false));
23412319 },
23422320 .func => |func| {
23432321 assert(file.zir_loaded);
2344 const decl = file.zir.getDeclaration(inst_info.inst)[0];
2322 const decl = file.zir.getDeclaration(inst_info.inst);
23452323
2346 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2347 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2324 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2325 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
23482326 break :parent .{
23492327 parent_namespace_ptr.owner_type,
2350 switch (decl.name) {
2351 .@"comptime",
2352 .@"usingnamespace",
2353 .unnamed_test,
2354 => DW.ACCESS.private,
2355 _ => if (decl.name.isNamedTest(file.zir))
2356 DW.ACCESS.private
2357 else if (decl.flags.is_pub)
2358 DW.ACCESS.public
2359 else
2360 DW.ACCESS.private,
2361 },
2328 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
23622329 };
23632330 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
23642331
......@@ -2421,7 +2388,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
24212388 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
24222389 try diw.writeInt(u32, 0, dwarf.endian);
24232390 const target = file.mod.resolved_target.result;
2424 try uleb128(diw, switch (nav.status.resolved.alignment) {
2391 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
24252392 .none => target_info.defaultFunctionAlignment(target),
24262393 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
24272394 }.toByteUnits().?);
......@@ -2585,23 +2552,22 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
25852552 const inst_info = nav.srcInst(ip).resolveFull(ip).?;
25862553 const file = zcu.fileByIndex(inst_info.file);
25872554 assert(file.zir_loaded);
2588 const decl = file.zir.getDeclaration(inst_info.inst)[0];
2555 const decl = file.zir.getDeclaration(inst_info.inst);
25892556
2590 const is_test = switch (decl.name) {
2591 .unnamed_test => true,
2592 .@"comptime", .@"usingnamespace" => false,
2593 _ => decl.name.isNamedTest(file.zir),
2557 const is_test = switch (decl.kind) {
2558 .unnamed_test, .@"test", .decltest => true,
2559 .@"comptime", .@"usingnamespace", .@"const", .@"var" => false,
25942560 };
25952561 if (is_test) {
25962562 // This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime.
25972563 return;
25982564 }
25992565
2600 const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
2601 const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
2566 const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
2567 const parent_namespace_ptr = ip.namespacePtr(a.namespace);
26022568 break :parent .{
26032569 parent_namespace_ptr.owner_type,
2604 if (decl.flags.is_pub) DW.ACCESS.public else DW.ACCESS.private,
2570 if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
26052571 };
26062572 } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
26072573
......@@ -2986,7 +2952,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
29862952 const nav_ty = nav_val.typeOf(zcu);
29872953 try wip_nav.refType(nav_ty);
29882954 try wip_nav.blockValue(nav_src_loc, nav_val);
2989 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
2955 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
29902956 nav_ty.abiAlignment(zcu).toByteUnits().?);
29912957 try diw.writeByte(@intFromBool(false));
29922958 },
......@@ -3011,7 +2977,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
30112977 try wip_nav.strp(nav.name.toSlice(ip));
30122978 try wip_nav.strp(nav.fqn.toSlice(ip));
30132979 const nav_ty_reloc_index = try wip_nav.refForward();
3014 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
2980 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
30152981 nav_ty.abiAlignment(zcu).toByteUnits().?);
30162982 try diw.writeByte(@intFromBool(false));
30172983 if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val);
......@@ -4198,9 +4164,7 @@ pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.I
41984164 assert(inst_info.inst != .main_struct_inst);
41994165 const file = zcu.fileByIndex(inst_info.file);
42004166
4201 const inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
4202 assert(inst.tag == .declaration);
4203 const line = file.zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
4167 const line = file.zir.getDeclaration(inst_info.inst).src_line;
42044168 var line_buf: [4]u8 = undefined;
42054169 std.mem.writeInt(u32, &line_buf, line, dwarf.endian);
42064170
src/link/Elf/ZigObject.zig+10-15
......@@ -925,14 +925,11 @@ pub fn getNavVAddr(
925925 const ip = &zcu.intern_pool;
926926 const nav = ip.getNav(nav_index);
927927 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
928 const this_sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
929 .@"extern" => |@"extern"| try self.getGlobalSymbol(
930 elf_file,
931 nav.name.toSlice(ip),
932 @"extern".lib_name.toSlice(ip),
933 ),
934 else => try self.getOrCreateMetadataForNav(zcu, nav_index),
935 };
928 const this_sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
929 elf_file,
930 nav.name.toSlice(ip),
931 @"extern".lib_name.toSlice(ip),
932 ) else try self.getOrCreateMetadataForNav(zcu, nav_index);
936933 const this_sym = self.symbol(this_sym_index);
937934 const vaddr = this_sym.address(.{}, elf_file);
938935 switch (reloc_info.parent) {
......@@ -1107,15 +1104,13 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index
11071104
11081105pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
11091106 const gpa = zcu.gpa;
1107 const ip = &zcu.intern_pool;
11101108 const gop = try self.navs.getOrPut(gpa, nav_index);
11111109 if (!gop.found_existing) {
11121110 const symbol_index = try self.newSymbolWithAtom(gpa, 0);
1113 const nav_val = Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
11141111 const sym = self.symbol(symbol_index);
1115 if (nav_val.getVariable(zcu)) |variable| {
1116 if (variable.is_threadlocal and zcu.comp.config.any_non_single_threaded) {
1117 sym.flags.is_tls = true;
1118 }
1112 if (ip.getNav(nav_index).isThreadlocal(ip) and zcu.comp.config.any_non_single_threaded) {
1113 sym.flags.is_tls = true;
11191114 }
11201115 gop.value_ptr.* = .{ .symbol_index = symbol_index };
11211116 }
......@@ -1547,7 +1542,7 @@ pub fn updateNav(
15471542
15481543 log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
15491544
1550 const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
1545 const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
15511546 .func => .none,
15521547 .variable => |variable| variable.init,
15531548 .@"extern" => |@"extern"| {
......@@ -1560,7 +1555,7 @@ pub fn updateNav(
15601555 self.symbol(sym_index).flags.is_extern_ptr = true;
15611556 return;
15621557 },
1563 else => nav.status.resolved.val,
1558 else => nav.status.fully_resolved.val,
15641559 };
15651560
15661561 if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
src/link/MachO/ZigObject.zig+8-15
......@@ -608,14 +608,11 @@ pub fn getNavVAddr(
608608 const ip = &zcu.intern_pool;
609609 const nav = ip.getNav(nav_index);
610610 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
611 const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
612 .@"extern" => |@"extern"| try self.getGlobalSymbol(
613 macho_file,
614 nav.name.toSlice(ip),
615 @"extern".lib_name.toSlice(ip),
616 ),
617 else => try self.getOrCreateMetadataForNav(macho_file, nav_index),
618 };
611 const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
612 macho_file,
613 nav.name.toSlice(ip),
614 @"extern".lib_name.toSlice(ip),
615 ) else try self.getOrCreateMetadataForNav(macho_file, nav_index);
619616 const sym = self.symbols.items[sym_index];
620617 const vaddr = sym.getAddress(.{}, macho_file);
621618 switch (reloc_info.parent) {
......@@ -882,7 +879,7 @@ pub fn updateNav(
882879 const ip = &zcu.intern_pool;
883880 const nav = ip.getNav(nav_index);
884881
885 const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
882 const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
886883 .func => .none,
887884 .variable => |variable| variable.init,
888885 .@"extern" => |@"extern"| {
......@@ -895,7 +892,7 @@ pub fn updateNav(
895892 sym.flags.is_extern_ptr = true;
896893 return;
897894 },
898 else => nav.status.resolved.val,
895 else => nav.status.fully_resolved.val,
899896 };
900897
901898 if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
......@@ -1561,11 +1558,7 @@ fn isThreadlocal(macho_file: *MachO, nav_index: InternPool.Nav.Index) bool {
15611558 if (!macho_file.base.comp.config.any_non_single_threaded)
15621559 return false;
15631560 const ip = &macho_file.base.comp.zcu.?.intern_pool;
1564 return switch (ip.indexToKey(ip.getNav(nav_index).status.resolved.val)) {
1565 .variable => |variable| variable.is_threadlocal,
1566 .@"extern" => |@"extern"| @"extern".is_threadlocal,
1567 else => false,
1568 };
1561 return ip.getNav(nav_index).isThreadlocal(ip);
15691562}
15701563
15711564fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
src/link/Plan9.zig+2-2
......@@ -1021,7 +1021,7 @@ pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
10211021 const atom_idx = gop.value_ptr.index;
10221022 // handle externs here because they might not get updateDecl called on them
10231023 const nav = ip.getNav(nav_index);
1024 if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
1024 if (nav.getExtern(ip) != null) {
10251025 // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs
10261026 if (nav.name.eqlSlice("etext", ip)) {
10271027 self.etext_edata_end_atom_indices[0] = atom_idx;
......@@ -1370,7 +1370,7 @@ pub fn getNavVAddr(
13701370 const ip = &pt.zcu.intern_pool;
13711371 const nav = ip.getNav(nav_index);
13721372 log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)});
1373 if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
1373 if (nav.getExtern(ip) != null) {
13741374 if (nav.name.eqlSlice("etext", ip)) {
13751375 try self.addReloc(reloc_info.parent.atom_index, .{
13761376 .target = undefined,
src/link/Wasm/ZigObject.zig+7-8
......@@ -241,7 +241,7 @@ pub fn updateNav(
241241
242242 const nav_val = zcu.navValue(nav_index);
243243 const is_extern, const lib_name, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
244 .variable => |variable| .{ false, variable.lib_name, Value.fromInterned(variable.init) },
244 .variable => |variable| .{ false, .none, Value.fromInterned(variable.init) },
245245 .func => return,
246246 .@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip)))
247247 return
......@@ -734,15 +734,14 @@ pub fn getNavVAddr(
734734 const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
735735 const target_atom = wasm.getAtom(target_atom_index);
736736 const target_symbol_index = @intFromEnum(target_atom.sym_index);
737 switch (ip.indexToKey(nav.status.resolved.val)) {
738 .@"extern" => |@"extern"| try zig_object.addOrUpdateImport(
737 if (nav.getExtern(ip)) |@"extern"| {
738 try zig_object.addOrUpdateImport(
739739 wasm,
740740 nav.name.toSlice(ip),
741741 target_atom.sym_index,
742742 @"extern".lib_name.toSlice(ip),
743743 null,
744 ),
745 else => {},
744 );
746745 }
747746
748747 std.debug.assert(reloc_info.parent.atom_index != 0);
......@@ -945,8 +944,8 @@ pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.In
945944 segment.name = &.{}; // Ensure no accidental double free
946945 }
947946
948 const nav_val = zcu.navValue(nav_index).toIntern();
949 if (ip.indexToKey(nav_val) == .@"extern") {
947 const nav = ip.getNav(nav_index);
948 if (nav.getExtern(ip) != null) {
950949 std.debug.assert(zig_object.imports.remove(atom.sym_index));
951950 }
952951 std.debug.assert(wasm.symbol_atom.remove(atom.symbolLoc()));
......@@ -960,7 +959,7 @@ pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.In
960959 if (sym.isGlobal()) {
961960 std.debug.assert(zig_object.global_syms.remove(atom.sym_index));
962961 }
963 if (ip.isFunctionType(ip.typeOf(nav_val))) {
962 if (ip.isFunctionType(nav.typeOf(ip))) {
964963 zig_object.functions_free_list.append(gpa, sym.index) catch {};
965964 std.debug.assert(zig_object.atom_types.remove(atom_index));
966965 } else {
src/print_zir.zig+29-69
......@@ -542,7 +542,6 @@ const Writer = struct {
542542
543543 .@"asm" => try self.writeAsm(stream, extended, false),
544544 .asm_expr => try self.writeAsm(stream, extended, true),
545 .variable => try self.writeVarExtended(stream, extended),
546545 .alloc => try self.writeAllocExtended(stream, extended),
547546
548547 .compile_log => try self.writeNodeMultiOp(stream, extended),
......@@ -2347,7 +2346,6 @@ const Writer = struct {
23472346 inferred_error_set,
23482347 false,
23492348 false,
2350 false,
23512349
23522350 .none,
23532351 &.{},
......@@ -2371,13 +2369,6 @@ const Writer = struct {
23712369 var ret_ty_ref: Zir.Inst.Ref = .none;
23722370 var ret_ty_body: []const Zir.Inst.Index = &.{};
23732371
2374 if (extra.data.bits.has_lib_name) {
2375 const lib_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
2376 extra_index += 1;
2377 try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)});
2378 }
2379 try self.writeFlag(stream, "test, ", extra.data.bits.is_test);
2380
23812372 if (extra.data.bits.has_cc_body) {
23822373 const body_len = self.code.extra[extra_index];
23832374 extra_index += 1;
......@@ -2414,7 +2405,6 @@ const Writer = struct {
24142405 stream,
24152406 extra.data.bits.is_inferred_error,
24162407 extra.data.bits.is_var_args,
2417 extra.data.bits.is_extern,
24182408 extra.data.bits.is_noinline,
24192409 cc_ref,
24202410 cc_body,
......@@ -2427,36 +2417,6 @@ const Writer = struct {
24272417 );
24282418 }
24292419
2430 fn writeVarExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
2431 const extra = self.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
2432 const small = @as(Zir.Inst.ExtendedVar.Small, @bitCast(extended.small));
2433
2434 try self.writeInstRef(stream, extra.data.var_type);
2435
2436 var extra_index: usize = extra.end;
2437 if (small.has_lib_name) {
2438 const lib_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
2439 const lib_name = self.code.nullTerminatedString(lib_name_index);
2440 extra_index += 1;
2441 try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)});
2442 }
2443 const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: {
2444 const align_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
2445 extra_index += 1;
2446 break :blk align_inst;
2447 };
2448 const init_inst: Zir.Inst.Ref = if (!small.has_init) .none else blk: {
2449 const init_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
2450 extra_index += 1;
2451 break :blk init_inst;
2452 };
2453 try self.writeFlag(stream, ", is_extern", small.is_extern);
2454 try self.writeFlag(stream, ", is_threadlocal", small.is_threadlocal);
2455 try self.writeOptionalInstRef(stream, ", align=", align_inst);
2456 try self.writeOptionalInstRef(stream, ", init=", init_inst);
2457 try stream.writeAll("))");
2458 }
2459
24602420 fn writeAllocExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
24612421 const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand);
24622422 const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small));
......@@ -2604,7 +2564,6 @@ const Writer = struct {
26042564 stream: anytype,
26052565 inferred_error_set: bool,
26062566 var_args: bool,
2607 is_extern: bool,
26082567 is_noinline: bool,
26092568 cc_ref: Zir.Inst.Ref,
26102569 cc_body: []const Zir.Inst.Index,
......@@ -2618,7 +2577,6 @@ const Writer = struct {
26182577 try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body);
26192578 try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body);
26202579 try self.writeFlag(stream, "vargs, ", var_args);
2621 try self.writeFlag(stream, "extern, ", is_extern);
26222580 try self.writeFlag(stream, "inferror, ", inferred_error_set);
26232581 try self.writeFlag(stream, "noinline, ", is_noinline);
26242582
......@@ -2664,56 +2622,58 @@ const Writer = struct {
26642622 }
26652623
26662624 fn writeDeclaration(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2667 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].declaration;
2668 const extra = self.code.extraData(Zir.Inst.Declaration, inst_data.payload_index);
2625 const decl = self.code.getDeclaration(inst);
26692626
26702627 const prev_parent_decl_node = self.parent_decl_node;
26712628 defer self.parent_decl_node = prev_parent_decl_node;
2672 self.parent_decl_node = inst_data.src_node;
2629 self.parent_decl_node = decl.src_node;
26732630
2674 if (extra.data.flags.is_pub) try stream.writeAll("pub ");
2675 if (extra.data.flags.is_export) try stream.writeAll("export ");
2676 switch (extra.data.name) {
2631 if (decl.is_pub) try stream.writeAll("pub ");
2632 switch (decl.linkage) {
2633 .normal => {},
2634 .@"export" => try stream.writeAll("export "),
2635 .@"extern" => try stream.writeAll("extern "),
2636 }
2637 switch (decl.kind) {
26772638 .@"comptime" => try stream.writeAll("comptime"),
26782639 .@"usingnamespace" => try stream.writeAll("usingnamespace"),
26792640 .unnamed_test => try stream.writeAll("test"),
2680 _ => {
2681 const name = extra.data.name.toString(self.code).?;
2682 const prefix = if (extra.data.name.isNamedTest(self.code)) p: {
2683 break :p if (extra.data.flags.test_is_decltest) "decltest " else "test ";
2684 } else "";
2685 try stream.print("{s}'{s}'", .{ prefix, self.code.nullTerminatedString(name) });
2641 .@"test", .decltest, .@"const", .@"var" => {
2642 try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });
26862643 },
26872644 }
2688 const src_hash_arr: [4]u32 = .{
2689 extra.data.src_hash_0,
2690 extra.data.src_hash_1,
2691 extra.data.src_hash_2,
2692 extra.data.src_hash_3,
2693 };
2694 const src_hash_bytes: [16]u8 = @bitCast(src_hash_arr);
2695 try stream.print(" line({d}) hash({})", .{ extra.data.src_line, std.fmt.fmtSliceHexLower(&src_hash_bytes) });
2645 const src_hash = self.code.getAssociatedSrcHash(inst).?;
2646 try stream.print(" line({d}) column({d}) hash({})", .{
2647 decl.src_line,
2648 decl.src_column,
2649 std.fmt.fmtSliceHexLower(&src_hash),
2650 });
26962651
26972652 {
2698 const bodies = extra.data.getBodies(@intCast(extra.end), self.code);
2699
2700 try stream.writeAll(" value=");
2701 try self.writeBracedDecl(stream, bodies.value_body);
2653 if (decl.type_body) |b| {
2654 try stream.writeAll(" type=");
2655 try self.writeBracedDecl(stream, b);
2656 }
27022657
2703 if (bodies.align_body) |b| {
2658 if (decl.align_body) |b| {
27042659 try stream.writeAll(" align=");
27052660 try self.writeBracedDecl(stream, b);
27062661 }
27072662
2708 if (bodies.linksection_body) |b| {
2663 if (decl.linksection_body) |b| {
27092664 try stream.writeAll(" linksection=");
27102665 try self.writeBracedDecl(stream, b);
27112666 }
27122667
2713 if (bodies.addrspace_body) |b| {
2668 if (decl.addrspace_body) |b| {
27142669 try stream.writeAll(" addrspace=");
27152670 try self.writeBracedDecl(stream, b);
27162671 }
2672
2673 if (decl.value_body) |b| {
2674 try stream.writeAll(" value=");
2675 try self.writeBracedDecl(stream, b);
2676 }
27172677 }
27182678
27192679 try stream.writeAll(") ");
test/behavior/globals.zig+96
......@@ -66,3 +66,99 @@ test "global loads can affect liveness" {
6666 S.f();
6767 try std.testing.expect(y.a == 1);
6868}
69
70test "global const can be self-referential" {
71 const S = struct {
72 self: *const @This(),
73 x: u32,
74
75 const foo: @This() = .{ .self = &foo, .x = 123 };
76 };
77
78 try std.testing.expect(S.foo.x == 123);
79 try std.testing.expect(S.foo.self.x == 123);
80 try std.testing.expect(S.foo.self.self.x == 123);
81 try std.testing.expect(S.foo.self == &S.foo);
82 try std.testing.expect(S.foo.self.self == &S.foo);
83}
84
85test "global var can be self-referential" {
86 const S = struct {
87 self: *@This(),
88 x: u32,
89
90 var foo: @This() = .{ .self = &foo, .x = undefined };
91 };
92
93 S.foo.x = 123;
94
95 try std.testing.expect(S.foo.x == 123);
96 try std.testing.expect(S.foo.self.x == 123);
97 try std.testing.expect(S.foo.self == &S.foo);
98
99 S.foo.self.x = 456;
100
101 try std.testing.expect(S.foo.x == 456);
102 try std.testing.expect(S.foo.self.x == 456);
103 try std.testing.expect(S.foo.self == &S.foo);
104
105 S.foo.self.self.x = 789;
106
107 try std.testing.expect(S.foo.x == 789);
108 try std.testing.expect(S.foo.self.x == 789);
109 try std.testing.expect(S.foo.self == &S.foo);
110}
111
112test "global const can be indirectly self-referential" {
113 const S = struct {
114 other: *const @This(),
115 x: u32,
116
117 const foo: @This() = .{ .other = &bar, .x = 123 };
118 const bar: @This() = .{ .other = &foo, .x = 456 };
119 };
120
121 try std.testing.expect(S.foo.x == 123);
122 try std.testing.expect(S.foo.other.x == 456);
123 try std.testing.expect(S.foo.other.other.x == 123);
124 try std.testing.expect(S.foo.other.other.other.x == 456);
125 try std.testing.expect(S.foo.other == &S.bar);
126 try std.testing.expect(S.foo.other.other == &S.foo);
127
128 try std.testing.expect(S.bar.x == 456);
129 try std.testing.expect(S.bar.other.x == 123);
130 try std.testing.expect(S.bar.other.other.x == 456);
131 try std.testing.expect(S.bar.other.other.other.x == 123);
132 try std.testing.expect(S.bar.other == &S.foo);
133 try std.testing.expect(S.bar.other.other == &S.bar);
134}
135
136test "global var can be indirectly self-referential" {
137 const S = struct {
138 other: *@This(),
139 x: u32,
140
141 var foo: @This() = .{ .other = &bar, .x = undefined };
142 var bar: @This() = .{ .other = &foo, .x = undefined };
143 };
144
145 S.foo.other.x = 123; // bar.x
146 S.foo.other.other.x = 456; // foo.x
147
148 try std.testing.expect(S.foo.x == 456);
149 try std.testing.expect(S.foo.other.x == 123);
150 try std.testing.expect(S.foo.other.other.x == 456);
151 try std.testing.expect(S.foo.other.other.other.x == 123);
152 try std.testing.expect(S.foo.other == &S.bar);
153 try std.testing.expect(S.foo.other.other == &S.foo);
154
155 S.bar.other.x = 111; // foo.x
156 S.bar.other.other.x = 222; // bar.x
157
158 try std.testing.expect(S.bar.x == 222);
159 try std.testing.expect(S.bar.other.x == 111);
160 try std.testing.expect(S.bar.other.other.x == 222);
161 try std.testing.expect(S.bar.other.other.other.x == 111);
162 try std.testing.expect(S.bar.other == &S.foo);
163 try std.testing.expect(S.bar.other.other == &S.bar);
164}
test/cases/compile_errors/address_of_threadlocal_not_comptime_known.zig+2-1
......@@ -10,4 +10,5 @@ pub export fn entry() void {
1010// target=native
1111//
1212// :2:36: error: unable to resolve comptime value
13// :2:36: note: container level variable initializers must be comptime-known
13// :2:36: note: global variable initializer must be comptime-known
14// :2:36: note: thread local and dll imported variables have runtime-known addresses
test/cases/compile_errors/self_reference_missing_const.zig created+11
......@@ -0,0 +1,11 @@
1const S = struct { self: *S, x: u32 };
2const s: S = .{ .self = &s, .x = 123 };
3
4comptime {
5 _ = s;
6}
7
8// error
9//
10// :2:18: error: expected type '*tmp.S', found '*const tmp.S'
11// :2:18: note: cast discards const qualifier
test/cases/compile_errors/type_variables_must_be_constant.zig+2-2
......@@ -7,5 +7,5 @@ export fn entry() foo {
77// backend=stage2
88// target=native
99//
10// :1:5: error: variable of type 'type' must be const or comptime
11// :1:5: note: types are not available at runtime
10// :1:11: error: variable of type 'type' must be const or comptime
11// :1:11: note: types are not available at runtime
test/cases/compile_errors/use_invalid_number_literal_as_array_index.zig+2-2
......@@ -8,5 +8,5 @@ export fn entry() void {
88// backend=stage2
99// target=native
1010//
11// :1:5: error: variable of type 'comptime_int' must be const or comptime
12// :1:5: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
11// :1:9: error: variable of type 'comptime_int' must be const or comptime
12// :1:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type