| author | |
| committer | |
| log | 497592c9b45a94fb7b6028bf45b80f183e395a9b |
| tree | 467873c408750cb4223f3ccf31775e42ec9fbd5c |
| parent | af5e731729592af4a5716edd3b1e03264d66ea46 |
| parent | 3afda4322c34dedc2319701fdfac3505c8d311e9 |
| signature |
compiler: analyze type and value of global declarations separately29 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 { |
| 106 | 106 | Zir.Inst.SwitchBlock.Bits, |
| 107 | 107 | Zir.Inst.SwitchBlockErrUnion.Bits, |
| 108 | 108 | Zir.Inst.FuncFancy.Bits, |
| 109 | Zir.Inst.Declaration.Flags, | |
| 110 | 109 | => @bitCast(@field(extra, field.name)), |
| 111 | 110 | |
| 112 | 111 | else => @compileError("bad field type"), |
| ... | ... | @@ -1317,12 +1316,45 @@ fn fnProtoExpr( |
| 1317 | 1316 | return astgen.failTok(some, "function type cannot have a name", .{}); |
| 1318 | 1317 | } |
| 1319 | 1318 | |
| 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 | ||
| 1320 | 1337 | const is_extern = blk: { |
| 1321 | 1338 | const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false; |
| 1322 | 1339 | break :blk token_tags[maybe_extern_token] == .keyword_extern; |
| 1323 | 1340 | }; |
| 1324 | 1341 | assert(!is_extern); |
| 1325 | 1342 | |
| 1343 | return fnProtoExprInner(gz, scope, ri, node, fn_proto, false); | |
| 1344 | } | |
| 1345 | ||
| 1346 | fn 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 | ||
| 1326 | 1358 | var block_scope = gz.makeSubBlock(scope); |
| 1327 | 1359 | defer block_scope.unstack(); |
| 1328 | 1360 | |
| ... | ... | @@ -1386,18 +1418,6 @@ fn fnProtoExpr( |
| 1386 | 1418 | break :is_var_args false; |
| 1387 | 1419 | }; |
| 1388 | 1420 | |
| 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 | ||
| 1401 | 1421 | const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0) |
| 1402 | 1422 | try expr( |
| 1403 | 1423 | &block_scope, |
| ... | ... | @@ -1405,14 +1425,11 @@ fn fnProtoExpr( |
| 1405 | 1425 | .{ .rl = .{ .coerced_ty = try block_scope.addBuiltinValue(fn_proto.ast.callconv_expr, .calling_convention) } }, |
| 1406 | 1426 | fn_proto.ast.callconv_expr, |
| 1407 | 1427 | ) |
| 1428 | else if (implicit_ccc) | |
| 1429 | try block_scope.addBuiltinValue(node, .calling_convention_c) | |
| 1408 | 1430 | else |
| 1409 | Zir.Inst.Ref.none; | |
| 1431 | .none; | |
| 1410 | 1432 | |
| 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 | } | |
| 1416 | 1433 | const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type); |
| 1417 | 1434 | |
| 1418 | 1435 | const result = try block_scope.addFunc(.{ |
| ... | ... | @@ -1428,11 +1445,8 @@ fn fnProtoExpr( |
| 1428 | 1445 | |
| 1429 | 1446 | .param_block = block_inst, |
| 1430 | 1447 | .body_gz = null, |
| 1431 | .lib_name = .empty, | |
| 1432 | 1448 | .is_var_args = is_var_args, |
| 1433 | 1449 | .is_inferred_error = false, |
| 1434 | .is_test = false, | |
| 1435 | .is_extern = false, | |
| 1436 | 1450 | .is_noinline = false, |
| 1437 | 1451 | .noalias_bits = noalias_bits, |
| 1438 | 1452 | |
| ... | ... | @@ -4121,17 +4135,6 @@ fn fnDecl( |
| 4121 | 4135 | |
| 4122 | 4136 | const saved_cursor = astgen.saveSourceCursor(); |
| 4123 | 4137 | |
| 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 | ||
| 4135 | 4138 | const decl_column = astgen.source_column; |
| 4136 | 4139 | |
| 4137 | 4140 | // Set this now, since parameter types, return type, etc may be generic. |
| ... | ... | @@ -4152,12 +4155,140 @@ fn fnDecl( |
| 4152 | 4155 | const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false; |
| 4153 | 4156 | break :blk token_tags[maybe_inline_token] == .keyword_inline; |
| 4154 | 4157 | }; |
| 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 | ||
| 4269 | fn 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 | ||
| 4155 | 4282 | const is_noinline = blk: { |
| 4156 | 4283 | const maybe_noinline_token = fn_proto.extern_export_inline_token orelse break :blk false; |
| 4157 | 4284 | break :blk token_tags[maybe_noinline_token] == .keyword_noinline; |
| 4158 | 4285 | }; |
| 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; | |
| 4161 | 4292 | |
| 4162 | 4293 | // Note that the capacity here may not be sufficient, as this does not include `anytype` parameters. |
| 4163 | 4294 | var param_insts: std.ArrayListUnmanaged(Zir.Inst.Index) = try .initCapacity(astgen.arena, fn_proto.ast.params.len); |
| ... | ... | @@ -4192,11 +4323,9 @@ fn fnDecl( |
| 4192 | 4323 | break :blk .empty; |
| 4193 | 4324 | |
| 4194 | 4325 | 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"); | |
| 4198 | 4327 | break :blk param_name; |
| 4199 | } else if (!is_extern) { | |
| 4328 | } else { | |
| 4200 | 4329 | if (param.anytype_ellipsis3) |tok| { |
| 4201 | 4330 | return astgen.failTok(tok, "missing parameter name", .{}); |
| 4202 | 4331 | } else { |
| ... | ... | @@ -4225,7 +4354,7 @@ fn fnDecl( |
| 4225 | 4354 | } |
| 4226 | 4355 | return astgen.failNode(param.type_expr, "missing parameter name", .{}); |
| 4227 | 4356 | } |
| 4228 | } else .empty; | |
| 4357 | }; | |
| 4229 | 4358 | |
| 4230 | 4359 | const param_inst = if (is_anytype) param: { |
| 4231 | 4360 | const name_token = param.name_token orelse param.anytype_ellipsis3.?; |
| ... | ... | @@ -4251,12 +4380,12 @@ fn fnDecl( |
| 4251 | 4380 | break :param param_inst.toRef(); |
| 4252 | 4381 | }; |
| 4253 | 4382 | |
| 4254 | if (param_name == .empty or is_extern) continue; | |
| 4383 | if (param_name == .empty) continue; | |
| 4255 | 4384 | |
| 4256 | 4385 | const sub_scope = try astgen.arena.create(Scope.LocalVal); |
| 4257 | 4386 | sub_scope.* = .{ |
| 4258 | 4387 | .parent = params_scope, |
| 4259 | .gen_zir = &decl_gz, | |
| 4388 | .gen_zir = decl_gz, | |
| 4260 | 4389 | .name = param_name, |
| 4261 | 4390 | .inst = param_inst, |
| 4262 | 4391 | .token_src = param.name_token.?, |
| ... | ... | @@ -4268,23 +4397,9 @@ fn fnDecl( |
| 4268 | 4397 | break :is_var_args false; |
| 4269 | 4398 | }; |
| 4270 | 4399 | |
| 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 | ||
| 4285 | 4400 | // 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. | |
| 4288 | 4403 | |
| 4289 | 4404 | var ret_gz = decl_gz.makeSubBlock(params_scope); |
| 4290 | 4405 | defer ret_gz.unstack(); |
| ... | ... | @@ -4309,13 +4424,6 @@ fn fnDecl( |
| 4309 | 4424 | defer cc_gz.unstack(); |
| 4310 | 4425 | const cc_ref: Zir.Inst.Ref = blk: { |
| 4311 | 4426 | 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 | } | |
| 4319 | 4427 | const inst = try expr( |
| 4320 | 4428 | &cc_gz, |
| 4321 | 4429 | scope, |
| ... | ... | @@ -4328,10 +4436,6 @@ fn fnDecl( |
| 4328 | 4436 | } |
| 4329 | 4437 | _ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst); |
| 4330 | 4438 | 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; | |
| 4335 | 4439 | } else if (has_inline_keyword) { |
| 4336 | 4440 | const inst = try cc_gz.addBuiltinValue(decl_node, .calling_convention_inline); |
| 4337 | 4441 | _ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst); |
| ... | ... | @@ -4341,167 +4445,86 @@ fn fnDecl( |
| 4341 | 4445 | } |
| 4342 | 4446 | }; |
| 4343 | 4447 | |
| 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, | |
| 4453 | 4456 | }; |
| 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); | |
| 4454 | 4474 | |
| 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; | |
| 4457 | 4489 | |
| 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; | |
| 4459 | 4493 | |
| 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; | |
| 4462 | 4497 | |
| 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); | |
| 4469 | 4500 | |
| 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); | |
| 4476 | 4504 | |
| 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)); | |
| 4483 | 4507 | } |
| 4484 | 4508 | |
| 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); | |
| 4505 | 4528 | } |
| 4506 | 4529 | |
| 4507 | 4530 | fn globalVarDecl( |
| ... | ... | @@ -4522,26 +4545,7 @@ fn globalVarDecl( |
| 4522 | 4545 | astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column)); |
| 4523 | 4546 | |
| 4524 | 4547 | 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 | ||
| 4529 | 4548 | 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 | ||
| 4545 | 4549 | const is_pub = var_decl.visib_token != null; |
| 4546 | 4550 | const is_export = blk: { |
| 4547 | 4551 | const maybe_export_token = var_decl.extern_export_token orelse break :blk false; |
| ... | ... | @@ -4551,15 +4555,12 @@ fn globalVarDecl( |
| 4551 | 4555 | const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; |
| 4552 | 4556 | break :blk token_tags[maybe_extern_token] == .keyword_extern; |
| 4553 | 4557 | }; |
| 4554 | wip_members.nextDecl(decl_inst); | |
| 4555 | ||
| 4556 | 4558 | const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: { |
| 4557 | 4559 | if (!is_mutable) { |
| 4558 | 4560 | return astgen.failTok(tok, "threadlocal variable cannot be constant", .{}); |
| 4559 | 4561 | } |
| 4560 | 4562 | break :blk true; |
| 4561 | 4563 | } else false; |
| 4562 | ||
| 4563 | 4564 | const lib_name = if (var_decl.lib_name) |lib_name_token| blk: { |
| 4564 | 4565 | const lib_name_str = try astgen.strLitAsString(lib_name_token); |
| 4565 | 4566 | const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len]; |
| ... | ... | @@ -4571,9 +4572,14 @@ fn globalVarDecl( |
| 4571 | 4572 | break :blk lib_name_str.index; |
| 4572 | 4573 | } else .empty; |
| 4573 | 4574 | |
| 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); | |
| 4575 | 4581 | |
| 4576 | const var_inst: Zir.Inst.Ref = if (var_decl.ast.init_node != 0) vi: { | |
| 4582 | if (var_decl.ast.init_node != 0) { | |
| 4577 | 4583 | if (is_extern) { |
| 4578 | 4584 | return astgen.failNode( |
| 4579 | 4585 | var_decl.ast.init_node, |
| ... | ... | @@ -4581,102 +4587,91 @@ fn globalVarDecl( |
| 4581 | 4587 | .{}, |
| 4582 | 4588 | ); |
| 4583 | 4589 | } |
| 4590 | } else { | |
| 4591 | if (!is_extern) { | |
| 4592 | return astgen.failNode(node, "variables must be initialized", .{}); | |
| 4593 | } | |
| 4594 | } | |
| 4584 | 4595 | |
| 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 | } | |
| 4596 | 4599 | |
| 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 | |
| 4603 | 4601 | |
| 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, | |
| 4638 | 4610 | }; |
| 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 | } | |
| 4639 | 4617 | |
| 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(); | |
| 4643 | 4620 | |
| 4644 | var align_gz = block_scope.makeSubBlock(scope); | |
| 4645 | 4621 | 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); | |
| 4647 | 4623 | _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node); |
| 4648 | 4624 | } |
| 4649 | 4625 | |
| 4650 | var linksection_gz = align_gz.makeSubBlock(scope); | |
| 4626 | var linksection_gz = type_gz.makeSubBlock(scope); | |
| 4627 | defer linksection_gz.unstack(); | |
| 4628 | ||
| 4651 | 4629 | 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); | |
| 4653 | 4631 | _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node); |
| 4654 | 4632 | } |
| 4655 | 4633 | |
| 4656 | var addrspace_gz = linksection_gz.makeSubBlock(scope); | |
| 4634 | var addrspace_gz = type_gz.makeSubBlock(scope); | |
| 4635 | defer addrspace_gz.unstack(); | |
| 4636 | ||
| 4657 | 4637 | if (var_decl.ast.addrspace_node != 0) { |
| 4658 | 4638 | 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); | |
| 4660 | 4640 | _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node); |
| 4661 | 4641 | } |
| 4662 | 4642 | |
| 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 | ||
| 4663 | 4655 | var hash: std.zig.SrcHash = undefined; |
| 4664 | 4656 | 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 | }); | |
| 4680 | 4675 | } |
| 4681 | 4676 | |
| 4682 | 4677 | fn comptimeDecl( |
| ... | ... | @@ -4702,37 +4697,45 @@ fn comptimeDecl( |
| 4702 | 4697 | wip_members.nextDecl(decl_inst); |
| 4703 | 4698 | astgen.advanceSourceCursorToNode(node); |
| 4704 | 4699 | |
| 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 = .{ | |
| 4706 | 4705 | .is_comptime = true, |
| 4707 | 4706 | .decl_node_index = node, |
| 4708 | 4707 | .decl_line = astgen.source_line, |
| 4709 | 4708 | .parent = scope, |
| 4710 | 4709 | .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, | |
| 4713 | 4712 | }; |
| 4714 | defer decl_block.unstack(); | |
| 4713 | defer comptime_gz.unstack(); | |
| 4715 | 4714 | |
| 4716 | 4715 | const decl_column = astgen.source_column; |
| 4717 | 4716 | |
| 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); | |
| 4721 | 4720 | } |
| 4722 | 4721 | |
| 4723 | 4722 | var hash: std.zig.SrcHash = undefined; |
| 4724 | 4723 | 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 | }); | |
| 4736 | 4739 | } |
| 4737 | 4740 | |
| 4738 | 4741 | fn usingnamespaceDecl( |
| ... | ... | @@ -4764,7 +4767,11 @@ fn usingnamespaceDecl( |
| 4764 | 4767 | wip_members.nextDecl(decl_inst); |
| 4765 | 4768 | astgen.advanceSourceCursorToNode(node); |
| 4766 | 4769 | |
| 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 = .{ | |
| 4768 | 4775 | .is_comptime = true, |
| 4769 | 4776 | .decl_node_index = node, |
| 4770 | 4777 | .decl_line = astgen.source_line, |
| ... | ... | @@ -4773,26 +4780,30 @@ fn usingnamespaceDecl( |
| 4773 | 4780 | .instructions = gz.instructions, |
| 4774 | 4781 | .instructions_top = gz.instructions.items.len, |
| 4775 | 4782 | }; |
| 4776 | defer decl_block.unstack(); | |
| 4783 | defer usingnamespace_gz.unstack(); | |
| 4777 | 4784 | |
| 4778 | 4785 | const decl_column = astgen.source_column; |
| 4779 | 4786 | |
| 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); | |
| 4782 | 4789 | |
| 4783 | 4790 | var hash: std.zig.SrcHash = undefined; |
| 4784 | 4791 | 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 | }); | |
| 4796 | 4807 | } |
| 4797 | 4808 | |
| 4798 | 4809 | fn testDecl( |
| ... | ... | @@ -4819,14 +4830,18 @@ fn testDecl( |
| 4819 | 4830 | wip_members.nextDecl(decl_inst); |
| 4820 | 4831 | astgen.advanceSourceCursorToNode(node); |
| 4821 | 4832 | |
| 4833 | // This is just needed for the `setDeclaration` call. | |
| 4834 | var dummy_gz: GenZir = gz.makeSubBlock(scope); | |
| 4835 | defer dummy_gz.unstack(); | |
| 4836 | ||
| 4822 | 4837 | var decl_block: GenZir = .{ |
| 4823 | 4838 | .is_comptime = true, |
| 4824 | 4839 | .decl_node_index = node, |
| 4825 | 4840 | .decl_line = astgen.source_line, |
| 4826 | 4841 | .parent = scope, |
| 4827 | 4842 | .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, | |
| 4830 | 4845 | }; |
| 4831 | 4846 | defer decl_block.unstack(); |
| 4832 | 4847 | |
| ... | ... | @@ -4835,11 +4850,21 @@ fn testDecl( |
| 4835 | 4850 | const main_tokens = tree.nodes.items(.main_token); |
| 4836 | 4851 | const token_tags = tree.tokens.items(.tag); |
| 4837 | 4852 | const test_token = main_tokens[node]; |
| 4853 | ||
| 4838 | 4854 | 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: { | |
| 4843 | 4868 | const ident_name_raw = tree.tokenSlice(test_name_token); |
| 4844 | 4869 | |
| 4845 | 4870 | 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( |
| 4909 | 4934 | return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name}); |
| 4910 | 4935 | } |
| 4911 | 4936 | |
| 4912 | break :blk .{ .decltest = test_name_token }; | |
| 4937 | break :name try astgen.identAsString(test_name_token); | |
| 4913 | 4938 | }, |
| 4914 | 4939 | }; |
| 4915 | 4940 | |
| ... | ... | @@ -4965,11 +4990,8 @@ fn testDecl( |
| 4965 | 4990 | .lbrace_column = lbrace_column, |
| 4966 | 4991 | .param_block = decl_inst, |
| 4967 | 4992 | .body_gz = &fn_block, |
| 4968 | .lib_name = .empty, | |
| 4969 | 4993 | .is_var_args = false, |
| 4970 | 4994 | .is_inferred_error = false, |
| 4971 | .is_test = true, | |
| 4972 | .is_extern = false, | |
| 4973 | 4995 | .is_noinline = false, |
| 4974 | 4996 | .noalias_bits = 0, |
| 4975 | 4997 | |
| ... | ... | @@ -4981,17 +5003,27 @@ fn testDecl( |
| 4981 | 5003 | |
| 4982 | 5004 | var hash: std.zig.SrcHash = undefined; |
| 4983 | 5005 | 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 | }); | |
| 4995 | 5027 | } |
| 4996 | 5028 | |
| 4997 | 5029 | fn structDeclInner( |
| ... | ... | @@ -5882,7 +5914,8 @@ fn containerMember( |
| 5882 | 5914 | try addFailedDeclaration( |
| 5883 | 5915 | wip_members, |
| 5884 | 5916 | gz, |
| 5885 | .{ .named = full.name_token.? }, | |
| 5917 | .@"const", | |
| 5918 | try astgen.identAsString(full.name_token.?), | |
| 5886 | 5919 | full.ast.proto_node, |
| 5887 | 5920 | full.visib_token != null, |
| 5888 | 5921 | ); |
| ... | ... | @@ -5904,7 +5937,8 @@ fn containerMember( |
| 5904 | 5937 | try addFailedDeclaration( |
| 5905 | 5938 | wip_members, |
| 5906 | 5939 | gz, |
| 5907 | .{ .named = full.ast.mut_token + 1 }, | |
| 5940 | .@"const", // doesn't really matter | |
| 5941 | try astgen.identAsString(full.ast.mut_token + 1), | |
| 5908 | 5942 | member_node, |
| 5909 | 5943 | full.visib_token != null, |
| 5910 | 5944 | ); |
| ... | ... | @@ -5922,6 +5956,7 @@ fn containerMember( |
| 5922 | 5956 | wip_members, |
| 5923 | 5957 | gz, |
| 5924 | 5958 | .@"comptime", |
| 5959 | .empty, | |
| 5925 | 5960 | member_node, |
| 5926 | 5961 | false, |
| 5927 | 5962 | ); |
| ... | ... | @@ -5938,6 +5973,7 @@ fn containerMember( |
| 5938 | 5973 | wip_members, |
| 5939 | 5974 | gz, |
| 5940 | 5975 | .@"usingnamespace", |
| 5976 | .empty, | |
| 5941 | 5977 | member_node, |
| 5942 | 5978 | is_pub: { |
| 5943 | 5979 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -5962,6 +5998,7 @@ fn containerMember( |
| 5962 | 5998 | wip_members, |
| 5963 | 5999 | gz, |
| 5964 | 6000 | .unnamed_test, |
| 6001 | .empty, | |
| 5965 | 6002 | member_node, |
| 5966 | 6003 | false, |
| 5967 | 6004 | ); |
| ... | ... | @@ -11670,23 +11707,6 @@ fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice { |
| 11670 | 11707 | }; |
| 11671 | 11708 | } |
| 11672 | 11709 | |
| 11673 | fn 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 | ||
| 11690 | 11710 | const Scope = struct { |
| 11691 | 11711 | tag: Tag, |
| 11692 | 11712 | |
| ... | ... | @@ -12077,12 +12097,9 @@ const GenZir = struct { |
| 12077 | 12097 | cc_ref: Zir.Inst.Ref, |
| 12078 | 12098 | ret_ref: Zir.Inst.Ref, |
| 12079 | 12099 | |
| 12080 | lib_name: Zir.NullTerminatedString, | |
| 12081 | 12100 | noalias_bits: u32, |
| 12082 | 12101 | is_var_args: bool, |
| 12083 | 12102 | is_inferred_error: bool, |
| 12084 | is_test: bool, | |
| 12085 | is_extern: bool, | |
| 12086 | 12103 | is_noinline: bool, |
| 12087 | 12104 | |
| 12088 | 12105 | /// Ignored if `body_gz == null`. |
| ... | ... | @@ -12150,9 +12167,8 @@ const GenZir = struct { |
| 12150 | 12167 | |
| 12151 | 12168 | const body_len = astgen.countBodyLenAfterFixupsExtraRefs(body, args.param_insts); |
| 12152 | 12169 | |
| 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) | |
| 12156 | 12172 | inst_info: { |
| 12157 | 12173 | try astgen.extra.ensureUnusedCapacity( |
| 12158 | 12174 | gpa, |
| ... | ... | @@ -12160,7 +12176,6 @@ const GenZir = struct { |
| 12160 | 12176 | fancyFnExprExtraLen(astgen, &.{}, cc_body, args.cc_ref) + |
| 12161 | 12177 | fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) + |
| 12162 | 12178 | body_len + src_locs_and_hash.len + |
| 12163 | @intFromBool(args.lib_name != .empty) + | |
| 12164 | 12179 | @intFromBool(args.noalias_bits != 0), |
| 12165 | 12180 | ); |
| 12166 | 12181 | const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{ |
| ... | ... | @@ -12169,10 +12184,7 @@ const GenZir = struct { |
| 12169 | 12184 | .bits = .{ |
| 12170 | 12185 | .is_var_args = args.is_var_args, |
| 12171 | 12186 | .is_inferred_error = args.is_inferred_error, |
| 12172 | .is_test = args.is_test, | |
| 12173 | .is_extern = args.is_extern, | |
| 12174 | 12187 | .is_noinline = args.is_noinline, |
| 12175 | .has_lib_name = args.lib_name != .empty, | |
| 12176 | 12188 | .has_any_noalias = args.noalias_bits != 0, |
| 12177 | 12189 | |
| 12178 | 12190 | .has_cc_ref = args.cc_ref != .none, |
| ... | ... | @@ -12182,9 +12194,6 @@ const GenZir = struct { |
| 12182 | 12194 | .has_ret_ty_body = ret_body.len != 0, |
| 12183 | 12195 | }, |
| 12184 | 12196 | }); |
| 12185 | if (args.lib_name != .empty) { | |
| 12186 | astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name)); | |
| 12187 | } | |
| 12188 | 12197 | |
| 12189 | 12198 | const zir_datas = astgen.instructions.items(.data); |
| 12190 | 12199 | if (cc_body.len != 0) { |
| ... | ... | @@ -12279,61 +12288,6 @@ const GenZir = struct { |
| 12279 | 12288 | @intFromBool(main_body.len > 0 or ref != .none); |
| 12280 | 12289 | } |
| 12281 | 12290 | |
| 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 | ||
| 12337 | 12291 | fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref { |
| 12338 | 12292 | return gz.add(.{ |
| 12339 | 12293 | .tag = .int, |
| ... | ... | @@ -13909,14 +13863,18 @@ const DeclarationName = union(enum) { |
| 13909 | 13863 | fn addFailedDeclaration( |
| 13910 | 13864 | wip_members: *WipMembers, |
| 13911 | 13865 | gz: *GenZir, |
| 13912 | name: DeclarationName, | |
| 13866 | kind: Zir.Inst.Declaration.Unwrapped.Kind, | |
| 13867 | name: Zir.NullTerminatedString, | |
| 13913 | 13868 | src_node: Ast.Node.Index, |
| 13914 | 13869 | is_pub: bool, |
| 13915 | 13870 | ) !void { |
| 13916 | 13871 | const decl_inst = try gz.makeDeclaration(src_node); |
| 13917 | 13872 | 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(.{ | |
| 13920 | 13878 | .tag = .extended, |
| 13921 | 13879 | .data = .{ .extended = .{ |
| 13922 | 13880 | .opcode = .astgen_error, |
| ... | ... | @@ -13924,110 +13882,198 @@ fn addFailedDeclaration( |
| 13924 | 13882 | .operand = undefined, |
| 13925 | 13883 | } }, |
| 13926 | 13884 | }); |
| 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 | }); | |
| 13938 | 13901 | } |
| 13939 | 13902 | |
| 13940 | 13903 | /// 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`. | |
| 13942 | 13905 | fn setDeclaration( |
| 13943 | 13906 | 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`. | |
| 13955 | 13921 | align_gz: *GenZir, |
| 13956 | 13922 | /// Must be stacked on `align_gz`. |
| 13957 | 13923 | linksection_gz: *GenZir, |
| 13958 | /// Must be stacked on `linksection_gz`, and have nothing stacked on it. | |
| 13924 | /// Must be stacked on `linksection_gz`. | |
| 13959 | 13925 | addrspace_gz: *GenZir, |
| 13926 | /// Must be stacked on `addrspace_gz` and have nothing stacked on top of it. | |
| 13927 | value_gz: *GenZir, | |
| 13960 | 13928 | }, |
| 13961 | 13929 | ) !void { |
| 13962 | const astgen = value_gz.astgen; | |
| 13930 | const astgen = args.value_gz.astgen; | |
| 13963 | 13931 | const gpa = astgen.gpa; |
| 13964 | 13932 | |
| 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 | }; | |
| 13972 | 14000 | |
| 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); | |
| 13974 | 14011 | const align_len = astgen.countBodyLenAfterFixups(align_body); |
| 13975 | 14012 | const linksection_len = astgen.countBodyLenAfterFixups(linksection_body); |
| 13976 | 14013 | 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); | |
| 13977 | 14023 | |
| 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); | |
| 13979 | 14034 | |
| 13980 | 14035 | const extra: Zir.Inst.Declaration = .{ |
| 13981 | 14036 | .src_hash_0 = src_hash_arr[0], |
| 13982 | 14037 | .src_hash_1 = src_hash_arr[1], |
| 13983 | 14038 | .src_hash_2 = src_hash_arr[2], |
| 13984 | 14039 | .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], | |
| 14008 | 14042 | }; |
| 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(&.{ | |
| 14012 | 14057 | align_len, |
| 14013 | 14058 | linksection_len, |
| 14014 | 14059 | addrspace_len, |
| 14015 | 14060 | }); |
| 14016 | 14061 | } |
| 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); | |
| 14023 | 14064 | } |
| 14024 | 14065 | |
| 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(); | |
| 14031 | 14077 | } |
| 14032 | 14078 | |
| 14033 | 14079 | /// 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 { |
| 1868 | 1868 | /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum. |
| 1869 | 1869 | /// `noreturn` instructions may not go here; they must be part of the main `Tag` enum. |
| 1870 | 1870 | pub const Extended = enum(u16) { |
| 1871 | /// Declares a global variable. | |
| 1872 | /// `operand` is payload index to `ExtendedVar`. | |
| 1873 | /// `small` is `ExtendedVar.Small`. | |
| 1874 | variable, | |
| 1875 | 1871 | /// A struct type definition. Contains references to ZIR instructions for |
| 1876 | 1872 | /// the field types, defaults, and alignments. |
| 1877 | 1873 | /// `operand` is payload index to `StructDecl`. |
| ... | ... | @@ -2493,26 +2489,25 @@ pub const Inst = struct { |
| 2493 | 2489 | }; |
| 2494 | 2490 | |
| 2495 | 2491 | /// Trailing: |
| 2496 | /// 0. lib_name: NullTerminatedString, // null terminated string index, if has_lib_name is set | |
| 2497 | 2492 | /// if (has_cc_ref and !has_cc_body) { |
| 2498 | /// 1. cc: Ref, | |
| 2493 | /// 0. cc: Ref, | |
| 2499 | 2494 | /// } |
| 2500 | 2495 | /// 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 | |
| 2503 | 2498 | /// } |
| 2504 | 2499 | /// if (has_ret_ty_ref and !has_ret_ty_body) { |
| 2505 | /// 4. ret_ty: Ref, | |
| 2500 | /// 3. ret_ty: Ref, | |
| 2506 | 2501 | /// } |
| 2507 | 2502 | /// 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 | |
| 2510 | 2505 | /// } |
| 2511 | /// 7. noalias_bits: u32 // if has_any_noalias | |
| 2506 | /// 6. noalias_bits: u32 // if has_any_noalias | |
| 2512 | 2507 | /// - 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 | |
| 2516 | 2511 | pub const FuncFancy = struct { |
| 2517 | 2512 | /// Points to the block that contains the param instructions for this function. |
| 2518 | 2513 | /// If this is a `declaration`, it refers to the declaration's value body. |
| ... | ... | @@ -2522,38 +2517,16 @@ pub const Inst = struct { |
| 2522 | 2517 | |
| 2523 | 2518 | /// If both has_cc_ref and has_cc_body are false, it means auto calling convention. |
| 2524 | 2519 | /// 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) { | |
| 2526 | 2521 | is_var_args: bool, |
| 2527 | 2522 | is_inferred_error: bool, |
| 2528 | is_test: bool, | |
| 2529 | is_extern: bool, | |
| 2530 | 2523 | is_noinline: bool, |
| 2531 | 2524 | has_cc_ref: bool, |
| 2532 | 2525 | has_cc_body: bool, |
| 2533 | 2526 | has_ret_ty_ref: bool, |
| 2534 | 2527 | has_ret_ty_body: bool, |
| 2535 | has_lib_name: bool, | |
| 2536 | 2528 | 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, | |
| 2557 | 2530 | }; |
| 2558 | 2531 | }; |
| 2559 | 2532 | |
| ... | ... | @@ -2582,39 +2555,301 @@ pub const Inst = struct { |
| 2582 | 2555 | }; |
| 2583 | 2556 | |
| 2584 | 2557 | /// 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` | |
| 2590 | 2567 | /// - 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 | |
| 2592 | 2569 | /// - for each `align_body_len` |
| 2593 | 2570 | /// - 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 | |
| 2595 | 2572 | /// - for each `linksection_body_len` |
| 2596 | 2573 | /// - 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 | |
| 2598 | 2575 | /// - for each `addrspace_body_len` |
| 2599 | 2576 | /// - 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 | |
| 2600 | 2581 | pub const Declaration = struct { |
| 2601 | 2582 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. |
| 2602 | 2583 | src_hash_0: u32, |
| 2603 | 2584 | src_hash_1: u32, |
| 2604 | 2585 | src_hash_2: u32, |
| 2605 | 2586 | 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 | }; | |
| 2611 | 2601 | |
| 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"`. | |
| 2614 | 2617 | 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 | }; | |
| 2618 | 2853 | }; |
| 2619 | 2854 | |
| 2620 | 2855 | pub const Name = enum(u32) { |
| ... | ... | @@ -2647,17 +2882,24 @@ pub const Inst = struct { |
| 2647 | 2882 | }; |
| 2648 | 2883 | |
| 2649 | 2884 | pub const Bodies = struct { |
| 2650 | value_body: []const Index, | |
| 2885 | type_body: ?[]const Index, | |
| 2651 | 2886 | align_body: ?[]const Index, |
| 2652 | 2887 | linksection_body: ?[]const Index, |
| 2653 | 2888 | addrspace_body: ?[]const Index, |
| 2889 | value_body: ?[]const Index, | |
| 2654 | 2890 | }; |
| 2655 | 2891 | |
| 2656 | 2892 | pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies { |
| 2657 | 2893 | 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 | }; | |
| 2659 | 2901 | 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()) { | |
| 2661 | 2903 | break :lens .{ 0, 0, 0 }; |
| 2662 | 2904 | } |
| 2663 | 2905 | const lens = zir.extra[extra_index..][0..3].*; |
| ... | ... | @@ -2665,21 +2907,30 @@ pub const Inst = struct { |
| 2665 | 2907 | break :lens lens; |
| 2666 | 2908 | }; |
| 2667 | 2909 | 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; | |
| 2671 | 2914 | }, |
| 2672 | 2915 | .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; | |
| 2675 | 2919 | }, |
| 2676 | 2920 | .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; | |
| 2679 | 2924 | }, |
| 2680 | 2925 | .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; | |
| 2683 | 2934 | }, |
| 2684 | 2935 | }; |
| 2685 | 2936 | } |
| ... | ... | @@ -3711,18 +3962,18 @@ pub const DeclContents = struct { |
| 3711 | 3962 | pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void { |
| 3712 | 3963 | contents.clear(); |
| 3713 | 3964 | |
| 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); | |
| 3716 | 3966 | |
| 3717 | 3967 | // `defer` instructions duplicate the same body arbitrarily many times, but we only want to traverse |
| 3718 | 3968 | // their contents once per defer. So, we store the extra index of the body here to deduplicate. |
| 3719 | 3969 | var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty; |
| 3720 | 3970 | defer found_defers.deinit(gpa); |
| 3721 | 3971 | |
| 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); | |
| 3726 | 3977 | } |
| 3727 | 3978 | |
| 3728 | 3979 | /// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than |
| ... | ... | @@ -3991,7 +4242,6 @@ fn findTrackableInner( |
| 3991 | 4242 | .value_placeholder => unreachable, |
| 3992 | 4243 | |
| 3993 | 4244 | // Once again, we start with the boring tags. |
| 3994 | .variable, | |
| 3995 | 4245 | .this, |
| 3996 | 4246 | .ret_addr, |
| 3997 | 4247 | .builtin_src, |
| ... | ... | @@ -4237,7 +4487,6 @@ fn findTrackableInner( |
| 4237 | 4487 | const inst_data = datas[@intFromEnum(inst)].pl_node; |
| 4238 | 4488 | const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index); |
| 4239 | 4489 | var extra_index: usize = extra.end; |
| 4240 | extra_index += @intFromBool(extra.data.bits.has_lib_name); | |
| 4241 | 4490 | |
| 4242 | 4491 | if (extra.data.bits.has_cc_body) { |
| 4243 | 4492 | const body_len = zir.extra[extra_index]; |
| ... | ... | @@ -4470,8 +4719,7 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index { |
| 4470 | 4719 | return zir.bodySlice(param_block.end, param_block.data.body_len); |
| 4471 | 4720 | }, |
| 4472 | 4721 | .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.?; | |
| 4475 | 4723 | }, |
| 4476 | 4724 | else => unreachable, |
| 4477 | 4725 | } |
| ... | ... | @@ -4526,7 +4774,6 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { |
| 4526 | 4774 | var ret_ty_ref: Inst.Ref = .void_type; |
| 4527 | 4775 | var ret_ty_body: []const Inst.Index = &.{}; |
| 4528 | 4776 | |
| 4529 | extra_index += @intFromBool(extra.data.bits.has_lib_name); | |
| 4530 | 4777 | if (extra.data.bits.has_cc_body) { |
| 4531 | 4778 | extra_index += zir.extra[extra_index] + 1; |
| 4532 | 4779 | } else if (extra.data.bits.has_cc_ref) { |
| ... | ... | @@ -4555,17 +4802,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { |
| 4555 | 4802 | }, |
| 4556 | 4803 | else => unreachable, |
| 4557 | 4804 | }; |
| 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); | |
| 4569 | 4806 | var total_params_len: u32 = 0; |
| 4570 | 4807 | for (param_body) |inst| { |
| 4571 | 4808 | switch (tags[@intFromEnum(inst)]) { |
| ... | ... | @@ -4585,13 +4822,74 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo { |
| 4585 | 4822 | }; |
| 4586 | 4823 | } |
| 4587 | 4824 | |
| 4588 | pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } { | |
| 4825 | pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) Inst.Declaration.Unwrapped { | |
| 4589 | 4826 | assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration); |
| 4590 | 4827 | const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].declaration; |
| 4591 | 4828 | 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 | ||
| 4592 | 4875 | 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, | |
| 4595 | 4893 | }; |
| 4596 | 4894 | } |
| 4597 | 4895 | |
| ... | ... | @@ -4636,7 +4934,6 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash { |
| 4636 | 4934 | } |
| 4637 | 4935 | const bits = extra.data.bits; |
| 4638 | 4936 | var extra_index = extra.end; |
| 4639 | extra_index += @intFromBool(bits.has_lib_name); | |
| 4640 | 4937 | if (bits.has_cc_body) { |
| 4641 | 4938 | const body_len = zir.extra[extra_index]; |
| 4642 | 4939 | extra_index += 1 + body_len; |
src/Compilation.zig+52-29| ... | ... | @@ -348,12 +348,15 @@ const Job = union(enum) { |
| 348 | 348 | /// Corresponds to the task in `link.Task`. |
| 349 | 349 | /// Only needed for backends that haven't yet been updated to not race against Sema. |
| 350 | 350 | 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. | |
| 352 | 356 | /// 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. | |
| 355 | 357 | /// After analysis, a `codegen_func` job will be queued. |
| 356 | 358 | /// 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. | |
| 357 | 360 | analyze_func: InternPool.Index, |
| 358 | 361 | /// The main source file for the module needs to be analyzed. |
| 359 | 362 | analyze_mod: *Package.Module, |
| ... | ... | @@ -2903,6 +2906,7 @@ const Header = extern struct { |
| 2903 | 2906 | file_deps_len: u32, |
| 2904 | 2907 | src_hash_deps_len: u32, |
| 2905 | 2908 | nav_val_deps_len: u32, |
| 2909 | nav_ty_deps_len: u32, | |
| 2906 | 2910 | namespace_deps_len: u32, |
| 2907 | 2911 | namespace_name_deps_len: u32, |
| 2908 | 2912 | first_dependency_len: u32, |
| ... | ... | @@ -2946,6 +2950,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 2946 | 2950 | .file_deps_len = @intCast(ip.file_deps.count()), |
| 2947 | 2951 | .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), |
| 2948 | 2952 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), |
| 2953 | .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()), | |
| 2949 | 2954 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), |
| 2950 | 2955 | .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), |
| 2951 | 2956 | .first_dependency_len = @intCast(ip.first_dependency.count()), |
| ... | ... | @@ -2976,6 +2981,8 @@ pub fn saveState(comp: *Compilation) !void { |
| 2976 | 2981 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values())); |
| 2977 | 2982 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys())); |
| 2978 | 2983 | 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())); | |
| 2979 | 2986 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys())); |
| 2980 | 2987 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values())); |
| 2981 | 2988 | addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys())); |
| ... | ... | @@ -3141,8 +3148,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3141 | 3148 | } |
| 3142 | 3149 | |
| 3143 | 3150 | 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), | |
| 3146 | 3155 | }; |
| 3147 | 3156 | |
| 3148 | 3157 | // Skip errors for AnalUnits within files that had a parse failure. |
| ... | ... | @@ -3374,11 +3383,9 @@ pub fn addModuleErrorMsg( |
| 3374 | 3383 | const rt_file_path = try src.file_scope.fullPath(gpa); |
| 3375 | 3384 | defer gpa.free(rt_file_path); |
| 3376 | 3385 | 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), | |
| 3382 | 3389 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), |
| 3383 | 3390 | }; |
| 3384 | 3391 | try ref_traces.append(gpa, .{ |
| ... | ... | @@ -3641,10 +3648,14 @@ fn performAllTheWorkInner( |
| 3641 | 3648 | // If there's no work queued, check if there's anything outdated |
| 3642 | 3649 | // which we need to work on, and queue it if so. |
| 3643 | 3650 | 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 | }); | |
| 3648 | 3659 | continue; |
| 3649 | 3660 | } |
| 3650 | 3661 | } |
| ... | ... | @@ -3667,13 +3678,13 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre |
| 3667 | 3678 | .codegen_nav => |nav_index| { |
| 3668 | 3679 | const zcu = comp.zcu.?; |
| 3669 | 3680 | 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 }); | |
| 3672 | 3683 | if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) { |
| 3673 | 3684 | return; |
| 3674 | 3685 | } |
| 3675 | 3686 | } |
| 3676 | assert(nav.status == .resolved); | |
| 3687 | assert(nav.status == .fully_resolved); | |
| 3677 | 3688 | comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index }); |
| 3678 | 3689 | }, |
| 3679 | 3690 | .codegen_func => |func| { |
| ... | ... | @@ -3688,36 +3699,48 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre |
| 3688 | 3699 | |
| 3689 | 3700 | const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); |
| 3690 | 3701 | 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, | |
| 3693 | 3705 | error.AnalysisFail => return, |
| 3694 | 3706 | }; |
| 3695 | 3707 | }, |
| 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 | ||
| 3697 | 3712 | const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); |
| 3698 | 3713 | 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, | |
| 3701 | 3724 | error.AnalysisFail => return, |
| 3702 | 3725 | }; |
| 3726 | ||
| 3703 | 3727 | queue_test_analysis: { |
| 3704 | 3728 | 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 | }; | |
| 3705 | 3733 | |
| 3706 | 3734 | // Check if this is a test function. |
| 3707 | 3735 | 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)) { | |
| 3714 | 3737 | break :queue_test_analysis; |
| 3715 | 3738 | } |
| 3716 | 3739 | |
| 3717 | 3740 | // Tests are always emitted in test binaries. The decl_refs are created by |
| 3718 | 3741 | // Zcu.populateTestFunctions, but this will not queue body analysis, so do |
| 3719 | 3742 | // 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); | |
| 3721 | 3744 | } |
| 3722 | 3745 | }, |
| 3723 | 3746 | .resolve_type_fully => |ty| { |
src/InternPool.zig+355-336| ... | ... | @@ -34,6 +34,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index), |
| 34 | 34 | /// Dependencies on the value of a Nav. |
| 35 | 35 | /// Value is index into `dep_entries` of the first dependency on this Nav value. |
| 36 | 36 | nav_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. | |
| 39 | nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index), | |
| 37 | 40 | /// Dependencies on an interned value, either: |
| 38 | 41 | /// * a runtime function (invalidated when its IES changes) |
| 39 | 42 | /// * a container type requiring resolution (invalidated when the type must be recreated at a new index) |
| ... | ... | @@ -80,6 +83,7 @@ pub const empty: InternPool = .{ |
| 80 | 83 | .file_deps = .empty, |
| 81 | 84 | .src_hash_deps = .empty, |
| 82 | 85 | .nav_val_deps = .empty, |
| 86 | .nav_ty_deps = .empty, | |
| 83 | 87 | .interned_deps = .empty, |
| 84 | 88 | .namespace_deps = .empty, |
| 85 | 89 | .namespace_name_deps = .empty, |
| ... | ... | @@ -363,33 +367,56 @@ pub fn rehashTrackedInsts( |
| 363 | 367 | } |
| 364 | 368 | |
| 365 | 369 | /// 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. | |
| 368 | 370 | /// This is the "source" of an incremental dependency edge. |
| 369 | pub const AnalUnit = packed struct(u32) { | |
| 370 | kind: enum(u1) { cau, func }, | |
| 371 | index: u31, | |
| 372 | pub const Unwrapped = union(enum) { | |
| 373 | cau: Cau.Index, | |
| 371 | pub 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. | |
| 374 | 394 | func: InternPool.Index, |
| 375 | 395 | }; |
| 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 | ), | |
| 380 | 404 | }; |
| 381 | 405 | } |
| 382 | 406 | pub fn wrap(raw: Unwrapped) AnalUnit { |
| 383 | 407 | 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 | }, | |
| 386 | 412 | }; |
| 387 | 413 | } |
| 414 | ||
| 388 | 415 | pub fn toOptional(as: AnalUnit) Optional { |
| 389 | return @enumFromInt(@as(u32, @bitCast(as))); | |
| 416 | return @enumFromInt(@as(u64, @bitCast(as))); | |
| 390 | 417 | } |
| 391 | pub const Optional = enum(u32) { | |
| 392 | none = std.math.maxInt(u32), | |
| 418 | pub const Optional = enum(u64) { | |
| 419 | none = std.math.maxInt(u64), | |
| 393 | 420 | _, |
| 394 | 421 | pub fn unwrap(opt: Optional) ?AnalUnit { |
| 395 | 422 | return switch (opt) { |
| ... | ... | @@ -400,97 +427,30 @@ pub const AnalUnit = packed struct(u32) { |
| 400 | 427 | }; |
| 401 | 428 | }; |
| 402 | 429 | |
| 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. | |
| 415 | pub const Cau = struct { | |
| 416 | /// The `declaration`, `struct_decl`, `enum_decl`, or `union_decl` instruction which this `Cau` analyzes. | |
| 430 | pub const ComptimeUnit = extern struct { | |
| 417 | 431 | zir_index: TrackedInst.Index, |
| 418 | /// The namespace which this `Cau` should be analyzed within. | |
| 419 | 432 | 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 | }; | |
| 442 | 433 | |
| 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 | } | |
| 461 | 437 | |
| 462 | pub const Index = enum(u32) { | |
| 438 | pub const Id = enum(u32) { | |
| 463 | 439 | _, |
| 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 | } | |
| 479 | 440 | const Unwrapped = struct { |
| 480 | 441 | tid: Zcu.PerThread.Id, |
| 481 | 442 | index: u32, |
| 482 | ||
| 483 | fn wrap(unwrapped: Unwrapped, ip: *const InternPool) Cau.Index { | |
| 443 | fn wrap(unwrapped: Unwrapped, ip: *const InternPool) ComptimeUnit.Id { | |
| 484 | 444 | 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 | | |
| 487 | 447 | unwrapped.index); |
| 488 | 448 | } |
| 489 | 449 | }; |
| 490 | fn unwrap(cau_index: Cau.Index, ip: *const InternPool) Unwrapped { | |
| 450 | fn unwrap(id: Id, ip: *const InternPool) Unwrapped { | |
| 491 | 451 | 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), | |
| 494 | 454 | }; |
| 495 | 455 | } |
| 496 | 456 | |
| ... | ... | @@ -507,6 +467,11 @@ pub const Cau = struct { |
| 507 | 467 | /// * Generic instances have a `Nav` corresponding to the instantiated function. |
| 508 | 468 | /// * `@extern` calls create a `Nav` whose value is a `.@"extern"`. |
| 509 | 469 | /// |
| 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 | /// | |
| 510 | 475 | /// `Nav.Repr` is the in-memory representation. |
| 511 | 476 | pub const Nav = struct { |
| 512 | 477 | /// 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 { |
| 514 | 479 | name: NullTerminatedString, |
| 515 | 480 | /// The fully-qualified name of this `Nav`. |
| 516 | 481 | 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 | }, | |
| 520 | 488 | /// TODO: this is a hack! If #20663 isn't accepted, let's figure out something a bit better. |
| 521 | 489 | is_usingnamespace: bool, |
| 522 | 490 | status: union(enum) { |
| 523 | /// This `Nav` is pending semantic analysis through `analysis_owner`. | |
| 491 | /// This `Nav` is pending semantic analysis. | |
| 524 | 492 | 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 | }, | |
| 525 | 505 | /// The value of this `Nav` is resolved. |
| 526 | resolved: struct { | |
| 506 | fully_resolved: struct { | |
| 527 | 507 | val: InternPool.Index, |
| 528 | 508 | alignment: Alignment, |
| 529 | 509 | @"linksection": OptionalNullTerminatedString, |
| ... | ... | @@ -531,30 +511,96 @@ pub const Nav = struct { |
| 531 | 511 | }, |
| 532 | 512 | }, |
| 533 | 513 | |
| 534 | /// Asserts that `status == .resolved`. | |
| 514 | /// Asserts that `status != .unresolved`. | |
| 535 | 515 | 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 | }; | |
| 537 | 536 | } |
| 538 | 537 | |
| 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 | }; | |
| 542 | 589 | } |
| 543 | 590 | |
| 544 | 591 | /// Get the ZIR instruction corresponding to this `Nav`, used to resolve source locations. |
| 545 | 592 | /// This is a `declaration`. |
| 546 | 593 | 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; | |
| 549 | 596 | } |
| 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)) { | |
| 552 | 599 | .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. | |
| 555 | 602 | 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; | |
| 558 | 604 | }, |
| 559 | 605 | .@"extern" => |@"extern"| @"extern".zir_index, // extern / @extern |
| 560 | 606 | else => unreachable, |
| ... | ... | @@ -600,24 +646,29 @@ pub const Nav = struct { |
| 600 | 646 | }; |
| 601 | 647 | |
| 602 | 648 | /// The compact in-memory representation of a `Nav`. |
| 603 | /// 18 bytes. | |
| 649 | /// 26 bytes. | |
| 604 | 650 | const Repr = struct { |
| 605 | 651 | name: NullTerminatedString, |
| 606 | 652 | 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`. | |
| 611 | 659 | @"linksection": OptionalNullTerminatedString, |
| 612 | 660 | bits: Bits, |
| 613 | 661 | |
| 614 | 662 | 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`. | |
| 617 | 665 | alignment: Alignment, |
| 618 | /// Populated only if `bits.status == .resolved`. | |
| 666 | /// Populated only if `bits.status != .unresolved`. | |
| 619 | 667 | @"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, | |
| 621 | 672 | is_usingnamespace: bool, |
| 622 | 673 | }; |
| 623 | 674 | |
| ... | ... | @@ -625,12 +676,27 @@ pub const Nav = struct { |
| 625 | 676 | return .{ |
| 626 | 677 | .name = repr.name, |
| 627 | 678 | .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 | }, | |
| 629 | 686 | .is_usingnamespace = repr.bits.is_usingnamespace, |
| 630 | 687 | .status = switch (repr.bits.status) { |
| 631 | 688 | .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, | |
| 634 | 700 | .alignment = repr.bits.alignment, |
| 635 | 701 | .@"linksection" = repr.@"linksection", |
| 636 | 702 | .@"addrspace" = repr.bits.@"addrspace", |
| ... | ... | @@ -646,14 +712,17 @@ pub const Nav = struct { |
| 646 | 712 | return .{ |
| 647 | 713 | .name = nav.name, |
| 648 | 714 | .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) { | |
| 651 | 718 | .unresolved => .none, |
| 652 | .resolved => |r| r.val, | |
| 719 | .type_resolved => |r| r.type, | |
| 720 | .fully_resolved => |r| r.val, | |
| 653 | 721 | }, |
| 654 | 722 | .@"linksection" = switch (nav.status) { |
| 655 | 723 | .unresolved => .none, |
| 656 | .resolved => |r| r.@"linksection", | |
| 724 | .type_resolved => |r| r.@"linksection", | |
| 725 | .fully_resolved => |r| r.@"linksection", | |
| 657 | 726 | }, |
| 658 | 727 | .bits = switch (nav.status) { |
| 659 | 728 | .unresolved => .{ |
| ... | ... | @@ -661,12 +730,24 @@ pub const Nav = struct { |
| 661 | 730 | .alignment = .none, |
| 662 | 731 | .@"addrspace" = .generic, |
| 663 | 732 | .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, | |
| 664 | 743 | }, |
| 665 | .resolved => |r| .{ | |
| 666 | .status = .resolved, | |
| 744 | .fully_resolved => |r| .{ | |
| 745 | .status = .fully_resolved, | |
| 667 | 746 | .alignment = r.alignment, |
| 668 | 747 | .@"addrspace" = r.@"addrspace", |
| 669 | 748 | .is_usingnamespace = nav.is_usingnamespace, |
| 749 | .is_const = false, | |
| 750 | .is_threadlocal = false, | |
| 670 | 751 | }, |
| 671 | 752 | }, |
| 672 | 753 | }; |
| ... | ... | @@ -677,6 +758,7 @@ pub const Dependee = union(enum) { |
| 677 | 758 | file: FileIndex, |
| 678 | 759 | src_hash: TrackedInst.Index, |
| 679 | 760 | nav_val: Nav.Index, |
| 761 | nav_ty: Nav.Index, | |
| 680 | 762 | interned: Index, |
| 681 | 763 | namespace: TrackedInst.Index, |
| 682 | 764 | namespace_name: NamespaceNameKey, |
| ... | ... | @@ -726,6 +808,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI |
| 726 | 808 | .file => |x| ip.file_deps.get(x), |
| 727 | 809 | .src_hash => |x| ip.src_hash_deps.get(x), |
| 728 | 810 | .nav_val => |x| ip.nav_val_deps.get(x), |
| 811 | .nav_ty => |x| ip.nav_ty_deps.get(x), | |
| 729 | 812 | .interned => |x| ip.interned_deps.get(x), |
| 730 | 813 | .namespace => |x| ip.namespace_deps.get(x), |
| 731 | 814 | .namespace_name => |x| ip.namespace_name_deps.get(x), |
| ... | ... | @@ -763,6 +846,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 763 | 846 | .file => ip.file_deps, |
| 764 | 847 | .src_hash => ip.src_hash_deps, |
| 765 | 848 | .nav_val => ip.nav_val_deps, |
| 849 | .nav_ty => ip.nav_ty_deps, | |
| 766 | 850 | .interned => ip.interned_deps, |
| 767 | 851 | .namespace => ip.namespace_deps, |
| 768 | 852 | .namespace_name => ip.namespace_name_deps, |
| ... | ... | @@ -862,8 +946,8 @@ const Local = struct { |
| 862 | 946 | tracked_insts: ListMutate, |
| 863 | 947 | files: ListMutate, |
| 864 | 948 | maps: ListMutate, |
| 865 | caus: ListMutate, | |
| 866 | 949 | navs: ListMutate, |
| 950 | comptime_units: ListMutate, | |
| 867 | 951 | |
| 868 | 952 | namespaces: BucketListMutate, |
| 869 | 953 | } align(std.atomic.cache_line), |
| ... | ... | @@ -876,8 +960,8 @@ const Local = struct { |
| 876 | 960 | tracked_insts: TrackedInsts, |
| 877 | 961 | files: List(File), |
| 878 | 962 | maps: Maps, |
| 879 | caus: Caus, | |
| 880 | 963 | navs: Navs, |
| 964 | comptime_units: ComptimeUnits, | |
| 881 | 965 | |
| 882 | 966 | namespaces: Namespaces, |
| 883 | 967 | |
| ... | ... | @@ -899,8 +983,8 @@ const Local = struct { |
| 899 | 983 | const Strings = List(struct { u8 }); |
| 900 | 984 | const TrackedInsts = List(struct { TrackedInst.MaybeLost }); |
| 901 | 985 | const Maps = List(struct { FieldMap }); |
| 902 | const Caus = List(struct { Cau }); | |
| 903 | 986 | const Navs = List(Nav.Repr); |
| 987 | const ComptimeUnits = List(struct { ComptimeUnit }); | |
| 904 | 988 | |
| 905 | 989 | const namespaces_bucket_width = 8; |
| 906 | 990 | const namespaces_bucket_mask = (1 << namespaces_bucket_width) - 1; |
| ... | ... | @@ -1275,21 +1359,21 @@ const Local = struct { |
| 1275 | 1359 | }; |
| 1276 | 1360 | } |
| 1277 | 1361 | |
| 1278 | pub fn getMutableCaus(local: *Local, gpa: Allocator) Caus.Mutable { | |
| 1362 | pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable { | |
| 1279 | 1363 | return .{ |
| 1280 | 1364 | .gpa = gpa, |
| 1281 | 1365 | .arena = &local.mutate.arena, |
| 1282 | .mutate = &local.mutate.caus, | |
| 1283 | .list = &local.shared.caus, | |
| 1366 | .mutate = &local.mutate.navs, | |
| 1367 | .list = &local.shared.navs, | |
| 1284 | 1368 | }; |
| 1285 | 1369 | } |
| 1286 | 1370 | |
| 1287 | pub fn getMutableNavs(local: *Local, gpa: Allocator) Navs.Mutable { | |
| 1371 | pub fn getMutableComptimeUnits(local: *Local, gpa: Allocator) ComptimeUnits.Mutable { | |
| 1288 | 1372 | return .{ |
| 1289 | 1373 | .gpa = gpa, |
| 1290 | 1374 | .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, | |
| 1293 | 1377 | }; |
| 1294 | 1378 | } |
| 1295 | 1379 | |
| ... | ... | @@ -2018,7 +2102,6 @@ pub const Key = union(enum) { |
| 2018 | 2102 | ty: Index, |
| 2019 | 2103 | init: Index, |
| 2020 | 2104 | owner_nav: Nav.Index, |
| 2021 | lib_name: OptionalNullTerminatedString, | |
| 2022 | 2105 | is_threadlocal: bool, |
| 2023 | 2106 | is_weak_linkage: bool, |
| 2024 | 2107 | }; |
| ... | ... | @@ -2111,36 +2194,36 @@ pub const Key = union(enum) { |
| 2111 | 2194 | return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered); |
| 2112 | 2195 | } |
| 2113 | 2196 | |
| 2114 | pub fn setAnalysisState(func: Func, ip: *InternPool, state: FuncAnalysis.State) void { | |
| 2197 | pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void { | |
| 2115 | 2198 | const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; |
| 2116 | 2199 | extra_mutex.lock(); |
| 2117 | 2200 | defer extra_mutex.unlock(); |
| 2118 | 2201 | |
| 2119 | 2202 | const analysis_ptr = func.analysisPtr(ip); |
| 2120 | 2203 | var analysis = analysis_ptr.*; |
| 2121 | analysis.state = state; | |
| 2204 | analysis.calls_or_awaits_errorable_fn = value; | |
| 2122 | 2205 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); |
| 2123 | 2206 | } |
| 2124 | 2207 | |
| 2125 | pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void { | |
| 2208 | pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void { | |
| 2126 | 2209 | const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; |
| 2127 | 2210 | extra_mutex.lock(); |
| 2128 | 2211 | defer extra_mutex.unlock(); |
| 2129 | 2212 | |
| 2130 | 2213 | const analysis_ptr = func.analysisPtr(ip); |
| 2131 | 2214 | var analysis = analysis_ptr.*; |
| 2132 | analysis.calls_or_awaits_errorable_fn = value; | |
| 2215 | analysis.branch_hint = hint; | |
| 2133 | 2216 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); |
| 2134 | 2217 | } |
| 2135 | 2218 | |
| 2136 | pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void { | |
| 2219 | pub fn setAnalyzed(func: Func, ip: *InternPool) void { | |
| 2137 | 2220 | const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex; |
| 2138 | 2221 | extra_mutex.lock(); |
| 2139 | 2222 | defer extra_mutex.unlock(); |
| 2140 | 2223 | |
| 2141 | 2224 | const analysis_ptr = func.analysisPtr(ip); |
| 2142 | 2225 | var analysis = analysis_ptr.*; |
| 2143 | analysis.branch_hint = hint; | |
| 2226 | analysis.is_analyzed = true; | |
| 2144 | 2227 | @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release); |
| 2145 | 2228 | } |
| 2146 | 2229 | |
| ... | ... | @@ -2741,7 +2824,6 @@ pub const Key = union(enum) { |
| 2741 | 2824 | return a_info.owner_nav == b_info.owner_nav and |
| 2742 | 2825 | a_info.ty == b_info.ty and |
| 2743 | 2826 | a_info.init == b_info.init and |
| 2744 | a_info.lib_name == b_info.lib_name and | |
| 2745 | 2827 | a_info.is_threadlocal == b_info.is_threadlocal and |
| 2746 | 2828 | a_info.is_weak_linkage == b_info.is_weak_linkage; |
| 2747 | 2829 | }, |
| ... | ... | @@ -3054,8 +3136,6 @@ pub const LoadedUnionType = struct { |
| 3054 | 3136 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3055 | 3137 | /// The name of this union type. |
| 3056 | 3138 | name: NullTerminatedString, |
| 3057 | /// The `Cau` within which type resolution occurs. | |
| 3058 | cau: Cau.Index, | |
| 3059 | 3139 | /// Represents the declarations inside this union. |
| 3060 | 3140 | namespace: NamespaceIndex, |
| 3061 | 3141 | /// The enum tag type. |
| ... | ... | @@ -3372,7 +3452,6 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType { |
| 3372 | 3452 | .tid = unwrapped_index.tid, |
| 3373 | 3453 | .extra_index = data, |
| 3374 | 3454 | .name = type_union.data.name, |
| 3375 | .cau = type_union.data.cau, | |
| 3376 | 3455 | .namespace = type_union.data.namespace, |
| 3377 | 3456 | .enum_tag_ty = type_union.data.tag_ty, |
| 3378 | 3457 | .field_types = field_types, |
| ... | ... | @@ -3389,8 +3468,6 @@ pub const LoadedStructType = struct { |
| 3389 | 3468 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 3390 | 3469 | /// The name of this struct type. |
| 3391 | 3470 | name: NullTerminatedString, |
| 3392 | /// The `Cau` within which type resolution occurs. | |
| 3393 | cau: Cau.Index, | |
| 3394 | 3471 | namespace: NamespaceIndex, |
| 3395 | 3472 | /// Index of the `struct_decl` or `reify` ZIR instruction. |
| 3396 | 3473 | zir_index: TrackedInst.Index, |
| ... | ... | @@ -3981,7 +4058,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 3981 | 4058 | switch (item.tag) { |
| 3982 | 4059 | .type_struct => { |
| 3983 | 4060 | 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").?]); | |
| 3985 | 4061 | const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]); |
| 3986 | 4062 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]); |
| 3987 | 4063 | 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 { |
| 4068 | 4144 | .tid = unwrapped_index.tid, |
| 4069 | 4145 | .extra_index = item.data, |
| 4070 | 4146 | .name = name, |
| 4071 | .cau = cau, | |
| 4072 | 4147 | .namespace = namespace, |
| 4073 | 4148 | .zir_index = zir_index, |
| 4074 | 4149 | .layout = if (flags.is_extern) .@"extern" else .auto, |
| ... | ... | @@ -4085,7 +4160,6 @@ pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType { |
| 4085 | 4160 | }, |
| 4086 | 4161 | .type_struct_packed, .type_struct_packed_inits => { |
| 4087 | 4162 | 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").?]); | |
| 4089 | 4163 | const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]); |
| 4090 | 4164 | const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?]; |
| 4091 | 4165 | 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 { |
| 4132 | 4206 | .tid = unwrapped_index.tid, |
| 4133 | 4207 | .extra_index = item.data, |
| 4134 | 4208 | .name = name, |
| 4135 | .cau = cau, | |
| 4136 | 4209 | .namespace = namespace, |
| 4137 | 4210 | .zir_index = zir_index, |
| 4138 | 4211 | .layout = .@"packed", |
| ... | ... | @@ -4155,9 +4228,6 @@ pub const LoadedEnumType = struct { |
| 4155 | 4228 | // TODO: the non-fqn will be needed by the new dwarf structure |
| 4156 | 4229 | /// The name of this enum type. |
| 4157 | 4230 | name: NullTerminatedString, |
| 4158 | /// The `Cau` within which type resolution occurs. | |
| 4159 | /// `null` if this is a generated tag type. | |
| 4160 | cau: Cau.Index.Optional, | |
| 4161 | 4231 | /// Represents the declarations inside this enum. |
| 4162 | 4232 | namespace: NamespaceIndex, |
| 4163 | 4233 | /// 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 { |
| 4234 | 4304 | .type_enum_auto => { |
| 4235 | 4305 | const extra = extraDataTrail(extra_list, EnumAuto, item.data); |
| 4236 | 4306 | 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) { | |
| 4238 | 4308 | 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 | } | |
| 4245 | 4310 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: { |
| 4246 | 4311 | extra_index += 2; // type_hash: PackedU64 |
| 4247 | 4312 | break :c 0; |
| 4248 | 4313 | } else extra.data.captures_len; |
| 4249 | 4314 | return .{ |
| 4250 | 4315 | .name = extra.data.name, |
| 4251 | .cau = cau, | |
| 4252 | 4316 | .namespace = extra.data.namespace, |
| 4253 | 4317 | .tag_ty = extra.data.int_tag_type, |
| 4254 | 4318 | .names = .{ |
| ... | ... | @@ -4274,21 +4338,15 @@ pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType { |
| 4274 | 4338 | }; |
| 4275 | 4339 | const extra = extraDataTrail(extra_list, EnumExplicit, item.data); |
| 4276 | 4340 | 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) { | |
| 4278 | 4342 | 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 | } | |
| 4285 | 4344 | const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: { |
| 4286 | 4345 | extra_index += 2; // type_hash: PackedU64 |
| 4287 | 4346 | break :c 0; |
| 4288 | 4347 | } else extra.data.captures_len; |
| 4289 | 4348 | return .{ |
| 4290 | 4349 | .name = extra.data.name, |
| 4291 | .cau = cau, | |
| 4292 | 4350 | .namespace = extra.data.namespace, |
| 4293 | 4351 | .tag_ty = extra.data.int_tag_type, |
| 4294 | 4352 | .names = .{ |
| ... | ... | @@ -5258,7 +5316,6 @@ pub const Tag = enum(u8) { |
| 5258 | 5316 | .payload = EnumExplicit, |
| 5259 | 5317 | .trailing = struct { |
| 5260 | 5318 | owner_union: Index, |
| 5261 | cau: ?Cau.Index, | |
| 5262 | 5319 | captures: ?[]CaptureValue, |
| 5263 | 5320 | type_hash: ?u64, |
| 5264 | 5321 | field_names: []NullTerminatedString, |
| ... | ... | @@ -5304,7 +5361,6 @@ pub const Tag = enum(u8) { |
| 5304 | 5361 | .payload = EnumAuto, |
| 5305 | 5362 | .trailing = struct { |
| 5306 | 5363 | owner_union: ?Index, |
| 5307 | cau: ?Cau.Index, | |
| 5308 | 5364 | captures: ?[]CaptureValue, |
| 5309 | 5365 | type_hash: ?u64, |
| 5310 | 5366 | field_names: []NullTerminatedString, |
| ... | ... | @@ -5573,9 +5629,6 @@ pub const Tag = enum(u8) { |
| 5573 | 5629 | /// May be `none`. |
| 5574 | 5630 | init: Index, |
| 5575 | 5631 | 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, | |
| 5579 | 5632 | flags: Flags, |
| 5580 | 5633 | |
| 5581 | 5634 | pub const Flags = packed struct(u32) { |
| ... | ... | @@ -5684,7 +5737,6 @@ pub const Tag = enum(u8) { |
| 5684 | 5737 | size: u32, |
| 5685 | 5738 | /// Only valid after .have_layout |
| 5686 | 5739 | padding: u32, |
| 5687 | cau: Cau.Index, | |
| 5688 | 5740 | namespace: NamespaceIndex, |
| 5689 | 5741 | /// The enum that provides the list of field names and values. |
| 5690 | 5742 | tag_ty: Index, |
| ... | ... | @@ -5715,7 +5767,6 @@ pub const Tag = enum(u8) { |
| 5715 | 5767 | /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits |
| 5716 | 5768 | pub const TypeStructPacked = struct { |
| 5717 | 5769 | name: NullTerminatedString, |
| 5718 | cau: Cau.Index, | |
| 5719 | 5770 | zir_index: TrackedInst.Index, |
| 5720 | 5771 | fields_len: u32, |
| 5721 | 5772 | namespace: NamespaceIndex, |
| ... | ... | @@ -5763,7 +5814,6 @@ pub const Tag = enum(u8) { |
| 5763 | 5814 | /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved |
| 5764 | 5815 | pub const TypeStruct = struct { |
| 5765 | 5816 | name: NullTerminatedString, |
| 5766 | cau: Cau.Index, | |
| 5767 | 5817 | zir_index: TrackedInst.Index, |
| 5768 | 5818 | namespace: NamespaceIndex, |
| 5769 | 5819 | fields_len: u32, |
| ... | ... | @@ -5820,7 +5870,7 @@ pub const Tag = enum(u8) { |
| 5820 | 5870 | /// equality or hashing, except for `inferred_error_set` which is considered |
| 5821 | 5871 | /// to be part of the type of the function. |
| 5822 | 5872 | pub const FuncAnalysis = packed struct(u32) { |
| 5823 | state: State, | |
| 5873 | is_analyzed: bool, | |
| 5824 | 5874 | branch_hint: std.builtin.BranchHint, |
| 5825 | 5875 | is_noinline: bool, |
| 5826 | 5876 | calls_or_awaits_errorable_fn: bool, |
| ... | ... | @@ -5828,20 +5878,7 @@ pub const FuncAnalysis = packed struct(u32) { |
| 5828 | 5878 | inferred_error_set: bool, |
| 5829 | 5879 | disable_instrumentation: bool, |
| 5830 | 5880 | |
| 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, | |
| 5845 | 5882 | }; |
| 5846 | 5883 | |
| 5847 | 5884 | pub const Bytes = struct { |
| ... | ... | @@ -6093,11 +6130,10 @@ pub const Array = struct { |
| 6093 | 6130 | |
| 6094 | 6131 | /// Trailing: |
| 6095 | 6132 | /// 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 | |
| 6101 | 6137 | pub const EnumExplicit = struct { |
| 6102 | 6138 | name: NullTerminatedString, |
| 6103 | 6139 | /// `std.math.maxInt(u32)` indicates this type is reified. |
| ... | ... | @@ -6120,10 +6156,9 @@ pub const EnumExplicit = struct { |
| 6120 | 6156 | |
| 6121 | 6157 | /// Trailing: |
| 6122 | 6158 | /// 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 | |
| 6127 | 6162 | pub const EnumAuto = struct { |
| 6128 | 6163 | name: NullTerminatedString, |
| 6129 | 6164 | /// `std.math.maxInt(u32)` indicates this type is reified. |
| ... | ... | @@ -6413,32 +6448,32 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void { |
| 6413 | 6448 | ip.locals = try gpa.alloc(Local, used_threads); |
| 6414 | 6449 | @memset(ip.locals, .{ |
| 6415 | 6450 | .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, | |
| 6427 | 6462 | }, |
| 6428 | 6463 | .mutate = .{ |
| 6429 | 6464 | .arena = .{}, |
| 6430 | 6465 | |
| 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, | |
| 6440 | 6475 | |
| 6441 | .namespaces = Local.BucketListMutate.empty, | |
| 6476 | .namespaces = .empty, | |
| 6442 | 6477 | }, |
| 6443 | 6478 | }); |
| 6444 | 6479 | |
| ... | ... | @@ -6486,6 +6521,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 6486 | 6521 | ip.file_deps.deinit(gpa); |
| 6487 | 6522 | ip.src_hash_deps.deinit(gpa); |
| 6488 | 6523 | ip.nav_val_deps.deinit(gpa); |
| 6524 | ip.nav_ty_deps.deinit(gpa); | |
| 6489 | 6525 | ip.interned_deps.deinit(gpa); |
| 6490 | 6526 | ip.namespace_deps.deinit(gpa); |
| 6491 | 6527 | ip.namespace_name_deps.deinit(gpa); |
| ... | ... | @@ -6511,7 +6547,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 6511 | 6547 | namespace.priv_decls.deinit(gpa); |
| 6512 | 6548 | namespace.pub_usingnamespace.deinit(gpa); |
| 6513 | 6549 | namespace.priv_usingnamespace.deinit(gpa); |
| 6514 | namespace.other_decls.deinit(gpa); | |
| 6550 | namespace.comptime_decls.deinit(gpa); | |
| 6551 | namespace.test_decls.deinit(gpa); | |
| 6515 | 6552 | } |
| 6516 | 6553 | }; |
| 6517 | 6554 | const maps = local.getMutableMaps(gpa); |
| ... | ... | @@ -6530,8 +6567,6 @@ pub fn activate(ip: *const InternPool) void { |
| 6530 | 6567 | _ = OptionalString.debug_state; |
| 6531 | 6568 | _ = NullTerminatedString.debug_state; |
| 6532 | 6569 | _ = OptionalNullTerminatedString.debug_state; |
| 6533 | _ = Cau.Index.debug_state; | |
| 6534 | _ = Cau.Index.Optional.debug_state; | |
| 6535 | 6570 | _ = Nav.Index.debug_state; |
| 6536 | 6571 | _ = Nav.Index.Optional.debug_state; |
| 6537 | 6572 | std.debug.assert(debug_state.intern_pool == null); |
| ... | ... | @@ -6716,14 +6751,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6716 | 6751 | if (extra.data.captures_len == std.math.maxInt(u32)) { |
| 6717 | 6752 | break :ns .{ .reified = .{ |
| 6718 | 6753 | .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(), | |
| 6720 | 6755 | } }; |
| 6721 | 6756 | } |
| 6722 | 6757 | break :ns .{ .declared = .{ |
| 6723 | 6758 | .zir_index = zir_index, |
| 6724 | 6759 | .captures = .{ .owned = .{ |
| 6725 | 6760 | .tid = unwrapped_index.tid, |
| 6726 | .start = extra.end + 1, | |
| 6761 | .start = extra.end, | |
| 6727 | 6762 | .len = extra.data.captures_len, |
| 6728 | 6763 | } }, |
| 6729 | 6764 | } }; |
| ... | ... | @@ -6740,14 +6775,14 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6740 | 6775 | if (extra.data.captures_len == std.math.maxInt(u32)) { |
| 6741 | 6776 | break :ns .{ .reified = .{ |
| 6742 | 6777 | .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(), | |
| 6744 | 6779 | } }; |
| 6745 | 6780 | } |
| 6746 | 6781 | break :ns .{ .declared = .{ |
| 6747 | 6782 | .zir_index = zir_index, |
| 6748 | 6783 | .captures = .{ .owned = .{ |
| 6749 | 6784 | .tid = unwrapped_index.tid, |
| 6750 | .start = extra.end + 1, | |
| 6785 | .start = extra.end, | |
| 6751 | 6786 | .len = extra.data.captures_len, |
| 6752 | 6787 | } }, |
| 6753 | 6788 | } }; |
| ... | ... | @@ -6928,7 +6963,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6928 | 6963 | .ty = extra.ty, |
| 6929 | 6964 | .init = extra.init, |
| 6930 | 6965 | .owner_nav = extra.owner_nav, |
| 6931 | .lib_name = extra.lib_name, | |
| 6932 | 6966 | .is_threadlocal = extra.flags.is_threadlocal, |
| 6933 | 6967 | .is_weak_linkage = extra.flags.is_weak_linkage, |
| 6934 | 6968 | } }; |
| ... | ... | @@ -6944,8 +6978,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 6944 | 6978 | .is_threadlocal = extra.flags.is_threadlocal, |
| 6945 | 6979 | .is_weak_linkage = extra.flags.is_weak_linkage, |
| 6946 | 6980 | .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", | |
| 6949 | 6983 | .zir_index = extra.zir_index, |
| 6950 | 6984 | .owner_nav = extra.owner_nav, |
| 6951 | 6985 | } }; |
| ... | ... | @@ -7575,7 +7609,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All |
| 7575 | 7609 | .ty = variable.ty, |
| 7576 | 7610 | .init = variable.init, |
| 7577 | 7611 | .owner_nav = variable.owner_nav, |
| 7578 | .lib_name = variable.lib_name, | |
| 7579 | 7612 | .flags = .{ |
| 7580 | 7613 | .is_const = false, |
| 7581 | 7614 | .is_threadlocal = variable.is_threadlocal, |
| ... | ... | @@ -8330,7 +8363,6 @@ pub fn getUnionType( |
| 8330 | 8363 | .size = std.math.maxInt(u32), |
| 8331 | 8364 | .padding = std.math.maxInt(u32), |
| 8332 | 8365 | .name = undefined, // set by `finish` |
| 8333 | .cau = undefined, // set by `finish` | |
| 8334 | 8366 | .namespace = undefined, // set by `finish` |
| 8335 | 8367 | .tag_ty = ini.enum_tag_ty, |
| 8336 | 8368 | .zir_index = switch (ini.key) { |
| ... | ... | @@ -8382,7 +8414,6 @@ pub fn getUnionType( |
| 8382 | 8414 | .tid = tid, |
| 8383 | 8415 | .index = gop.put(), |
| 8384 | 8416 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?, |
| 8385 | .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "cau").?, | |
| 8386 | 8417 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?, |
| 8387 | 8418 | } }; |
| 8388 | 8419 | } |
| ... | ... | @@ -8391,7 +8422,6 @@ pub const WipNamespaceType = struct { |
| 8391 | 8422 | tid: Zcu.PerThread.Id, |
| 8392 | 8423 | index: Index, |
| 8393 | 8424 | type_name_extra_index: u32, |
| 8394 | cau_extra_index: ?u32, | |
| 8395 | 8425 | namespace_extra_index: u32, |
| 8396 | 8426 | |
| 8397 | 8427 | pub fn setName( |
| ... | ... | @@ -8407,18 +8437,11 @@ pub const WipNamespaceType = struct { |
| 8407 | 8437 | pub fn finish( |
| 8408 | 8438 | wip: WipNamespaceType, |
| 8409 | 8439 | ip: *InternPool, |
| 8410 | analysis_owner: Cau.Index.Optional, | |
| 8411 | 8440 | namespace: NamespaceIndex, |
| 8412 | 8441 | ) Index { |
| 8413 | 8442 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); |
| 8414 | 8443 | const extra_items = extra.view().items(.@"0"); |
| 8415 | 8444 | |
| 8416 | if (wip.cau_extra_index) |i| { | |
| 8417 | extra_items[i] = @intFromEnum(analysis_owner.unwrap().?); | |
| 8418 | } else { | |
| 8419 | assert(analysis_owner == .none); | |
| 8420 | } | |
| 8421 | ||
| 8422 | 8445 | extra_items[wip.namespace_extra_index] = @intFromEnum(namespace); |
| 8423 | 8446 | |
| 8424 | 8447 | return wip.index; |
| ... | ... | @@ -8517,7 +8540,6 @@ pub fn getStructType( |
| 8517 | 8540 | ini.fields_len); // inits |
| 8518 | 8541 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{ |
| 8519 | 8542 | .name = undefined, // set by `finish` |
| 8520 | .cau = undefined, // set by `finish` | |
| 8521 | 8543 | .zir_index = zir_index, |
| 8522 | 8544 | .fields_len = ini.fields_len, |
| 8523 | 8545 | .namespace = undefined, // set by `finish` |
| ... | ... | @@ -8562,7 +8584,6 @@ pub fn getStructType( |
| 8562 | 8584 | .tid = tid, |
| 8563 | 8585 | .index = gop.put(), |
| 8564 | 8586 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?, |
| 8565 | .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "cau").?, | |
| 8566 | 8587 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?, |
| 8567 | 8588 | } }; |
| 8568 | 8589 | }, |
| ... | ... | @@ -8585,7 +8606,6 @@ pub fn getStructType( |
| 8585 | 8606 | 1); // names_map |
| 8586 | 8607 | const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{ |
| 8587 | 8608 | .name = undefined, // set by `finish` |
| 8588 | .cau = undefined, // set by `finish` | |
| 8589 | 8609 | .zir_index = zir_index, |
| 8590 | 8610 | .namespace = undefined, // set by `finish` |
| 8591 | 8611 | .fields_len = ini.fields_len, |
| ... | ... | @@ -8654,7 +8674,6 @@ pub fn getStructType( |
| 8654 | 8674 | .tid = tid, |
| 8655 | 8675 | .index = gop.put(), |
| 8656 | 8676 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?, |
| 8657 | .cau_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "cau").?, | |
| 8658 | 8677 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?, |
| 8659 | 8678 | } }; |
| 8660 | 8679 | } |
| ... | ... | @@ -8878,7 +8897,7 @@ pub fn getFuncDecl( |
| 8878 | 8897 | |
| 8879 | 8898 | const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{ |
| 8880 | 8899 | .analysis = .{ |
| 8881 | .state = .unreferenced, | |
| 8900 | .is_analyzed = false, | |
| 8882 | 8901 | .branch_hint = .none, |
| 8883 | 8902 | .is_noinline = key.is_noinline, |
| 8884 | 8903 | .calls_or_awaits_errorable_fn = false, |
| ... | ... | @@ -8987,7 +9006,7 @@ pub fn getFuncDeclIes( |
| 8987 | 9006 | |
| 8988 | 9007 | const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{ |
| 8989 | 9008 | .analysis = .{ |
| 8990 | .state = .unreferenced, | |
| 9009 | .is_analyzed = false, | |
| 8991 | 9010 | .branch_hint = .none, |
| 8992 | 9011 | .is_noinline = key.is_noinline, |
| 8993 | 9012 | .calls_or_awaits_errorable_fn = false, |
| ... | ... | @@ -9183,7 +9202,7 @@ pub fn getFuncInstance( |
| 9183 | 9202 | |
| 9184 | 9203 | const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{ |
| 9185 | 9204 | .analysis = .{ |
| 9186 | .state = .unreferenced, | |
| 9205 | .is_analyzed = false, | |
| 9187 | 9206 | .branch_hint = .none, |
| 9188 | 9207 | .is_noinline = arg.is_noinline, |
| 9189 | 9208 | .calls_or_awaits_errorable_fn = false, |
| ... | ... | @@ -9281,7 +9300,7 @@ pub fn getFuncInstanceIes( |
| 9281 | 9300 | |
| 9282 | 9301 | const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{ |
| 9283 | 9302 | .analysis = .{ |
| 9284 | .state = .unreferenced, | |
| 9303 | .is_analyzed = false, | |
| 9285 | 9304 | .branch_hint = .none, |
| 9286 | 9305 | .is_noinline = arg.is_noinline, |
| 9287 | 9306 | .calls_or_awaits_errorable_fn = false, |
| ... | ... | @@ -9390,7 +9409,7 @@ fn finishFuncInstance( |
| 9390 | 9409 | func_extra_index: u32, |
| 9391 | 9410 | ) Allocator.Error!void { |
| 9392 | 9411 | 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; | |
| 9394 | 9413 | |
| 9395 | 9414 | // TODO: improve this name |
| 9396 | 9415 | const nav_name = try ip.getOrPutStringFmt(gpa, tid, "{}__anon_{d}", .{ |
| ... | ... | @@ -9400,9 +9419,9 @@ fn finishFuncInstance( |
| 9400 | 9419 | .name = nav_name, |
| 9401 | 9420 | .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name), |
| 9402 | 9421 | .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", | |
| 9406 | 9425 | }); |
| 9407 | 9426 | |
| 9408 | 9427 | // Populate the owner_nav field which was left undefined until now. |
| ... | ... | @@ -9436,7 +9455,6 @@ pub const WipEnumType = struct { |
| 9436 | 9455 | index: Index, |
| 9437 | 9456 | tag_ty_index: u32, |
| 9438 | 9457 | type_name_extra_index: u32, |
| 9439 | cau_extra_index: u32, | |
| 9440 | 9458 | namespace_extra_index: u32, |
| 9441 | 9459 | names_map: MapIndex, |
| 9442 | 9460 | names_start: u32, |
| ... | ... | @@ -9456,13 +9474,11 @@ pub const WipEnumType = struct { |
| 9456 | 9474 | pub fn prepare( |
| 9457 | 9475 | wip: WipEnumType, |
| 9458 | 9476 | ip: *InternPool, |
| 9459 | analysis_owner: Cau.Index, | |
| 9460 | 9477 | namespace: NamespaceIndex, |
| 9461 | 9478 | ) void { |
| 9462 | 9479 | const extra = ip.getLocalShared(wip.tid).extra.acquire(); |
| 9463 | 9480 | const extra_items = extra.view().items(.@"0"); |
| 9464 | 9481 | |
| 9465 | extra_items[wip.cau_extra_index] = @intFromEnum(analysis_owner); | |
| 9466 | 9482 | extra_items[wip.namespace_extra_index] = @intFromEnum(namespace); |
| 9467 | 9483 | } |
| 9468 | 9484 | |
| ... | ... | @@ -9563,7 +9579,6 @@ pub fn getEnumType( |
| 9563 | 9579 | .reified => 2, // type_hash: PackedU64 |
| 9564 | 9580 | } + |
| 9565 | 9581 | // zig fmt: on |
| 9566 | 1 + // cau | |
| 9567 | 9582 | ini.fields_len); // field types |
| 9568 | 9583 | |
| 9569 | 9584 | const extra_index = addExtraAssumeCapacity(extra, EnumAuto{ |
| ... | ... | @@ -9584,8 +9599,6 @@ pub fn getEnumType( |
| 9584 | 9599 | .tag = .type_enum_auto, |
| 9585 | 9600 | .data = extra_index, |
| 9586 | 9601 | }); |
| 9587 | const cau_extra_index = extra.view().len; | |
| 9588 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | |
| 9589 | 9602 | switch (ini.key) { |
| 9590 | 9603 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9591 | 9604 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), |
| ... | ... | @@ -9598,7 +9611,6 @@ pub fn getEnumType( |
| 9598 | 9611 | .index = gop.put(), |
| 9599 | 9612 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?, |
| 9600 | 9613 | .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?, |
| 9601 | .cau_extra_index = @intCast(cau_extra_index), | |
| 9602 | 9614 | .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?, |
| 9603 | 9615 | .names_map = names_map, |
| 9604 | 9616 | .names_start = @intCast(names_start), |
| ... | ... | @@ -9623,7 +9635,6 @@ pub fn getEnumType( |
| 9623 | 9635 | .reified => 2, // type_hash: PackedU64 |
| 9624 | 9636 | } + |
| 9625 | 9637 | // zig fmt: on |
| 9626 | 1 + // cau | |
| 9627 | 9638 | ini.fields_len + // field types |
| 9628 | 9639 | ini.fields_len * @intFromBool(ini.has_values)); // field values |
| 9629 | 9640 | |
| ... | ... | @@ -9650,8 +9661,6 @@ pub fn getEnumType( |
| 9650 | 9661 | }, |
| 9651 | 9662 | .data = extra_index, |
| 9652 | 9663 | }); |
| 9653 | const cau_extra_index = extra.view().len; | |
| 9654 | extra.appendAssumeCapacity(undefined); // `cau` will be set by `finish` | |
| 9655 | 9664 | switch (ini.key) { |
| 9656 | 9665 | .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}), |
| 9657 | 9666 | .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}), |
| ... | ... | @@ -9668,7 +9677,6 @@ pub fn getEnumType( |
| 9668 | 9677 | .index = gop.put(), |
| 9669 | 9678 | .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?, |
| 9670 | 9679 | .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?, |
| 9671 | .cau_extra_index = @intCast(cau_extra_index), | |
| 9672 | 9680 | .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?, |
| 9673 | 9681 | .names_map = names_map, |
| 9674 | 9682 | .names_start = @intCast(names_start), |
| ... | ... | @@ -9865,7 +9873,6 @@ pub fn getOpaqueType( |
| 9865 | 9873 | .tid = tid, |
| 9866 | 9874 | .index = gop.put(), |
| 9867 | 9875 | .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?, |
| 9868 | .cau_extra_index = null, // opaques do not undergo type resolution | |
| 9869 | 9876 | .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?, |
| 9870 | 9877 | }, |
| 9871 | 9878 | }; |
| ... | ... | @@ -9981,7 +9988,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 { |
| 9981 | 9988 | inline for (@typeInfo(@TypeOf(item)).@"struct".fields) |field| { |
| 9982 | 9989 | extra.appendAssumeCapacity(.{switch (field.type) { |
| 9983 | 9990 | Index, |
| 9984 | Cau.Index, | |
| 9985 | 9991 | Nav.Index, |
| 9986 | 9992 | NamespaceIndex, |
| 9987 | 9993 | OptionalNamespaceIndex, |
| ... | ... | @@ -10044,7 +10050,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat |
| 10044 | 10050 | const extra_item = extra_items[extra_index]; |
| 10045 | 10051 | @field(result, field.name) = switch (field.type) { |
| 10046 | 10052 | Index, |
| 10047 | Cau.Index, | |
| 10048 | 10053 | Nav.Index, |
| 10049 | 10054 | NamespaceIndex, |
| 10050 | 10055 | OptionalNamespaceIndex, |
| ... | ... | @@ -11065,12 +11070,6 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator) |
| 11065 | 11070 | try bw.flush(); |
| 11066 | 11071 | } |
| 11067 | 11072 | |
| 11068 | pub 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 | ||
| 11074 | 11073 | pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav { |
| 11075 | 11074 | const unwrapped = index.unwrap(ip); |
| 11076 | 11075 | const navs = ip.getLocalShared(unwrapped.tid).navs.acquire(); |
| ... | ... | @@ -11084,51 +11083,34 @@ pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Names |
| 11084 | 11083 | return &namespaces_bucket[unwrapped_namespace_index.index]; |
| 11085 | 11084 | } |
| 11086 | 11085 | |
| 11087 | /// Create a `Cau` associated with the type at the given `InternPool.Index`. | |
| 11088 | pub fn createTypeCau( | |
| 11086 | /// Create a `ComptimeUnit`, forming an `AnalUnit` for a `comptime` declaration. | |
| 11087 | pub fn createComptimeUnit( | |
| 11089 | 11088 | ip: *InternPool, |
| 11090 | 11089 | gpa: Allocator, |
| 11091 | 11090 | tid: Zcu.PerThread.Id, |
| 11092 | 11091 | zir_index: TrackedInst.Index, |
| 11093 | 11092 | 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 = .{ | |
| 11098 | 11096 | .tid = tid, |
| 11099 | .index = caus.mutate.len, | |
| 11097 | .index = comptime_units.mutate.len, | |
| 11100 | 11098 | }; |
| 11101 | try caus.append(.{.{ | |
| 11099 | try comptime_units.append(.{.{ | |
| 11102 | 11100 | .zir_index = zir_index, |
| 11103 | 11101 | .namespace = namespace, |
| 11104 | .owner = Cau.Owner.wrap(.{ .type = owner_type }), | |
| 11105 | 11102 | }}); |
| 11106 | return index_unwrapped.wrap(ip); | |
| 11103 | return id_unwrapped.wrap(ip); | |
| 11107 | 11104 | } |
| 11108 | 11105 | |
| 11109 | /// Create a `Cau` for a `comptime` declaration. | |
| 11110 | pub 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); | |
| 11106 | pub 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]; | |
| 11128 | 11110 | } |
| 11129 | 11111 | |
| 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. | |
| 11132 | 11114 | pub fn createNav( |
| 11133 | 11115 | ip: *InternPool, |
| 11134 | 11116 | gpa: Allocator, |
| ... | ... | @@ -11150,8 +11132,8 @@ pub fn createNav( |
| 11150 | 11132 | try navs.append(Nav.pack(.{ |
| 11151 | 11133 | .name = opts.name, |
| 11152 | 11134 | .fqn = opts.fqn, |
| 11153 | .analysis_owner = .none, | |
| 11154 | .status = .{ .resolved = .{ | |
| 11135 | .analysis = null, | |
| 11136 | .status = .{ .fully_resolved = .{ | |
| 11155 | 11137 | .val = opts.val, |
| 11156 | 11138 | .alignment = opts.alignment, |
| 11157 | 11139 | .@"linksection" = opts.@"linksection", |
| ... | ... | @@ -11162,10 +11144,9 @@ pub fn createNav( |
| 11162 | 11144 | return index_unwrapped.wrap(ip); |
| 11163 | 11145 | } |
| 11164 | 11146 | |
| 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. | |
| 11168 | pub 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. | |
| 11149 | pub fn createDeclNav( | |
| 11169 | 11150 | ip: *InternPool, |
| 11170 | 11151 | gpa: Allocator, |
| 11171 | 11152 | tid: Zcu.PerThread.Id, |
| ... | ... | @@ -11175,36 +11156,72 @@ pub fn createPairedCauNav( |
| 11175 | 11156 | namespace: NamespaceIndex, |
| 11176 | 11157 | /// TODO: this is hacky! See `Nav.is_usingnamespace`. |
| 11177 | 11158 | is_usingnamespace: bool, |
| 11178 | ) Allocator.Error!struct { Cau.Index, Nav.Index } { | |
| 11179 | const caus = ip.getLocal(tid).getMutableCaus(gpa); | |
| 11159 | ) Allocator.Error!Nav.Index { | |
| 11180 | 11160 | const navs = ip.getLocal(tid).getMutableNavs(gpa); |
| 11181 | 11161 | |
| 11182 | try caus.ensureUnusedCapacity(1); | |
| 11183 | 11162 | try navs.ensureUnusedCapacity(1); |
| 11184 | 11163 | |
| 11185 | const cau = Cau.Index.Unwrapped.wrap(.{ | |
| 11186 | .tid = tid, | |
| 11187 | .index = caus.mutate.len, | |
| 11188 | }, ip); | |
| 11189 | 11164 | const nav = Nav.Index.Unwrapped.wrap(.{ |
| 11190 | 11165 | .tid = tid, |
| 11191 | 11166 | .index = navs.mutate.len, |
| 11192 | 11167 | }, ip); |
| 11193 | 11168 | |
| 11194 | caus.appendAssumeCapacity(.{.{ | |
| 11195 | .zir_index = zir_index, | |
| 11196 | .namespace = namespace, | |
| 11197 | .owner = Cau.Owner.wrap(.{ .nav = nav }), | |
| 11198 | }}); | |
| 11199 | 11169 | navs.appendAssumeCapacity(Nav.pack(.{ |
| 11200 | 11170 | .name = name, |
| 11201 | 11171 | .fqn = fqn, |
| 11202 | .analysis_owner = cau.toOptional(), | |
| 11172 | .analysis = .{ | |
| 11173 | .namespace = namespace, | |
| 11174 | .zir_index = zir_index, | |
| 11175 | }, | |
| 11203 | 11176 | .status = .unresolved, |
| 11204 | 11177 | .is_usingnamespace = is_usingnamespace, |
| 11205 | 11178 | })); |
| 11206 | 11179 | |
| 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. | |
| 11185 | pub 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); | |
| 11208 | 11225 | } |
| 11209 | 11226 | |
| 11210 | 11227 | /// Resolve the value of a `Nav` with an analysis owner. |
| ... | ... | @@ -11227,18 +11244,20 @@ pub fn resolveNavValue( |
| 11227 | 11244 | |
| 11228 | 11245 | const navs = local.shared.navs.view(); |
| 11229 | 11246 | |
| 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); | |
| 11232 | 11250 | const nav_linksections = navs.items(.@"linksection"); |
| 11233 | 11251 | const nav_bits = navs.items(.bits); |
| 11234 | 11252 | |
| 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); | |
| 11236 | 11255 | |
| 11237 | 11256 | @atomicStore(InternPool.Index, &nav_vals[unwrapped.index], resolved.val, .release); |
| 11238 | 11257 | @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release); |
| 11239 | 11258 | |
| 11240 | 11259 | var bits = nav_bits[unwrapped.index]; |
| 11241 | bits.status = .resolved; | |
| 11260 | bits.status = .fully_resolved; | |
| 11242 | 11261 | bits.alignment = resolved.alignment; |
| 11243 | 11262 | bits.@"addrspace" = resolved.@"addrspace"; |
| 11244 | 11263 | @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release); |
src/Sema.zig+273-404| ... | ... | @@ -1284,7 +1284,6 @@ fn analyzeBodyInner( |
| 1284 | 1284 | const extended = datas[@intFromEnum(inst)].extended; |
| 1285 | 1285 | break :ext switch (extended.opcode) { |
| 1286 | 1286 | // zig fmt: off |
| 1287 | .variable => try sema.zirVarExtended( block, extended), | |
| 1288 | 1287 | .struct_decl => try sema.zirStructDecl( block, extended, inst), |
| 1289 | 1288 | .enum_decl => try sema.zirEnumDecl( block, extended, inst), |
| 1290 | 1289 | .union_decl => try sema.zirUnionDecl( block, extended, inst), |
| ... | ... | @@ -2114,13 +2113,33 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) |
| 2114 | 2113 | } |
| 2115 | 2114 | |
| 2116 | 2115 | /// 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. | |
| 2118 | 2116 | /// Generic poison causes `error.GenericPoison` to be returned. |
| 2119 | 2117 | fn 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 | } | |
| 2124 | 2143 | } |
| 2125 | 2144 | |
| 2126 | 2145 | /// 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 { |
| 2183 | 2202 | return try sema.resolveLazyValue(val); |
| 2184 | 2203 | } |
| 2185 | 2204 | |
| 2186 | /// Returns all InternPool keys representing values, including `variable`, `undef`, and `generic_poison`. | |
| 2187 | fn 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 | ||
| 2215 | 2205 | /// Value Tag may be `undef` or `variable`. |
| 2216 | 2206 | pub fn resolveFinalDeclValue( |
| 2217 | 2207 | sema: *Sema, |
| ... | ... | @@ -2221,8 +2211,13 @@ pub fn resolveFinalDeclValue( |
| 2221 | 2211 | ) CompileError!Value { |
| 2222 | 2212 | const zcu = sema.pt.zcu; |
| 2223 | 2213 | |
| 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) | |
| 2226 | 2221 | "thread local and dll imported variables have runtime-known addresses" |
| 2227 | 2222 | else |
| 2228 | 2223 | null; |
| ... | ... | @@ -2232,10 +2227,8 @@ pub fn resolveFinalDeclValue( |
| 2232 | 2227 | .value_comptime_reason = value_comptime_reason, |
| 2233 | 2228 | }); |
| 2234 | 2229 | }; |
| 2235 | if (val.isGenericPoison()) return error.GenericPoison; | |
| 2236 | 2230 | |
| 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)) { | |
| 2239 | 2232 | return sema.fail(block, src, "global variable contains reference to comptime var", .{}); |
| 2240 | 2233 | } |
| 2241 | 2234 | |
| ... | ... | @@ -2877,7 +2870,7 @@ fn zirStructDecl( |
| 2877 | 2870 | }; |
| 2878 | 2871 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, struct_init, false)) { |
| 2879 | 2872 | .existing => |ty| { |
| 2880 | const new_ty = try pt.ensureTypeUpToDate(ty, false); | |
| 2873 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 2881 | 2874 | |
| 2882 | 2875 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 2883 | 2876 | // up on e.g. changed comptime decls. |
| ... | ... | @@ -2907,12 +2900,10 @@ fn zirStructDecl( |
| 2907 | 2900 | }); |
| 2908 | 2901 | errdefer pt.destroyNamespace(new_namespace_index); |
| 2909 | 2902 | |
| 2910 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 2911 | ||
| 2912 | 2903 | if (pt.zcu.comp.incremental) { |
| 2913 | 2904 | try ip.addDependency( |
| 2914 | 2905 | sema.gpa, |
| 2915 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 2906 | AnalUnit.wrap(.{ .type = wip_ty.index }), | |
| 2916 | 2907 | .{ .src_hash = tracked_inst }, |
| 2917 | 2908 | ); |
| 2918 | 2909 | } |
| ... | ... | @@ -2929,7 +2920,7 @@ fn zirStructDecl( |
| 2929 | 2920 | } |
| 2930 | 2921 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 2931 | 2922 | 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)); | |
| 2933 | 2924 | } |
| 2934 | 2925 | |
| 2935 | 2926 | fn createTypeName( |
| ... | ... | @@ -3107,7 +3098,7 @@ fn zirEnumDecl( |
| 3107 | 3098 | }; |
| 3108 | 3099 | const wip_ty = switch (try ip.getEnumType(gpa, pt.tid, enum_init, false)) { |
| 3109 | 3100 | .existing => |ty| { |
| 3110 | const new_ty = try pt.ensureTypeUpToDate(ty, false); | |
| 3101 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3111 | 3102 | |
| 3112 | 3103 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3113 | 3104 | // up on e.g. changed comptime decls. |
| ... | ... | @@ -3143,16 +3134,14 @@ fn zirEnumDecl( |
| 3143 | 3134 | }); |
| 3144 | 3135 | errdefer if (!done) pt.destroyNamespace(new_namespace_index); |
| 3145 | 3136 | |
| 3146 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 3147 | ||
| 3148 | 3137 | try pt.scanNamespace(new_namespace_index, decls); |
| 3149 | 3138 | |
| 3150 | 3139 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 3151 | 3140 | try sema.addTypeReferenceEntry(src, wip_ty.index); |
| 3152 | 3141 | |
| 3153 | 3142 | // 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); | |
| 3156 | 3145 | done = true; |
| 3157 | 3146 | |
| 3158 | 3147 | try Sema.resolveDeclaredEnum( |
| ... | ... | @@ -3162,7 +3151,6 @@ fn zirEnumDecl( |
| 3162 | 3151 | tracked_inst, |
| 3163 | 3152 | new_namespace_index, |
| 3164 | 3153 | type_name, |
| 3165 | new_cau_index, | |
| 3166 | 3154 | small, |
| 3167 | 3155 | body, |
| 3168 | 3156 | tag_type_ref, |
| ... | ... | @@ -3252,7 +3240,7 @@ fn zirUnionDecl( |
| 3252 | 3240 | }; |
| 3253 | 3241 | const wip_ty = switch (try ip.getUnionType(gpa, pt.tid, union_init, false)) { |
| 3254 | 3242 | .existing => |ty| { |
| 3255 | const new_ty = try pt.ensureTypeUpToDate(ty, false); | |
| 3243 | const new_ty = try pt.ensureTypeUpToDate(ty); | |
| 3256 | 3244 | |
| 3257 | 3245 | // Make sure we update the namespace if the declaration is re-analyzed, to pick |
| 3258 | 3246 | // up on e.g. changed comptime decls. |
| ... | ... | @@ -3282,12 +3270,10 @@ fn zirUnionDecl( |
| 3282 | 3270 | }); |
| 3283 | 3271 | errdefer pt.destroyNamespace(new_namespace_index); |
| 3284 | 3272 | |
| 3285 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 3286 | ||
| 3287 | 3273 | if (pt.zcu.comp.incremental) { |
| 3288 | 3274 | try zcu.intern_pool.addDependency( |
| 3289 | 3275 | gpa, |
| 3290 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 3276 | AnalUnit.wrap(.{ .type = wip_ty.index }), | |
| 3291 | 3277 | .{ .src_hash = tracked_inst }, |
| 3292 | 3278 | ); |
| 3293 | 3279 | } |
| ... | ... | @@ -3304,7 +3290,7 @@ fn zirUnionDecl( |
| 3304 | 3290 | } |
| 3305 | 3291 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 3306 | 3292 | 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)); | |
| 3308 | 3294 | } |
| 3309 | 3295 | |
| 3310 | 3296 | fn zirOpaqueDecl( |
| ... | ... | @@ -3389,7 +3375,7 @@ fn zirOpaqueDecl( |
| 3389 | 3375 | try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 3390 | 3376 | } |
| 3391 | 3377 | 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)); | |
| 3393 | 3379 | } |
| 3394 | 3380 | |
| 3395 | 3381 | fn zirErrorSetDecl( |
| ... | ... | @@ -6509,9 +6495,9 @@ pub fn analyzeExport( |
| 6509 | 6495 | if (options.linkage == .internal) |
| 6510 | 6496 | return; |
| 6511 | 6497 | |
| 6512 | try sema.ensureNavResolved(src, orig_nav_index); | |
| 6498 | try sema.ensureNavResolved(src, orig_nav_index, .fully); | |
| 6513 | 6499 | |
| 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)) { | |
| 6515 | 6501 | .variable => |v| v.owner_nav, |
| 6516 | 6502 | .@"extern" => |e| e.owner_nav, |
| 6517 | 6503 | .func => |f| f.owner_nav, |
| ... | ... | @@ -6534,7 +6520,7 @@ pub fn analyzeExport( |
| 6534 | 6520 | } |
| 6535 | 6521 | |
| 6536 | 6522 | // TODO: some backends might support re-exporting extern decls |
| 6537 | if (exported_nav.isExtern(ip)) { | |
| 6523 | if (exported_nav.getExtern(ip) != null) { | |
| 6538 | 6524 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 6539 | 6525 | } |
| 6540 | 6526 | |
| ... | ... | @@ -6554,7 +6540,11 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void { |
| 6554 | 6540 | const ip = &zcu.intern_pool; |
| 6555 | 6541 | const func = switch (sema.owner.unwrap()) { |
| 6556 | 6542 | .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 | |
| 6558 | 6548 | }; |
| 6559 | 6549 | ip.funcSetDisableInstrumentation(func); |
| 6560 | 6550 | sema.allow_memoize = false; |
| ... | ... | @@ -6865,8 +6855,8 @@ fn lookupInNamespace( |
| 6865 | 6855 | } |
| 6866 | 6856 | |
| 6867 | 6857 | 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); | |
| 6870 | 6860 | const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu)); |
| 6871 | 6861 | try checked_namespaces.put(gpa, sub_ns, {}); |
| 6872 | 6862 | } |
| ... | ... | @@ -6875,11 +6865,8 @@ fn lookupInNamespace( |
| 6875 | 6865 | |
| 6876 | 6866 | ignore_self: { |
| 6877 | 6867 | 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, | |
| 6883 | 6870 | }; |
| 6884 | 6871 | var i: usize = 0; |
| 6885 | 6872 | while (i < candidates.items.len) { |
| ... | ... | @@ -7139,7 +7126,7 @@ fn zirCall( |
| 7139 | 7126 | const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); |
| 7140 | 7127 | |
| 7141 | 7128 | switch (sema.owner.unwrap()) { |
| 7142 | .cau => input_is_error = false, | |
| 7129 | .@"comptime", .type, .nav_ty, .nav_val => input_is_error = false, | |
| 7143 | 7130 | .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) { |
| 7144 | 7131 | // No errorable fn actually called; we have no error return trace |
| 7145 | 7132 | input_is_error = false; |
| ... | ... | @@ -7700,12 +7687,13 @@ fn analyzeCall( |
| 7700 | 7687 | .ptr => |ptr| blk: { |
| 7701 | 7688 | switch (ptr.base_addr) { |
| 7702 | 7689 | .nav => |nav_index| if (ptr.byte_offset == 0) { |
| 7690 | try sema.ensureNavResolved(call_src, nav_index, .fully); | |
| 7703 | 7691 | const nav = ip.getNav(nav_index); |
| 7704 | if (nav.isExtern(ip)) | |
| 7692 | if (nav.getExtern(ip) != null) | |
| 7705 | 7693 | return sema.fail(block, call_src, "{s} call of extern function pointer", .{ |
| 7706 | 7694 | if (is_comptime_call) "comptime" else "inline", |
| 7707 | 7695 | }); |
| 7708 | break :blk nav.status.resolved.val; | |
| 7696 | break :blk nav.status.fully_resolved.val; | |
| 7709 | 7697 | }, |
| 7710 | 7698 | else => {}, |
| 7711 | 7699 | } |
| ... | ... | @@ -7754,11 +7742,9 @@ fn analyzeCall( |
| 7754 | 7742 | // The call site definitely depends on the function's signature. |
| 7755 | 7743 | try sema.declareDependency(.{ .src_hash = module_fn.zir_body_inst }); |
| 7756 | 7744 | |
| 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`. | |
| 7759 | 7747 | 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); | |
| 7762 | 7748 | |
| 7763 | 7749 | // We effectively want a child Sema here, but can't literally do that, because we need AIR |
| 7764 | 7750 | // to be shared. InlineCallSema is a wrapper which handles this for us. While `ics` is in |
| ... | ... | @@ -7766,7 +7752,7 @@ fn analyzeCall( |
| 7766 | 7752 | // whenever performing an operation where the difference matters. |
| 7767 | 7753 | var ics = InlineCallSema.init( |
| 7768 | 7754 | sema, |
| 7769 | zcu.cauFileScope(fn_cau_index).zir, | |
| 7755 | zcu.navFileScope(module_fn.owner_nav).zir, | |
| 7770 | 7756 | module_fn_index, |
| 7771 | 7757 | block.error_return_trace_index, |
| 7772 | 7758 | ); |
| ... | ... | @@ -7776,7 +7762,7 @@ fn analyzeCall( |
| 7776 | 7762 | .parent = null, |
| 7777 | 7763 | .sema = sema, |
| 7778 | 7764 | // The function body exists in the same namespace as the corresponding function declaration. |
| 7779 | .namespace = fn_cau.namespace, | |
| 7765 | .namespace = fn_nav.analysis.?.namespace, | |
| 7780 | 7766 | .instructions = .{}, |
| 7781 | 7767 | .label = null, |
| 7782 | 7768 | .inlining = &inlining, |
| ... | ... | @@ -7787,7 +7773,7 @@ fn analyzeCall( |
| 7787 | 7773 | .runtime_cond = block.runtime_cond, |
| 7788 | 7774 | .runtime_loop = block.runtime_loop, |
| 7789 | 7775 | .runtime_index = block.runtime_index, |
| 7790 | .src_base_inst = fn_cau.zir_index, | |
| 7776 | .src_base_inst = fn_nav.analysis.?.zir_index, | |
| 7791 | 7777 | .type_name_ctx = fn_nav.fqn, |
| 7792 | 7778 | }; |
| 7793 | 7779 | |
| ... | ... | @@ -7802,7 +7788,7 @@ fn analyzeCall( |
| 7802 | 7788 | // mutate comptime state. |
| 7803 | 7789 | // TODO: comptime call memoization is currently not supported under incremental compilation |
| 7804 | 7790 | // 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`. | |
| 7806 | 7792 | var should_memoize = !zcu.comp.incremental; |
| 7807 | 7793 | |
| 7808 | 7794 | // If it's a comptime function call, we need to memoize it as long as no external |
| ... | ... | @@ -7911,7 +7897,7 @@ fn analyzeCall( |
| 7911 | 7897 | |
| 7912 | 7898 | // Since we're doing an inline call, we depend on the source code of the whole |
| 7913 | 7899 | // function declaration. |
| 7914 | try sema.declareDependency(.{ .src_hash = fn_cau.zir_index }); | |
| 7900 | try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index }); | |
| 7915 | 7901 | |
| 7916 | 7902 | new_fn_info.return_type = sema.fn_ret_ty.toIntern(); |
| 7917 | 7903 | if (!is_comptime_call and !block.is_typeof) { |
| ... | ... | @@ -8023,7 +8009,7 @@ fn analyzeCall( |
| 8023 | 8009 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 8024 | 8010 | |
| 8025 | 8011 | switch (sema.owner.unwrap()) { |
| 8026 | .cau => {}, | |
| 8012 | .@"comptime", .nav_ty, .nav_val, .type => {}, | |
| 8027 | 8013 | .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) { |
| 8028 | 8014 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); |
| 8029 | 8015 | }, |
| ... | ... | @@ -8062,7 +8048,10 @@ fn analyzeCall( |
| 8062 | 8048 | switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { |
| 8063 | 8049 | .func => break :skip_safety, |
| 8064 | 8050 | .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 | }, | |
| 8066 | 8055 | else => {}, |
| 8067 | 8056 | }, |
| 8068 | 8057 | else => {}, |
| ... | ... | @@ -8259,7 +8248,7 @@ fn instantiateGenericCall( |
| 8259 | 8248 | }); |
| 8260 | 8249 | const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) { |
| 8261 | 8250 | .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, | |
| 8263 | 8252 | else => unreachable, |
| 8264 | 8253 | }; |
| 8265 | 8254 | const generic_owner_func = zcu.intern_pool.indexToKey(generic_owner).func; |
| ... | ... | @@ -8275,10 +8264,9 @@ fn instantiateGenericCall( |
| 8275 | 8264 | // The actual monomorphization happens via adding `func_instance` to |
| 8276 | 8265 | // `InternPool`. |
| 8277 | 8266 | |
| 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. | |
| 8279 | 8268 | 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; | |
| 8282 | 8270 | const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail); |
| 8283 | 8271 | |
| 8284 | 8272 | const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count()); |
| ... | ... | @@ -8319,11 +8307,11 @@ fn instantiateGenericCall( |
| 8319 | 8307 | var child_block: Block = .{ |
| 8320 | 8308 | .parent = null, |
| 8321 | 8309 | .sema = &child_sema, |
| 8322 | .namespace = fn_cau.namespace, | |
| 8310 | .namespace = fn_nav.analysis.?.namespace, | |
| 8323 | 8311 | .instructions = .{}, |
| 8324 | 8312 | .inlining = null, |
| 8325 | 8313 | .is_comptime = true, |
| 8326 | .src_base_inst = fn_cau.zir_index, | |
| 8314 | .src_base_inst = fn_nav.analysis.?.zir_index, | |
| 8327 | 8315 | .type_name_ctx = fn_nav.fqn, |
| 8328 | 8316 | }; |
| 8329 | 8317 | defer child_block.instructions.deinit(gpa); |
| ... | ... | @@ -8488,7 +8476,7 @@ fn instantiateGenericCall( |
| 8488 | 8476 | if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); |
| 8489 | 8477 | |
| 8490 | 8478 | switch (sema.owner.unwrap()) { |
| 8491 | .cau => {}, | |
| 8479 | .@"comptime", .nav_ty, .nav_val, .type => {}, | |
| 8492 | 8480 | .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) { |
| 8493 | 8481 | ip.funcSetCallsOrAwaitsErrorableFn(owner_func); |
| 8494 | 8482 | }, |
| ... | ... | @@ -9517,16 +9505,13 @@ fn zirFunc( |
| 9517 | 9505 | // the callconv based on whether it is exported. Otherwise, the callconv defaults |
| 9518 | 9506 | // to `.auto`. |
| 9519 | 9507 | 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; | |
| 9526 | 9511 | 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"; | |
| 9530 | 9515 | }; |
| 9531 | 9516 | if (fn_is_exported) { |
| 9532 | 9517 | break :cc target.cCallingConvention() orelse { |
| ... | ... | @@ -9557,10 +9542,8 @@ fn zirFunc( |
| 9557 | 9542 | ret_ty, |
| 9558 | 9543 | false, |
| 9559 | 9544 | inferred_error_set, |
| 9560 | false, | |
| 9561 | 9545 | has_body, |
| 9562 | 9546 | src_locs, |
| 9563 | null, | |
| 9564 | 9547 | 0, |
| 9565 | 9548 | false, |
| 9566 | 9549 | ); |
| ... | ... | @@ -9619,7 +9602,7 @@ fn resolveGenericBody( |
| 9619 | 9602 | /// respective `Decl` (either `ExternFn` or `Var`). |
| 9620 | 9603 | /// The liveness of the duped library name is tied to liveness of `Zcu`. |
| 9621 | 9604 | /// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`). |
| 9622 | fn handleExternLibName( | |
| 9605 | pub fn handleExternLibName( | |
| 9623 | 9606 | sema: *Sema, |
| 9624 | 9607 | block: *Block, |
| 9625 | 9608 | src_loc: LazySrcLoc, |
| ... | ... | @@ -9843,10 +9826,8 @@ fn funcCommon( |
| 9843 | 9826 | bare_return_type: Type, |
| 9844 | 9827 | var_args: bool, |
| 9845 | 9828 | inferred_error_set: bool, |
| 9846 | is_extern: bool, | |
| 9847 | 9829 | has_body: bool, |
| 9848 | 9830 | src_locs: Zir.Inst.Func.SrcLocs, |
| 9849 | opt_lib_name: ?[]const u8, | |
| 9850 | 9831 | noalias_bits: u32, |
| 9851 | 9832 | is_noinline: bool, |
| 9852 | 9833 | ) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -9998,12 +9979,11 @@ fn funcCommon( |
| 9998 | 9979 | } |
| 9999 | 9980 | |
| 10000 | 9981 | if (inferred_error_set) { |
| 10001 | assert(!is_extern); | |
| 10002 | 9982 | assert(has_body); |
| 10003 | 9983 | if (!ret_poison) |
| 10004 | 9984 | try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src); |
| 10005 | 9985 | const func_index = try ip.getFuncDeclIes(gpa, pt.tid, .{ |
| 10006 | .owner_nav = sema.getOwnerCauNav(), | |
| 9986 | .owner_nav = sema.owner.unwrap().nav_val, | |
| 10007 | 9987 | |
| 10008 | 9988 | .param_types = param_types, |
| 10009 | 9989 | .noalias_bits = noalias_bits, |
| ... | ... | @@ -10050,35 +10030,9 @@ fn funcCommon( |
| 10050 | 10030 | .is_noinline = is_noinline, |
| 10051 | 10031 | }); |
| 10052 | 10032 | |
| 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 | ||
| 10079 | 10033 | if (has_body) { |
| 10080 | 10034 | const func_index = try ip.getFuncDecl(gpa, pt.tid, .{ |
| 10081 | .owner_nav = sema.getOwnerCauNav(), | |
| 10035 | .owner_nav = sema.owner.unwrap().nav_val, | |
| 10082 | 10036 | .ty = func_ty, |
| 10083 | 10037 | .cc = cc, |
| 10084 | 10038 | .is_noinline = is_noinline, |
| ... | ... | @@ -17702,7 +17656,7 @@ fn zirAsm( |
| 17702 | 17656 | if (is_volatile) { |
| 17703 | 17657 | return sema.fail(block, src, "volatile keyword is redundant on module-level assembly", .{}); |
| 17704 | 17658 | } |
| 17705 | try zcu.addGlobalAssembly(sema.owner.unwrap().cau, asm_source); | |
| 17659 | try zcu.addGlobalAssembly(sema.owner, asm_source); | |
| 17706 | 17660 | return .void_value; |
| 17707 | 17661 | } |
| 17708 | 17662 | |
| ... | ... | @@ -18193,7 +18147,7 @@ fn zirThis( |
| 18193 | 18147 | _ = extended; |
| 18194 | 18148 | const pt = sema.pt; |
| 18195 | 18149 | 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); | |
| 18197 | 18151 | switch (pt.zcu.intern_pool.indexToKey(new_ty)) { |
| 18198 | 18152 | .struct_type, .union_type, .enum_type => try sema.declareDependency(.{ .interned = new_ty }), |
| 18199 | 18153 | .opaque_type => {}, |
| ... | ... | @@ -19359,13 +19313,11 @@ fn typeInfoNamespaceDecls( |
| 19359 | 19313 | } |
| 19360 | 19314 | |
| 19361 | 19315 | 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; | |
| 19366 | 19318 | } |
| 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); | |
| 19369 | 19321 | try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces); |
| 19370 | 19322 | } |
| 19371 | 19323 | } |
| ... | ... | @@ -21225,14 +21177,13 @@ fn structInitAnon( |
| 21225 | 21177 | .file_scope = block.getFileScopeIndex(zcu), |
| 21226 | 21178 | .generation = zcu.generation, |
| 21227 | 21179 | }); |
| 21228 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip.index); | |
| 21229 | 21180 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index }); |
| 21230 | 21181 | codegen_type: { |
| 21231 | 21182 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| 21232 | 21183 | if (block.ownerModule().strip) break :codegen_type; |
| 21233 | 21184 | try zcu.comp.queueJob(.{ .codegen_type = wip.index }); |
| 21234 | 21185 | } |
| 21235 | break :ty wip.finish(ip, new_cau_index.toOptional(), new_namespace_index); | |
| 21186 | break :ty wip.finish(ip, new_namespace_index); | |
| 21236 | 21187 | }, |
| 21237 | 21188 | .existing => |ty| ty, |
| 21238 | 21189 | }; |
| ... | ... | @@ -21656,7 +21607,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref { |
| 21656 | 21607 | .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) { |
| 21657 | 21608 | return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty); |
| 21658 | 21609 | }, |
| 21659 | .cau => {}, | |
| 21610 | .@"comptime", .nav_ty, .nav_val, .type => {}, | |
| 21660 | 21611 | } |
| 21661 | 21612 | return Air.internedToRef(try pt.intern(.{ .opt = .{ |
| 21662 | 21613 | .ty = opt_ptr_stack_trace_ty.toIntern(), |
| ... | ... | @@ -22334,7 +22285,7 @@ fn zirReify( |
| 22334 | 22285 | }); |
| 22335 | 22286 | |
| 22336 | 22287 | 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)); | |
| 22338 | 22289 | }, |
| 22339 | 22290 | .@"union" => { |
| 22340 | 22291 | const struct_type = ip.loadStructType(ip.typeOf(union_val.val)); |
| ... | ... | @@ -22543,11 +22494,9 @@ fn reifyEnum( |
| 22543 | 22494 | .generation = zcu.generation, |
| 22544 | 22495 | }); |
| 22545 | 22496 | |
| 22546 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 22547 | ||
| 22548 | 22497 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 22549 | 22498 | 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); | |
| 22551 | 22500 | wip_ty.setTagTy(ip, tag_ty.toIntern()); |
| 22552 | 22501 | done = true; |
| 22553 | 22502 | |
| ... | ... | @@ -22849,8 +22798,6 @@ fn reifyUnion( |
| 22849 | 22798 | .generation = zcu.generation, |
| 22850 | 22799 | }); |
| 22851 | 22800 | |
| 22852 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 22853 | ||
| 22854 | 22801 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 22855 | 22802 | codegen_type: { |
| 22856 | 22803 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| ... | ... | @@ -22860,7 +22807,7 @@ fn reifyUnion( |
| 22860 | 22807 | } |
| 22861 | 22808 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 22862 | 22809 | 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)); | |
| 22864 | 22811 | } |
| 22865 | 22812 | |
| 22866 | 22813 | fn reifyTuple( |
| ... | ... | @@ -23208,8 +23155,6 @@ fn reifyStruct( |
| 23208 | 23155 | .generation = zcu.generation, |
| 23209 | 23156 | }); |
| 23210 | 23157 | |
| 23211 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, tracked_inst, new_namespace_index, wip_ty.index); | |
| 23212 | ||
| 23213 | 23158 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 23214 | 23159 | codegen_type: { |
| 23215 | 23160 | if (zcu.comp.config.use_llvm) break :codegen_type; |
| ... | ... | @@ -23219,7 +23164,7 @@ fn reifyStruct( |
| 23219 | 23164 | } |
| 23220 | 23165 | try sema.declareDependency(.{ .interned = wip_ty.index }); |
| 23221 | 23166 | 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)); | |
| 23223 | 23168 | } |
| 23224 | 23169 | |
| 23225 | 23170 | fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -26711,135 +26656,6 @@ fn zirAwaitNosuspend( |
| 26711 | 26656 | return sema.failWithUseOfAsync(block, src); |
| 26712 | 26657 | } |
| 26713 | 26658 | |
| 26714 | fn 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 | ||
| 26783 | fn 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 | ||
| 26843 | 26659 | fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 26844 | 26660 | const tracy = trace(@src()); |
| 26845 | 26661 | defer tracy.end(); |
| ... | ... | @@ -26857,13 +26673,6 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 26857 | 26673 | |
| 26858 | 26674 | var extra_index: usize = extra.end; |
| 26859 | 26675 | |
| 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 | ||
| 26867 | 26676 | const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: { |
| 26868 | 26677 | const body_len = sema.code.extra[extra_index]; |
| 26869 | 26678 | extra_index += 1; |
| ... | ... | @@ -26887,16 +26696,14 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 26887 | 26696 | break :blk try sema.analyzeValueAsCallconv(block, cc_src, cc_val); |
| 26888 | 26697 | } else cc: { |
| 26889 | 26698 | 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: { | |
| 26891 | 26700 | // Generic instance -- use the original function declaration to |
| 26892 | 26701 | // 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") { | |
| 26900 | 26707 | break :cc target.cCallingConvention() orelse { |
| 26901 | 26708 | // This target has no default C calling convention. We sometimes trigger a similar |
| 26902 | 26709 | // 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 |
| 26958 | 26765 | |
| 26959 | 26766 | const is_var_args = extra.data.bits.is_var_args; |
| 26960 | 26767 | const is_inferred_error = extra.data.bits.is_inferred_error; |
| 26961 | const is_extern = extra.data.bits.is_extern; | |
| 26962 | 26768 | const is_noinline = extra.data.bits.is_noinline; |
| 26963 | 26769 | |
| 26964 | 26770 | return sema.funcCommon( |
| ... | ... | @@ -26969,10 +26775,8 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 26969 | 26775 | ret_ty, |
| 26970 | 26776 | is_var_args, |
| 26971 | 26777 | is_inferred_error, |
| 26972 | is_extern, | |
| 26973 | 26778 | has_body, |
| 26974 | 26779 | src_locs, |
| 26975 | lib_name, | |
| 26976 | 26780 | noalias_bits, |
| 26977 | 26781 | is_noinline, |
| 26978 | 26782 | ); |
| ... | ... | @@ -27285,8 +27089,16 @@ fn zirBuiltinExtern( |
| 27285 | 27089 | // `builtin_extern` doesn't provide enough information, and isn't currently tracked. |
| 27286 | 27090 | // So, for now, just use our containing `declaration`. |
| 27287 | 27091 | .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 | }, | |
| 27290 | 27102 | }, |
| 27291 | 27103 | .owner_nav = undefined, // ignored by `getExtern` |
| 27292 | 27104 | }); |
| ... | ... | @@ -27467,7 +27279,7 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: |
| 27467 | 27279 | } |
| 27468 | 27280 | |
| 27469 | 27281 | /// Emit a compile error if type cannot be used for a runtime variable. |
| 27470 | fn validateVarType( | |
| 27282 | pub fn validateVarType( | |
| 27471 | 27283 | sema: *Sema, |
| 27472 | 27284 | block: *Block, |
| 27473 | 27285 | src: LazySrcLoc, |
| ... | ... | @@ -27934,7 +27746,7 @@ fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.Pan |
| 27934 | 27746 | error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, |
| 27935 | 27747 | error.OutOfMemory => |e| return e, |
| 27936 | 27748 | }).?; |
| 27937 | try sema.ensureNavResolved(src, msg_nav_index); | |
| 27749 | try sema.ensureNavResolved(src, msg_nav_index, .fully); | |
| 27938 | 27750 | zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional(); |
| 27939 | 27751 | return msg_nav_index; |
| 27940 | 27752 | } |
| ... | ... | @@ -29881,7 +29693,7 @@ fn elemPtrSlice( |
| 29881 | 29693 | return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty); |
| 29882 | 29694 | } |
| 29883 | 29695 | |
| 29884 | fn coerce( | |
| 29696 | pub fn coerce( | |
| 29885 | 29697 | sema: *Sema, |
| 29886 | 29698 | block: *Block, |
| 29887 | 29699 | dest_ty_unresolved: Type, |
| ... | ... | @@ -32841,34 +32653,45 @@ fn addTypeReferenceEntry( |
| 32841 | 32653 | try zcu.addTypeReference(sema.owner, referenced_type, src); |
| 32842 | 32654 | } |
| 32843 | 32655 | |
| 32844 | pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!void { | |
| 32656 | pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void { | |
| 32845 | 32657 | const pt = sema.pt; |
| 32846 | 32658 | const zcu = pt.zcu; |
| 32847 | 32659 | const ip = &zcu.intern_pool; |
| 32848 | 32660 | |
| 32849 | 32661 | 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); | |
| 32853 | 32664 | return; |
| 32854 | }; | |
| 32665 | } | |
| 32855 | 32666 | |
| 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 | }); | |
| 32858 | 32671 | |
| 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. | |
| 32860 | 32674 | |
| 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 | }); | |
| 32862 | 32679 | try sema.addReferenceEntry(src, anal_unit); |
| 32863 | 32680 | |
| 32864 | 32681 | if (zcu.analysis_in_progress.contains(anal_unit)) { |
| 32865 | 32682 | 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, | |
| 32867 | 32684 | .offset = LazySrcLoc.Offset.nodeOffset(0), |
| 32868 | 32685 | }, "dependency loop detected", .{})); |
| 32869 | 32686 | } |
| 32870 | 32687 | |
| 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 | } | |
| 32872 | 32695 | } |
| 32873 | 32696 | |
| 32874 | 32697 | fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { |
| ... | ... | @@ -32887,36 +32710,44 @@ fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) |
| 32887 | 32710 | return sema.analyzeNavRefInner(src, nav_index, true); |
| 32888 | 32711 | } |
| 32889 | 32712 | |
| 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. | |
| 32894 | fn 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`. | |
| 32716 | fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref { | |
| 32895 | 32717 | const pt = sema.pt; |
| 32896 | 32718 | const zcu = pt.zcu; |
| 32897 | 32719 | const ip = &zcu.intern_pool; |
| 32898 | 32720 | |
| 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 | }; | |
| 32902 | 32736 | |
| 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) }, | |
| 32909 | 32741 | }; |
| 32910 | const nav_info = ip.getNav(nav_index).status.resolved; | |
| 32911 | 32742 | const ptr_ty = try pt.ptrTypeSema(.{ |
| 32912 | .child = nav_val.typeOf(zcu).toIntern(), | |
| 32743 | .child = ty, | |
| 32913 | 32744 | .flags = .{ |
| 32914 | .alignment = nav_info.alignment, | |
| 32745 | .alignment = alignment, | |
| 32915 | 32746 | .is_const = is_const, |
| 32916 | .address_space = nav_info.@"addrspace", | |
| 32747 | .address_space = @"addrspace", | |
| 32917 | 32748 | }, |
| 32918 | 32749 | }); |
| 32919 | if (analyze_fn_body) { | |
| 32750 | if (is_ref) { | |
| 32920 | 32751 | try sema.maybeQueueFuncBodyAnalysis(src, nav_index); |
| 32921 | 32752 | } |
| 32922 | 32753 | return Air.internedToRef((try pt.intern(.{ .ptr = .{ |
| ... | ... | @@ -32927,11 +32758,22 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N |
| 32927 | 32758 | } |
| 32928 | 32759 | |
| 32929 | 32760 | fn 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; | |
| 32931 | 32763 | 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); | |
| 32932 | 32774 | const nav_val = zcu.navValue(nav_index); |
| 32933 | 32775 | if (!ip.isFuncBody(nav_val.toIntern())) return; |
| 32934 | if (!try nav_val.typeOf(zcu).fnHasRuntimeBitsSema(sema.pt)) return; | |
| 32776 | ||
| 32935 | 32777 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() })); |
| 32936 | 32778 | try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern()); |
| 32937 | 32779 | } |
| ... | ... | @@ -35818,7 +35660,7 @@ pub fn resolveStructAlignment( |
| 35818 | 35660 | const ip = &zcu.intern_pool; |
| 35819 | 35661 | const target = zcu.getTarget(); |
| 35820 | 35662 | |
| 35821 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 35663 | assert(sema.owner.unwrap().type == ty); | |
| 35822 | 35664 | |
| 35823 | 35665 | assert(struct_type.layout != .@"packed"); |
| 35824 | 35666 | assert(struct_type.flagsUnordered(ip).alignment == .none); |
| ... | ... | @@ -35861,7 +35703,7 @@ pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void { |
| 35861 | 35703 | const ip = &zcu.intern_pool; |
| 35862 | 35704 | const struct_type = zcu.typeToStruct(ty) orelse return; |
| 35863 | 35705 | |
| 35864 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 35706 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 35865 | 35707 | |
| 35866 | 35708 | if (struct_type.haveLayout(ip)) |
| 35867 | 35709 | return; |
| ... | ... | @@ -36008,15 +35850,13 @@ fn backingIntType( |
| 36008 | 35850 | const gpa = zcu.gpa; |
| 36009 | 35851 | const ip = &zcu.intern_pool; |
| 36010 | 35852 | |
| 36011 | const cau_index = struct_type.cau; | |
| 36012 | ||
| 36013 | 35853 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| 36014 | 35854 | defer analysis_arena.deinit(); |
| 36015 | 35855 | |
| 36016 | 35856 | var block: Block = .{ |
| 36017 | 35857 | .parent = null, |
| 36018 | 35858 | .sema = sema, |
| 36019 | .namespace = ip.getCau(cau_index).namespace, | |
| 35859 | .namespace = struct_type.namespace, | |
| 36020 | 35860 | .instructions = .{}, |
| 36021 | 35861 | .inlining = null, |
| 36022 | 35862 | .is_comptime = true, |
| ... | ... | @@ -36148,7 +35988,7 @@ pub fn resolveUnionAlignment( |
| 36148 | 35988 | const ip = &zcu.intern_pool; |
| 36149 | 35989 | const target = zcu.getTarget(); |
| 36150 | 35990 | |
| 36151 | assert(sema.owner.unwrap().cau == union_type.cau); | |
| 35991 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36152 | 35992 | |
| 36153 | 35993 | assert(!union_type.haveLayout(ip)); |
| 36154 | 35994 | |
| ... | ... | @@ -36188,7 +36028,7 @@ pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void { |
| 36188 | 36028 | // Load again, since the tag type might have changed due to resolution. |
| 36189 | 36029 | const union_type = ip.loadUnionType(ty.ip_index); |
| 36190 | 36030 | |
| 36191 | assert(sema.owner.unwrap().cau == union_type.cau); | |
| 36031 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36192 | 36032 | |
| 36193 | 36033 | const old_flags = union_type.flagsUnordered(ip); |
| 36194 | 36034 | switch (old_flags.status) { |
| ... | ... | @@ -36303,7 +36143,7 @@ pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void { |
| 36303 | 36143 | const ip = &zcu.intern_pool; |
| 36304 | 36144 | const struct_type = zcu.typeToStruct(ty).?; |
| 36305 | 36145 | |
| 36306 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 36146 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36307 | 36147 | |
| 36308 | 36148 | if (struct_type.setFullyResolved(ip)) return; |
| 36309 | 36149 | errdefer struct_type.clearFullyResolved(ip); |
| ... | ... | @@ -36326,7 +36166,7 @@ pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void { |
| 36326 | 36166 | const ip = &zcu.intern_pool; |
| 36327 | 36167 | const union_obj = zcu.typeToUnion(ty).?; |
| 36328 | 36168 | |
| 36329 | assert(sema.owner.unwrap().cau == union_obj.cau); | |
| 36169 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36330 | 36170 | |
| 36331 | 36171 | switch (union_obj.flagsUnordered(ip).status) { |
| 36332 | 36172 | .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {}, |
| ... | ... | @@ -36361,7 +36201,7 @@ pub fn resolveStructFieldTypes( |
| 36361 | 36201 | const zcu = pt.zcu; |
| 36362 | 36202 | const ip = &zcu.intern_pool; |
| 36363 | 36203 | |
| 36364 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 36204 | assert(sema.owner.unwrap().type == ty); | |
| 36365 | 36205 | |
| 36366 | 36206 | if (struct_type.haveFieldTypes(ip)) return; |
| 36367 | 36207 | |
| ... | ... | @@ -36387,7 +36227,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void { |
| 36387 | 36227 | const ip = &zcu.intern_pool; |
| 36388 | 36228 | const struct_type = zcu.typeToStruct(ty) orelse return; |
| 36389 | 36229 | |
| 36390 | assert(sema.owner.unwrap().cau == struct_type.cau); | |
| 36230 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36391 | 36231 | |
| 36392 | 36232 | // Inits can start as resolved |
| 36393 | 36233 | if (struct_type.haveFieldInits(ip)) return; |
| ... | ... | @@ -36416,7 +36256,7 @@ pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.Load |
| 36416 | 36256 | const zcu = pt.zcu; |
| 36417 | 36257 | const ip = &zcu.intern_pool; |
| 36418 | 36258 | |
| 36419 | assert(sema.owner.unwrap().cau == union_type.cau); | |
| 36259 | assert(sema.owner.unwrap().type == ty.toIntern()); | |
| 36420 | 36260 | |
| 36421 | 36261 | switch (union_type.flagsUnordered(ip).status) { |
| 36422 | 36262 | .none => {}, |
| ... | ... | @@ -36492,7 +36332,7 @@ fn resolveInferredErrorSet( |
| 36492 | 36332 | // In this case we are dealing with the actual InferredErrorSet object that |
| 36493 | 36333 | // corresponds to the function, not one created to track an inline/comptime call. |
| 36494 | 36334 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index })); |
| 36495 | try pt.ensureFuncBodyAnalyzed(func_index); | |
| 36335 | try pt.ensureFuncBodyUpToDate(func_index); | |
| 36496 | 36336 | } |
| 36497 | 36337 | |
| 36498 | 36338 | // This will now have been resolved by the logic at the end of `Zcu.analyzeFnBody` |
| ... | ... | @@ -36649,8 +36489,7 @@ fn structFields( |
| 36649 | 36489 | const zcu = pt.zcu; |
| 36650 | 36490 | const gpa = zcu.gpa; |
| 36651 | 36491 | 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; | |
| 36654 | 36493 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; |
| 36655 | 36494 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; |
| 36656 | 36495 | |
| ... | ... | @@ -36848,8 +36687,7 @@ fn structFieldInits( |
| 36848 | 36687 | |
| 36849 | 36688 | assert(!struct_type.haveFieldInits(ip)); |
| 36850 | 36689 | |
| 36851 | const cau_index = struct_type.cau; | |
| 36852 | const namespace_index = ip.getCau(cau_index).namespace; | |
| 36690 | const namespace_index = struct_type.namespace; | |
| 36853 | 36691 | const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir; |
| 36854 | 36692 | const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail; |
| 36855 | 36693 | const fields_len, _, var extra_index = structZirInfo(zir, zir_index); |
| ... | ... | @@ -38650,14 +38488,17 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { |
| 38650 | 38488 | // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would |
| 38651 | 38489 | // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve |
| 38652 | 38490 | // the loop. |
| 38491 | // Note that this also disallows a `nav_val` | |
| 38653 | 38492 | 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, | |
| 38658 | 38495 | else => {}, |
| 38659 | 38496 | }, |
| 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 => {}, | |
| 38661 | 38502 | } |
| 38662 | 38503 | |
| 38663 | 38504 | try zcu.intern_pool.addDependency(sema.gpa, sema.owner, dependee); |
| ... | ... | @@ -38836,45 +38677,6 @@ pub fn flushExports(sema: *Sema) !void { |
| 38836 | 38677 | } |
| 38837 | 38678 | } |
| 38838 | 38679 | |
| 38839 | /// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches | |
| 38840 | /// the corresponding `Nav`. | |
| 38841 | fn 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`. | |
| 38848 | fn 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. | |
| 38855 | fn 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. | |
| 38864 | fn 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 | ||
| 38878 | 38680 | /// Called as soon as a `declared` enum type is created. |
| 38879 | 38681 | /// Resolves the tag type and field inits. |
| 38880 | 38682 | /// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this. |
| ... | ... | @@ -38885,7 +38687,6 @@ pub fn resolveDeclaredEnum( |
| 38885 | 38687 | tracked_inst: InternPool.TrackedInst.Index, |
| 38886 | 38688 | namespace: InternPool.NamespaceIndex, |
| 38887 | 38689 | type_name: InternPool.NullTerminatedString, |
| 38888 | enum_cau: InternPool.Cau.Index, | |
| 38889 | 38690 | small: Zir.Inst.EnumDecl.Small, |
| 38890 | 38691 | body: []const Zir.Inst.Index, |
| 38891 | 38692 | tag_type_ref: Zir.Inst.Ref, |
| ... | ... | @@ -38903,7 +38704,7 @@ pub fn resolveDeclaredEnum( |
| 38903 | 38704 | const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(0) }; |
| 38904 | 38705 | const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = 0 } }; |
| 38905 | 38706 | |
| 38906 | const anal_unit = AnalUnit.wrap(.{ .cau = enum_cau }); | |
| 38707 | const anal_unit = AnalUnit.wrap(.{ .type = wip_ty.index }); | |
| 38907 | 38708 | |
| 38908 | 38709 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 38909 | 38710 | defer arena.deinit(); |
| ... | ... | @@ -39115,8 +38916,8 @@ fn getBuiltinInnerType( |
| 39115 | 38916 | const nav = opt_nav orelse return sema.fail(block, src, "std.builtin.{s} missing {s}", .{ |
| 39116 | 38917 | compile_error_parent_name, inner_name, |
| 39117 | 38918 | }); |
| 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); | |
| 39120 | 38921 | const ty = val.toType(); |
| 39121 | 38922 | try ty.resolveFully(pt); |
| 39122 | 38923 | return ty; |
| ... | ... | @@ -39127,6 +38928,74 @@ fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref { |
| 39127 | 38928 | const zcu = pt.zcu; |
| 39128 | 38929 | const ip = &zcu.intern_pool; |
| 39129 | 38930 | 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 | ||
| 38935 | pub const NavPtrModifiers = struct { | |
| 38936 | alignment: Alignment, | |
| 38937 | @"linksection": InternPool.OptionalNullTerminatedString, | |
| 38938 | @"addrspace": std.builtin.AddressSpace, | |
| 38939 | }; | |
| 38940 | ||
| 38941 | pub 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 | }; | |
| 39132 | 39001 | } |
src/Sema/comptime_ptr_access.zig+2-3| ... | ... | @@ -219,9 +219,8 @@ fn loadComptimePtrInner( |
| 219 | 219 | |
| 220 | 220 | const base_val: MutableValue = switch (ptr.base_addr) { |
| 221 | 221 | .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; | |
| 225 | 224 | switch (ip.indexToKey(val)) { |
| 226 | 225 | .variable => return .runtime_load, |
| 227 | 226 | // We let `.@"extern"` through here if it's a function. |
src/Type.zig+2-2| ... | ... | @@ -3851,7 +3851,7 @@ fn resolveStructInner( |
| 3851 | 3851 | const gpa = zcu.gpa; |
| 3852 | 3852 | |
| 3853 | 3853 | 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() }); | |
| 3855 | 3855 | |
| 3856 | 3856 | if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { |
| 3857 | 3857 | return error.AnalysisFail; |
| ... | ... | @@ -3905,7 +3905,7 @@ fn resolveUnionInner( |
| 3905 | 3905 | const gpa = zcu.gpa; |
| 3906 | 3906 | |
| 3907 | 3907 | 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() }); | |
| 3909 | 3909 | |
| 3910 | 3910 | if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) { |
| 3911 | 3911 | return error.AnalysisFail; |
src/Value.zig+6-1| ... | ... | @@ -1343,7 +1343,12 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool { |
| 1343 | 1343 | pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool { |
| 1344 | 1344 | const ip = &zcu.intern_pool; |
| 1345 | 1345 | 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)) { | |
| 1347 | 1352 | .@"extern" => |e| e.is_threadlocal or e.is_dll_import, |
| 1348 | 1353 | .variable => |v| v.is_threadlocal, |
| 1349 | 1354 | else => false, |
src/Zcu.zig+187-147| ... | ... | @@ -170,6 +170,9 @@ outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty, |
| 170 | 170 | /// it as outdated. |
| 171 | 171 | retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty, |
| 172 | 172 | |
| 173 | func_body_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty, | |
| 174 | nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, | |
| 175 | ||
| 173 | 176 | /// These are the modules which we initially queue for analysis in `Compilation.update`. |
| 174 | 177 | /// `resolveReferences` will use these as the root of its reachability traversal. |
| 175 | 178 | analysis_roots: std.BoundedArray(*Package.Module, 3) = .{}, |
| ... | ... | @@ -192,7 +195,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .empty, |
| 192 | 195 | |
| 193 | 196 | test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, |
| 194 | 197 | |
| 195 | global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .empty, | |
| 198 | global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty, | |
| 196 | 199 | |
| 197 | 200 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 198 | 201 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| ... | ... | @@ -282,7 +285,11 @@ pub const Exported = union(enum) { |
| 282 | 285 | |
| 283 | 286 | pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment { |
| 284 | 287 | 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 | }, | |
| 286 | 293 | .uav => .none, |
| 287 | 294 | }; |
| 288 | 295 | } |
| ... | ... | @@ -344,9 +351,12 @@ pub const Namespace = struct { |
| 344 | 351 | pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty, |
| 345 | 352 | /// All `usingnamespace` declarations in this namespace which are *not* marked `pub`. |
| 346 | 353 | 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, | |
| 350 | 360 | |
| 351 | 361 | pub const Index = InternPool.NamespaceIndex; |
| 352 | 362 | pub const OptionalIndex = InternPool.OptionalNamespaceIndex; |
| ... | ... | @@ -2238,6 +2248,9 @@ pub fn deinit(zcu: *Zcu) void { |
| 2238 | 2248 | zcu.outdated_ready.deinit(gpa); |
| 2239 | 2249 | zcu.retryable_failures.deinit(gpa); |
| 2240 | 2250 | |
| 2251 | zcu.func_body_analysis_queued.deinit(gpa); | |
| 2252 | zcu.nav_val_analysis_queued.deinit(gpa); | |
| 2253 | ||
| 2241 | 2254 | zcu.test_functions.deinit(gpa); |
| 2242 | 2255 | |
| 2243 | 2256 | for (zcu.global_assembly.values()) |s| { |
| ... | ... | @@ -2436,11 +2449,10 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2436 | 2449 | // If this is a Decl, we must recursively mark dependencies on its tyval |
| 2437 | 2450 | // as no longer PO. |
| 2438 | 2451 | 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 }), | |
| 2444 | 2456 | .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }), |
| 2445 | 2457 | } |
| 2446 | 2458 | } |
| ... | ... | @@ -2451,11 +2463,10 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 2451 | 2463 | fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void { |
| 2452 | 2464 | const ip = &zcu.intern_pool; |
| 2453 | 2465 | 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 }, | |
| 2459 | 2470 | .func => |func_index| .{ .interned = func_index }, // IES |
| 2460 | 2471 | }; |
| 2461 | 2472 | log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)}); |
| ... | ... | @@ -2512,14 +2523,14 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2512 | 2523 | } |
| 2513 | 2524 | |
| 2514 | 2525 | // 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! | |
| 2519 | 2530 | |
| 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 | |
| 2521 | 2532 | // 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 | |
| 2523 | 2534 | // which the most things depend on - the idea is that this will resolve a lot of loops (but this |
| 2524 | 2535 | // is only a heuristic). |
| 2525 | 2536 | |
| ... | ... | @@ -2530,33 +2541,29 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2530 | 2541 | |
| 2531 | 2542 | const ip = &zcu.intern_pool; |
| 2532 | 2543 | |
| 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; | |
| 2535 | 2546 | |
| 2536 | 2547 | inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| { |
| 2537 | 2548 | 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 | ||
| 2544 | 2549 | 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 | |
| 2547 | 2553 | .type => |ty| .{ .interned = ty }, |
| 2548 | .nav => |nav| .{ .nav_val = nav }, | |
| 2554 | .nav_val => |nav| .{ .nav_val = nav }, | |
| 2555 | .nav_ty => |nav| .{ .nav_ty = nav }, | |
| 2549 | 2556 | }); |
| 2550 | 2557 | while (it.next()) |_| n += 1; |
| 2551 | 2558 | |
| 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; | |
| 2555 | 2562 | } |
| 2556 | 2563 | } |
| 2557 | 2564 | } |
| 2558 | 2565 | |
| 2559 | if (chosen_cau == null) { | |
| 2566 | if (chosen_unit == null) { | |
| 2560 | 2567 | for (zcu.outdated.keys(), zcu.outdated.values()) |o, opod| { |
| 2561 | 2568 | const func = o.unwrap().func; |
| 2562 | 2569 | const nav = zcu.funcInfo(func).owner_nav; |
| ... | ... | @@ -2570,11 +2577,11 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { |
| 2570 | 2577 | } |
| 2571 | 2578 | |
| 2572 | 2579 | 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, | |
| 2575 | 2582 | }); |
| 2576 | 2583 | |
| 2577 | return AnalUnit.wrap(.{ .cau = chosen_cau.? }); | |
| 2584 | return chosen_unit.?; | |
| 2578 | 2585 | } |
| 2579 | 2586 | |
| 2580 | 2587 | /// During an incremental update, before semantic analysis, call this to flush all values from |
| ... | ... | @@ -2679,24 +2686,14 @@ pub fn mapOldZirToNew( |
| 2679 | 2686 | { |
| 2680 | 2687 | var old_decl_it = old_zir.declIterator(match_item.old_inst); |
| 2681 | 2688 | 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) { | |
| 2684 | 2691 | .@"comptime" => try comptime_decls.append(gpa, old_decl_inst), |
| 2685 | 2692 | .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst), |
| 2686 | 2693 | .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), | |
| 2700 | 2697 | } |
| 2701 | 2698 | } |
| 2702 | 2699 | } |
| ... | ... | @@ -2707,7 +2704,7 @@ pub fn mapOldZirToNew( |
| 2707 | 2704 | |
| 2708 | 2705 | var new_decl_it = new_zir.declIterator(match_item.new_inst); |
| 2709 | 2706 | 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); | |
| 2711 | 2708 | // Attempt to match this to a declaration in the old ZIR: |
| 2712 | 2709 | // * For named declarations (`const`/`var`/`fn`), we match based on name. |
| 2713 | 2710 | // * For named tests (`test "foo"`) and decltests (`test foo`), we also match based on name. |
| ... | ... | @@ -2715,7 +2712,7 @@ pub fn mapOldZirToNew( |
| 2715 | 2712 | // * For comptime blocks, we match based on order. |
| 2716 | 2713 | // * For usingnamespace decls, we match based on order. |
| 2717 | 2714 | // 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) { | |
| 2719 | 2716 | .@"comptime" => inst: { |
| 2720 | 2717 | if (comptime_decl_idx == comptime_decls.items.len) continue; |
| 2721 | 2718 | defer comptime_decl_idx += 1; |
| ... | ... | @@ -2731,18 +2728,17 @@ pub fn mapOldZirToNew( |
| 2731 | 2728 | defer unnamed_test_idx += 1; |
| 2732 | 2729 | break :inst unnamed_tests.items[unnamed_test_idx]; |
| 2733 | 2730 | }, |
| 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; | |
| 2746 | 2742 | }, |
| 2747 | 2743 | }; |
| 2748 | 2744 | |
| ... | ... | @@ -2797,14 +2793,39 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo |
| 2797 | 2793 | const ip = &zcu.intern_pool; |
| 2798 | 2794 | const func = zcu.funcInfo(func_index); |
| 2799 | 2795 | |
| 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 | } | |
| 2804 | 2805 | } |
| 2805 | 2806 | |
| 2807 | try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1); | |
| 2806 | 2808 | try zcu.comp.queueJob(.{ .analyze_func = func_index }); |
| 2807 | func.setAnalysisState(ip, .queued); | |
| 2809 | zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {}); | |
| 2810 | } | |
| 2811 | ||
| 2812 | pub 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, {}); | |
| 2808 | 2829 | } |
| 2809 | 2830 | |
| 2810 | 2831 | pub const ImportFileResult = struct { |
| ... | ... | @@ -3030,9 +3051,9 @@ pub fn handleUpdateExports( |
| 3030 | 3051 | }; |
| 3031 | 3052 | } |
| 3032 | 3053 | |
| 3033 | pub fn addGlobalAssembly(zcu: *Zcu, cau: InternPool.Cau.Index, source: []const u8) !void { | |
| 3054 | pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void { | |
| 3034 | 3055 | const gpa = zcu.gpa; |
| 3035 | const gop = try zcu.global_assembly.getOrPut(gpa, cau); | |
| 3056 | const gop = try zcu.global_assembly.getOrPut(gpa, unit); | |
| 3036 | 3057 | if (gop.found_existing) { |
| 3037 | 3058 | const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source }); |
| 3038 | 3059 | gpa.free(gop.value_ptr.*); |
| ... | ... | @@ -3315,23 +3336,22 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3315 | 3336 | |
| 3316 | 3337 | log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}); |
| 3317 | 3338 | |
| 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, | |
| 3324 | 3344 | else => unreachable, |
| 3325 | 3345 | }; |
| 3326 | if (resolution_cau.unwrap()) |cau| { | |
| 3346 | if (has_resolution) { | |
| 3327 | 3347 | // this should only be referenced by the type |
| 3328 | const unit = AnalUnit.wrap(.{ .cau = cau }); | |
| 3348 | const unit: AnalUnit = .wrap(.{ .type = ty }); | |
| 3329 | 3349 | assert(!result.contains(unit)); |
| 3330 | 3350 | try unit_queue.putNoClobber(gpa, unit, referencer); |
| 3331 | 3351 | } |
| 3332 | 3352 | |
| 3333 | 3353 | // 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. | |
| 3335 | 3355 | if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| { |
| 3336 | 3356 | const tag_ty = union_obj.enum_tag_ty; |
| 3337 | 3357 | if (tag_ty != .none) { |
| ... | ... | @@ -3346,53 +3366,61 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3346 | 3366 | // Queue any decls within this type which would be automatically analyzed. |
| 3347 | 3367 | // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`. |
| 3348 | 3368 | 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; | |
| 3353 | 3384 | const file = zcu.fileByIndex(inst_info.file); |
| 3354 | 3385 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. |
| 3355 | 3386 | 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) { | |
| 3358 | 3392 | .@"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; | |
| 3370 | 3401 | break :a true; |
| 3371 | 3402 | }, |
| 3372 | 3403 | }; |
| 3373 | 3404 | 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); | |
| 3382 | 3411 | } |
| 3383 | 3412 | } |
| 3384 | 3413 | for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| { |
| 3385 | 3414 | // 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; | |
| 3388 | 3416 | const file = zcu.fileByIndex(inst_info.file); |
| 3389 | 3417 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. |
| 3390 | 3418 | 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 }); | |
| 3394 | 3422 | if (!result.contains(unit)) { |
| 3395 | log.debug("type '{}': ref cau %{}", .{ | |
| 3423 | log.debug("type '{}': ref named %{}", .{ | |
| 3396 | 3424 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 3397 | 3425 | @intFromEnum(inst_info.inst), |
| 3398 | 3426 | }); |
| ... | ... | @@ -3402,16 +3430,15 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3402 | 3430 | } |
| 3403 | 3431 | for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| { |
| 3404 | 3432 | // 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; | |
| 3407 | 3434 | const file = zcu.fileByIndex(inst_info.file); |
| 3408 | 3435 | // If the file failed AstGen, the TrackedInst refers to the old ZIR. |
| 3409 | 3436 | 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 }); | |
| 3413 | 3440 | if (!result.contains(unit)) { |
| 3414 | log.debug("type '{}': ref cau %{}", .{ | |
| 3441 | log.debug("type '{}': ref named %{}", .{ | |
| 3415 | 3442 | Type.fromInterned(ty).containerTypeName(ip).fmt(ip), |
| 3416 | 3443 | @intFromEnum(inst_info.inst), |
| 3417 | 3444 | }); |
| ... | ... | @@ -3422,13 +3449,11 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3422 | 3449 | // Incremental compilation does not support `usingnamespace`. |
| 3423 | 3450 | // These are only included to keep good reference traces in non-incremental updates. |
| 3424 | 3451 | 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 }); | |
| 3427 | 3453 | if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer); |
| 3428 | 3454 | } |
| 3429 | 3455 | 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 }); | |
| 3432 | 3457 | if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer); |
| 3433 | 3458 | } |
| 3434 | 3459 | continue; |
| ... | ... | @@ -3437,6 +3462,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv |
| 3437 | 3462 | const unit = kv.key; |
| 3438 | 3463 | try result.putNoClobber(gpa, unit, kv.value); |
| 3439 | 3464 | |
| 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 | ||
| 3440 | 3476 | log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)}); |
| 3441 | 3477 | |
| 3442 | 3478 | if (zcu.reference_table.get(unit)) |first_ref_idx| { |
| ... | ... | @@ -3522,13 +3558,11 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 { |
| 3522 | 3558 | const ip = &zcu.intern_pool; |
| 3523 | 3559 | const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?; |
| 3524 | 3560 | 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; | |
| 3528 | 3562 | } |
| 3529 | 3563 | |
| 3530 | 3564 | pub 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); | |
| 3532 | 3566 | } |
| 3533 | 3567 | |
| 3534 | 3568 | pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index { |
| ... | ... | @@ -3540,12 +3574,6 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { |
| 3540 | 3574 | return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); |
| 3541 | 3575 | } |
| 3542 | 3576 | |
| 3543 | pub 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 | ||
| 3549 | 3577 | pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) { |
| 3550 | 3578 | return .{ .data = .{ .unit = unit, .zcu = zcu } }; |
| 3551 | 3579 | } |
| ... | ... | @@ -3558,19 +3586,18 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co |
| 3558 | 3586 | const zcu = data.zcu; |
| 3559 | 3587 | const ip = &zcu.intern_pool; |
| 3560 | 3588 | 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>)"); | |
| 3572 | 3596 | } |
| 3573 | 3597 | }, |
| 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)}), | |
| 3574 | 3601 | .func => |func| { |
| 3575 | 3602 | const nav = zcu.funcInfo(func).owner_nav; |
| 3576 | 3603 | return writer.print("func('{}')", .{ip.getNav(nav).fqn.fmt(ip)}); |
| ... | ... | @@ -3595,7 +3622,11 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com |
| 3595 | 3622 | }, |
| 3596 | 3623 | .nav_val => |nav| { |
| 3597 | 3624 | 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)}); | |
| 3599 | 3630 | }, |
| 3600 | 3631 | .interned => |ip_index| switch (ip.indexToKey(ip_index)) { |
| 3601 | 3632 | .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 |
| 3772 | 3803 | if (!backend_ok) return .{ .bad_backend = backend }; |
| 3773 | 3804 | return .ok; |
| 3774 | 3805 | } |
| 3806 | ||
| 3807 | /// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer. | |
| 3808 | pub 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 { |
| 469 | 469 | { |
| 470 | 470 | var it = old_zir.declIterator(old_inst); |
| 471 | 471 | 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; | |
| 478 | 474 | const name_ip = try zcu.intern_pool.getOrPutString( |
| 479 | 475 | zcu.gpa, |
| 480 | 476 | pt.tid, |
| ... | ... | @@ -488,12 +484,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 488 | 484 | { |
| 489 | 485 | var it = new_zir.declIterator(new_inst); |
| 490 | 486 | 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; | |
| 497 | 489 | const name_ip = try zcu.intern_pool.getOrPutString( |
| 498 | 490 | zcu.gpa, |
| 499 | 491 | pt.tid, |
| ... | ... | @@ -553,118 +545,643 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 553 | 545 | pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 554 | 546 | const file_root_type = pt.zcu.fileRootType(file_index); |
| 555 | 547 | if (file_root_type != .none) { |
| 556 | _ = try pt.ensureTypeUpToDate(file_root_type, false); | |
| 548 | _ = try pt.ensureTypeUpToDate(file_root_type); | |
| 557 | 549 | } else { |
| 558 | 550 | return pt.semaFile(file_index); |
| 559 | 551 | } |
| 560 | 552 | } |
| 561 | 553 | |
| 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. | |
| 565 | pub 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. | |
| 557 | pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu.SemaError!void { | |
| 566 | 558 | const tracy = trace(@src()); |
| 567 | 559 | defer tracy.end(); |
| 568 | 560 | |
| 569 | 561 | const zcu = pt.zcu; |
| 570 | 562 | const gpa = zcu.gpa; |
| 571 | const ip = &zcu.intern_pool; | |
| 572 | 563 | |
| 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 }); | |
| 575 | 565 | |
| 576 | log.debug("ensureCauAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 566 | log.debug("ensureComptimeUnitUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 577 | 567 | |
| 578 | 568 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 579 | 569 | |
| 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`. | |
| 589 | 578 | |
| 590 | const cau_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 579 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 591 | 580 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 592 | 581 | |
| 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) { | |
| 596 | 583 | _ = 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 | } | |
| 597 | 593 | } 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 | } | |
| 600 | 611 | 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. | |
| 632 | fn 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. | |
| 712 | pub 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); | |
| 601 | 763 | } |
| 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, | |
| 610 | 771 | } |
| 611 | 772 | } |
| 612 | 773 | |
| 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) { | |
| 621 | 784 | error.AnalysisFail => res: { |
| 622 | 785 | 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`. | |
| 624 | 787 | // Since it does not, this must be a transitive failure. |
| 625 | 788 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); |
| 626 | 789 | log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)}); |
| 627 | 790 | } |
| 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 }; | |
| 639 | 792 | }, |
| 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 | ||
| 824 | fn 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 | })); | |
| 655 | 994 | }, |
| 656 | 995 | }; |
| 657 | 996 | |
| 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 | ||
| 1103 | pub 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, | |
| 665 | 1157 | }; |
| 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 | }; | |
| 666 | 1181 | |
| 667 | if (invalidate) { | |
| 1182 | if (was_outdated) { | |
| 1183 | const dependee: InternPool.Dependee = .{ .nav_ty = nav_id }; | |
| 1184 | if (invalidate_type) { | |
| 668 | 1185 | // This dependency was marked as PO, meaning dependees were waiting |
| 669 | 1186 | // on its analysis result, and it has turned out to be outdated. |
| 670 | 1187 | // Update dependees accordingly. |
| ... | ... | @@ -676,67 +1193,151 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 676 | 1193 | } |
| 677 | 1194 | } |
| 678 | 1195 | |
| 679 | if (analysis_fail) return error.AnalysisFail; | |
| 680 | } | |
| 1196 | if (new_failed) return error.AnalysisFail; | |
| 1197 | } | |
| 1198 | ||
| 1199 | fn 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 | }; | |
| 681 | 1281 | |
| 682 | fn 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 }); | |
| 689 | 1283 | |
| 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 | }; | |
| 692 | 1289 | |
| 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); | |
| 694 | 1293 | |
| 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 | }; | |
| 708 | 1301 | |
| 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 | }; | |
| 712 | 1324 | |
| 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 }; | |
| 725 | 1326 | |
| 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 | }); | |
| 732 | 1336 | |
| 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 }; | |
| 737 | 1338 | } |
| 738 | 1339 | |
| 739 | pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void { | |
| 1340 | pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void { | |
| 740 | 1341 | dev.check(.sema); |
| 741 | 1342 | |
| 742 | 1343 | const tracy = trace(@src()); |
| ... | ... | @@ -746,35 +1347,43 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 746 | 1347 | const gpa = zcu.gpa; |
| 747 | 1348 | const ip = &zcu.intern_pool; |
| 748 | 1349 | |
| 1350 | _ = zcu.func_body_analysis_queued.swapRemove(maybe_coerced_func_index); | |
| 1351 | ||
| 749 | 1352 | // We only care about the uncoerced function. |
| 750 | 1353 | 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 }); | |
| 752 | 1355 | |
| 753 | log.debug("ensureFuncBodyAnalyzed {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1356 | log.debug("ensureFuncBodyUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 754 | 1357 | |
| 755 | 1358 | const func = zcu.funcInfo(maybe_coerced_func_index); |
| 756 | 1359 | |
| 757 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 1360 | const was_outdated = zcu.outdated.swapRemove(anal_unit) or | |
| 758 | 1361 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 759 | 1362 | |
| 760 | 1363 | const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit); |
| 761 | 1364 | |
| 762 | if (func_outdated) { | |
| 1365 | if (was_outdated) { | |
| 1366 | dev.check(.incremental); | |
| 763 | 1367 | _ = 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); | |
| 764 | 1374 | } else { |
| 765 | 1375 | // We can trust the current information about this function. |
| 766 | 1376 | if (prev_failed) { |
| 767 | 1377 | return error.AnalysisFail; |
| 768 | 1378 | } |
| 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; | |
| 774 | 1380 | } |
| 775 | 1381 | |
| 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 } | |
| 778 | 1387 | else |err| switch (err) { |
| 779 | 1388 | error.AnalysisFail => res: { |
| 780 | 1389 | if (!zcu.failed_analysis.contains(anal_unit)) { |
| ... | ... | @@ -788,10 +1397,18 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 788 | 1397 | // a different error later (which may now be invalid). |
| 789 | 1398 | break :res .{ !prev_failed, true }; |
| 790 | 1399 | }, |
| 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 | }, | |
| 792 | 1409 | }; |
| 793 | 1410 | |
| 794 | if (func_outdated) { | |
| 1411 | if (was_outdated) { | |
| 795 | 1412 | if (ies_outdated) { |
| 796 | 1413 | try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index }); |
| 797 | 1414 | } else { |
| ... | ... | @@ -799,13 +1416,12 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 799 | 1416 | } |
| 800 | 1417 | } |
| 801 | 1418 | |
| 802 | if (analysis_fail) return error.AnalysisFail; | |
| 1419 | if (new_failed) return error.AnalysisFail; | |
| 803 | 1420 | } |
| 804 | 1421 | |
| 805 | fn ensureFuncBodyAnalyzedInner( | |
| 1422 | fn analyzeFuncBody( | |
| 806 | 1423 | pt: Zcu.PerThread, |
| 807 | 1424 | func_index: InternPool.Index, |
| 808 | func_outdated: bool, | |
| 809 | 1425 | ) Zcu.SemaError!struct { ies_outdated: bool } { |
| 810 | 1426 | const zcu = pt.zcu; |
| 811 | 1427 | const gpa = zcu.gpa; |
| ... | ... | @@ -820,8 +1436,8 @@ fn ensureFuncBodyAnalyzedInner( |
| 820 | 1436 | |
| 821 | 1437 | if (func.generic_owner == .none) { |
| 822 | 1438 | // 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) { | |
| 825 | 1441 | // This function is no longer referenced! There's no point in re-analyzing it. |
| 826 | 1442 | // Just mark a transitive failure and move on. |
| 827 | 1443 | return error.AnalysisFail; |
| ... | ... | @@ -829,8 +1445,8 @@ fn ensureFuncBodyAnalyzedInner( |
| 829 | 1445 | } else { |
| 830 | 1446 | const go_nav = zcu.funcInfo(func.generic_owner).owner_nav; |
| 831 | 1447 | // 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) { | |
| 834 | 1450 | // The generic owner is no longer referenced, so this function is also unreferenced. |
| 835 | 1451 | // There's no point in re-analyzing it. Just mark a transitive failure and move on. |
| 836 | 1452 | return error.AnalysisFail; |
| ... | ... | @@ -844,38 +1460,13 @@ fn ensureFuncBodyAnalyzedInner( |
| 844 | 1460 | else |
| 845 | 1461 | .none; |
| 846 | 1462 | |
| 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)}); | |
| 873 | 1464 | |
| 874 | var air = try pt.analyzeFnBody(func_index); | |
| 1465 | var air = try pt.analyzeFnBodyInner(func_index); | |
| 875 | 1466 | errdefer air.deinit(gpa); |
| 876 | 1467 | |
| 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; | |
| 879 | 1470 | |
| 880 | 1471 | const comp = zcu.comp; |
| 881 | 1472 | |
| ... | ... | @@ -1043,12 +1634,11 @@ fn createFileRootStruct( |
| 1043 | 1634 | |
| 1044 | 1635 | wip_ty.setName(ip, try file.internFullyQualifiedName(pt)); |
| 1045 | 1636 | 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); | |
| 1047 | 1637 | |
| 1048 | 1638 | if (zcu.comp.incremental) { |
| 1049 | 1639 | try ip.addDependency( |
| 1050 | 1640 | gpa, |
| 1051 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 1641 | .wrap(.{ .type = wip_ty.index }), | |
| 1052 | 1642 | .{ .src_hash = tracked_inst }, |
| 1053 | 1643 | ); |
| 1054 | 1644 | } |
| ... | ... | @@ -1062,7 +1652,7 @@ fn createFileRootStruct( |
| 1062 | 1652 | try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index }); |
| 1063 | 1653 | } |
| 1064 | 1654 | 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); | |
| 1066 | 1656 | } |
| 1067 | 1657 | |
| 1068 | 1658 | /// 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 { |
| 1155 | 1745 | } |
| 1156 | 1746 | } |
| 1157 | 1747 | |
| 1158 | const 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. | |
| 1169 | fn 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 | ||
| 1446 | 1748 | pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult { |
| 1447 | 1749 | const zcu = pt.zcu; |
| 1448 | 1750 | const gpa = zcu.gpa; |
| ... | ... | @@ -1813,45 +2115,42 @@ pub fn scanNamespace( |
| 1813 | 2115 | |
| 1814 | 2116 | // For incremental updates, `scanDecl` wants to look up existing decls by their ZIR index rather |
| 1815 | 2117 | // 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; | |
| 1818 | 2120 | defer existing_by_inst.deinit(gpa); |
| 1819 | 2121 | |
| 1820 | 2122 | try existing_by_inst.ensureTotalCapacity(gpa, @intCast( |
| 1821 | 2123 | namespace.pub_decls.count() + namespace.priv_decls.count() + |
| 1822 | 2124 | 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, | |
| 1824 | 2127 | )); |
| 1825 | 2128 | |
| 1826 | 2129 | 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 })); | |
| 1830 | 2132 | } |
| 1831 | 2133 | 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 })); | |
| 1835 | 2136 | } |
| 1836 | 2137 | 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 })); | |
| 1840 | 2140 | } |
| 1841 | 2141 | 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); | |
| 1855 | 2154 | } |
| 1856 | 2155 | |
| 1857 | 2156 | var seen_decls: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty; |
| ... | ... | @@ -1861,7 +2160,8 @@ pub fn scanNamespace( |
| 1861 | 2160 | namespace.priv_decls.clearRetainingCapacity(); |
| 1862 | 2161 | namespace.pub_usingnamespace.clearRetainingCapacity(); |
| 1863 | 2162 | namespace.priv_usingnamespace.clearRetainingCapacity(); |
| 1864 | namespace.other_decls.clearRetainingCapacity(); | |
| 2163 | namespace.comptime_decls.clearRetainingCapacity(); | |
| 2164 | namespace.test_decls.clearRetainingCapacity(); | |
| 1865 | 2165 | |
| 1866 | 2166 | var scan_decl_iter: ScanDeclIter = .{ |
| 1867 | 2167 | .pt = pt, |
| ... | ... | @@ -1883,7 +2183,7 @@ const ScanDeclIter = struct { |
| 1883 | 2183 | pt: Zcu.PerThread, |
| 1884 | 2184 | namespace_index: Zcu.Namespace.Index, |
| 1885 | 2185 | 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), | |
| 1887 | 2187 | /// Decl scanning is run in two passes, so that we can detect when a generated |
| 1888 | 2188 | /// name would clash with an explicit name and use a different one. |
| 1889 | 2189 | pass: enum { named, unnamed }, |
| ... | ... | @@ -1919,64 +2219,41 @@ const ScanDeclIter = struct { |
| 1919 | 2219 | const zir = file.zir; |
| 1920 | 2220 | const ip = &zcu.intern_pool; |
| 1921 | 2221 | |
| 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); | |
| 1925 | 2223 | |
| 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: { | |
| 1930 | 2226 | if (iter.pass != .unnamed) return; |
| 1931 | break :info .{ | |
| 1932 | .none, | |
| 1933 | .@"comptime", | |
| 1934 | false, | |
| 1935 | }; | |
| 2227 | break :name .none; | |
| 1936 | 2228 | }, |
| 1937 | .@"usingnamespace" => info: { | |
| 2229 | .@"usingnamespace" => name: { | |
| 1938 | 2230 | if (iter.pass != .unnamed) return; |
| 1939 | 2231 | const i = iter.usingnamespace_index; |
| 1940 | 2232 | 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(); | |
| 1946 | 2234 | }, |
| 1947 | .unnamed_test => info: { | |
| 2235 | .unnamed_test => name: { | |
| 1948 | 2236 | if (iter.pass != .unnamed) return; |
| 1949 | 2237 | const i = iter.unnamed_test_index; |
| 1950 | 2238 | 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(); | |
| 1956 | 2240 | }, |
| 1957 | _ => if (declaration.name.isNamedTest(zir)) info: { | |
| 2241 | .@"test", .decltest => |kind| name: { | |
| 1958 | 2242 | // We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary. |
| 1959 | 2243 | 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: { | |
| 1967 | 2248 | if (iter.pass != .named) return; |
| 1968 | 2249 | const name = try ip.getOrPutString( |
| 1969 | 2250 | gpa, |
| 1970 | 2251 | pt.tid, |
| 1971 | zir.nullTerminatedString(declaration.name.toString(zir).?), | |
| 2252 | zir.nullTerminatedString(decl.name), | |
| 1972 | 2253 | .no_embedded_nulls, |
| 1973 | 2254 | ); |
| 1974 | 2255 | try iter.seen_decls.putNoClobber(gpa, name, {}); |
| 1975 | break :info .{ | |
| 1976 | name.toOptional(), | |
| 1977 | .named, | |
| 1978 | false, | |
| 1979 | }; | |
| 2256 | break :name name.toOptional(); | |
| 1980 | 2257 | }, |
| 1981 | 2258 | }; |
| 1982 | 2259 | |
| ... | ... | @@ -1985,60 +2262,59 @@ const ScanDeclIter = struct { |
| 1985 | 2262 | .inst = decl_inst, |
| 1986 | 2263 | }); |
| 1987 | 2264 | |
| 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); | |
| 1989 | 2273 | |
| 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 }); | |
| 1993 | 2275 | |
| 1994 | try namespace.other_decls.append(gpa, cau); | |
| 2276 | try namespace.comptime_decls.append(gpa, cu); | |
| 1995 | 2277 | |
| 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, {}); | |
| 2013 | 2285 | } |
| 2014 | 2286 | |
| 2015 | break :cau .{ cau, true }; | |
| 2287 | break :unit .{ unit, true }; | |
| 2016 | 2288 | }, |
| 2017 | else => cau: { | |
| 2289 | else => unit: { | |
| 2018 | 2290 | const name = maybe_name.unwrap().?; |
| 2019 | 2291 | 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) { | |
| 2028 | 2303 | .@"comptime" => unreachable, |
| 2029 | 2304 | .@"usingnamespace" => a: { |
| 2030 | 2305 | if (comp.incremental) { |
| 2031 | 2306 | @panic("'usingnamespace' is not supported by incremental compilation"); |
| 2032 | 2307 | } |
| 2033 | if (declaration.flags.is_pub) { | |
| 2308 | if (decl.is_pub) { | |
| 2034 | 2309 | try namespace.pub_usingnamespace.append(gpa, nav); |
| 2035 | 2310 | } else { |
| 2036 | 2311 | try namespace.priv_usingnamespace.append(gpa, nav); |
| 2037 | 2312 | } |
| 2038 | 2313 | break :a true; |
| 2039 | 2314 | }, |
| 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); | |
| 2042 | 2318 | // TODO: incremental compilation! |
| 2043 | 2319 | // * remove from `test_functions` if no longer matching filter |
| 2044 | 2320 | // * add to `test_functions` if newly passing filter |
| ... | ... | @@ -2046,7 +2322,7 @@ const ScanDeclIter = struct { |
| 2046 | 2322 | // Perhaps we should add all test indiscriminately and filter at the end of the update. |
| 2047 | 2323 | if (!comp.config.is_test) break :a false; |
| 2048 | 2324 | 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) { | |
| 2050 | 2326 | const fqn_slice = fqn.toSlice(ip); |
| 2051 | 2327 | for (comp.test_filters) |test_filter| { |
| 2052 | 2328 | if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break; |
| ... | ... | @@ -2055,8 +2331,8 @@ const ScanDeclIter = struct { |
| 2055 | 2331 | try zcu.test_functions.put(gpa, nav, {}); |
| 2056 | 2332 | break :a true; |
| 2057 | 2333 | }, |
| 2058 | .named => a: { | |
| 2059 | if (declaration.flags.is_pub) { | |
| 2334 | .@"const", .@"var" => a: { | |
| 2335 | if (decl.is_pub) { | |
| 2060 | 2336 | try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu }); |
| 2061 | 2337 | } else { |
| 2062 | 2338 | try namespace.priv_decls.putContext(gpa, nav, {}, .{ .zcu = zcu }); |
| ... | ... | @@ -2064,23 +2340,23 @@ const ScanDeclIter = struct { |
| 2064 | 2340 | break :a false; |
| 2065 | 2341 | }, |
| 2066 | 2342 | }; |
| 2067 | break :cau .{ cau, want_analysis }; | |
| 2343 | break :unit .{ unit, want_analysis }; | |
| 2068 | 2344 | }, |
| 2069 | 2345 | }; |
| 2070 | 2346 | |
| 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")) { | |
| 2072 | 2348 | 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) }, | |
| 2075 | 2351 | ); |
| 2076 | try comp.queueJob(.{ .analyze_cau = cau }); | |
| 2352 | try comp.queueJob(.{ .analyze_comptime_unit = unit }); | |
| 2077 | 2353 | } |
| 2078 | 2354 | |
| 2079 | 2355 | // TODO: we used to do line number updates here, but this is an inappropriate place for this logic to live. |
| 2080 | 2356 | } |
| 2081 | 2357 | }; |
| 2082 | 2358 | |
| 2083 | fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | |
| 2359 | fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | |
| 2084 | 2360 | const tracy = trace(@src()); |
| 2085 | 2361 | defer tracy.end(); |
| 2086 | 2362 | |
| ... | ... | @@ -2097,26 +2373,19 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2097 | 2373 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); |
| 2098 | 2374 | errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); |
| 2099 | 2375 | |
| 2100 | func.setAnalysisState(ip, .analyzed); | |
| 2376 | func.setAnalyzed(ip); | |
| 2101 | 2377 | if (func.analysisUnordered(ip).inferred_error_set) { |
| 2102 | 2378 | func.setResolvedErrorSet(ip, .none); |
| 2103 | 2379 | } |
| 2104 | 2380 | |
| 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); | |
| 2114 | 2386 | |
| 2115 | 2387 | const func_nav = ip.getNav(func.owner_nav); |
| 2116 | 2388 | |
| 2117 | const decl_prog_node = zcu.sema_prog_node.start(func_nav.fqn.toSlice(ip), 0); | |
| 2118 | defer decl_prog_node.end(); | |
| 2119 | ||
| 2120 | 2389 | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); |
| 2121 | 2390 | |
| 2122 | 2391 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -2150,7 +2419,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2150 | 2419 | |
| 2151 | 2420 | // Every runtime function has a dependency on the source of the Decl it originates from. |
| 2152 | 2421 | // 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 }); | |
| 2154 | 2423 | try sema.declareDependency(.{ .nav_val = func.owner_nav }); |
| 2155 | 2424 | |
| 2156 | 2425 | if (func.analysisUnordered(ip).inferred_error_set) { |
| ... | ... | @@ -2170,11 +2439,11 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError! |
| 2170 | 2439 | var inner_block: Sema.Block = .{ |
| 2171 | 2440 | .parent = null, |
| 2172 | 2441 | .sema = &sema, |
| 2173 | .namespace = decl_cau.namespace, | |
| 2442 | .namespace = decl_nav.analysis.?.namespace, | |
| 2174 | 2443 | .instructions = .{}, |
| 2175 | 2444 | .inlining = null, |
| 2176 | 2445 | .is_comptime = false, |
| 2177 | .src_base_inst = decl_cau.zir_index, | |
| 2446 | .src_base_inst = decl_nav.analysis.?.zir_index, | |
| 2178 | 2447 | .type_name_ctx = func_nav.fqn, |
| 2179 | 2448 | }; |
| 2180 | 2449 | defer inner_block.instructions.deinit(gpa); |
| ... | ... | @@ -2476,14 +2745,14 @@ fn processExportsInner( |
| 2476 | 2745 | .nav => |nav_index| if (failed: { |
| 2477 | 2746 | const nav = ip.getNav(nav_index); |
| 2478 | 2747 | 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; | |
| 2483 | 2752 | } |
| 2484 | 2753 | 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), | |
| 2487 | 2756 | }; |
| 2488 | 2757 | // If the value is a function, we also need to check if that function succeeded analysis. |
| 2489 | 2758 | if (val.typeOf(zcu).zigTypeTag(zcu) == .@"fn") { |
| ... | ... | @@ -2527,15 +2796,14 @@ pub fn populateTestFunctions( |
| 2527 | 2796 | Zcu.Namespace.NameAdapter{ .zcu = zcu }, |
| 2528 | 2797 | ).?; |
| 2529 | 2798 | { |
| 2530 | // We have to call `ensureCauAnalyzed` here in case `builtin.test_functions` | |
| 2799 | // We have to call `ensureNavValUpToDate` here in case `builtin.test_functions` | |
| 2531 | 2800 | // was not referenced by start code. |
| 2532 | 2801 | zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); |
| 2533 | 2802 | defer { |
| 2534 | 2803 | zcu.sema_prog_node.end(); |
| 2535 | 2804 | zcu.sema_prog_node = std.Progress.Node.none; |
| 2536 | 2805 | } |
| 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) { | |
| 2539 | 2807 | error.AnalysisFail => return, |
| 2540 | 2808 | error.OutOfMemory => return error.OutOfMemory, |
| 2541 | 2809 | }; |
| ... | ... | @@ -2556,8 +2824,7 @@ pub fn populateTestFunctions( |
| 2556 | 2824 | { |
| 2557 | 2825 | // The test declaration might have failed; if that's the case, just return, as we'll |
| 2558 | 2826 | // 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 }); | |
| 2561 | 2828 | if (zcu.failed_analysis.contains(anal_unit) or |
| 2562 | 2829 | zcu.transitive_failed_analysis.contains(anal_unit)) |
| 2563 | 2830 | { |
| ... | ... | @@ -2682,8 +2949,8 @@ pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error |
| 2682 | 2949 | "unable to codegen: {s}", |
| 2683 | 2950 | .{@errorName(err)}, |
| 2684 | 2951 | )); |
| 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 })); | |
| 2687 | 2954 | } else { |
| 2688 | 2955 | // TODO: we don't have a way to indicate that this failure is retryable! |
| 2689 | 2956 | // 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 |
| 3189 | 3456 | const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls); |
| 3190 | 3457 | const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse |
| 3191 | 3458 | @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); | |
| 3194 | 3461 | const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt")); |
| 3195 | 3462 | const name_str = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls); |
| 3196 | 3463 | return builtin_namespace.pub_decls.getKeyAdapted(name_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt"); |
| 3197 | 3464 | } |
| 3198 | 3465 | |
| 3199 | pub fn navPtrType(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Allocator.Error!Type { | |
| 3466 | pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type { | |
| 3200 | 3467 | const zcu = pt.zcu; |
| 3201 | 3468 | 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 | }; | |
| 3204 | 3474 | return pt.ptrType(.{ |
| 3205 | .child = ty.toIntern(), | |
| 3475 | .child = ty, | |
| 3206 | 3476 | .flags = .{ |
| 3207 | .alignment = if (r.alignment == ty.abiAlignment(zcu)) | |
| 3477 | .alignment = if (alignment == Type.fromInterned(ty).abiAlignment(zcu)) | |
| 3208 | 3478 | .none |
| 3209 | 3479 | 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, | |
| 3217 | 3483 | }, |
| 3218 | 3484 | }); |
| 3219 | 3485 | } |
| ... | ... | @@ -3233,76 +3499,57 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error! |
| 3233 | 3499 | // TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`. |
| 3234 | 3500 | pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPool.Alignment { |
| 3235 | 3501 | 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); | |
| 3239 | 3509 | } |
| 3240 | 3510 | |
| 3241 | 3511 | /// Given a container type requiring resolution, ensures that it is up-to-date. |
| 3242 | 3512 | /// If not, the type is recreated at a new `InternPool.Index`. |
| 3243 | 3513 | /// 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`. | |
| 3245 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index, already_updating: bool) Zcu.SemaError!InternPool.Index { | |
| 3514 | pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index { | |
| 3246 | 3515 | const zcu = pt.zcu; |
| 3516 | const gpa = zcu.gpa; | |
| 3247 | 3517 | 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 | ||
| 3248 | 3541 | 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), | |
| 3298 | 3545 | else => unreachable, |
| 3299 | 3546 | } |
| 3300 | 3547 | } |
| 3301 | 3548 | |
| 3302 | 3549 | fn recreateStructType( |
| 3303 | 3550 | pt: Zcu.PerThread, |
| 3551 | old_ty: InternPool.Index, | |
| 3304 | 3552 | full_key: InternPool.Key.NamespaceType, |
| 3305 | struct_obj: InternPool.LoadedStructType, | |
| 3306 | 3553 | ) Zcu.SemaError!InternPool.Index { |
| 3307 | 3554 | const zcu = pt.zcu; |
| 3308 | 3555 | const gpa = zcu.gpa; |
| ... | ... | @@ -3339,8 +3586,7 @@ fn recreateStructType( |
| 3339 | 3586 | |
| 3340 | 3587 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; |
| 3341 | 3588 | |
| 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); | |
| 3344 | 3590 | |
| 3345 | 3591 | const wip_ty = switch (try ip.getStructType(gpa, pt.tid, .{ |
| 3346 | 3592 | .layout = small.layout, |
| ... | ... | @@ -3362,17 +3608,16 @@ fn recreateStructType( |
| 3362 | 3608 | errdefer wip_ty.cancel(ip, pt.tid); |
| 3363 | 3609 | |
| 3364 | 3610 | 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); | |
| 3366 | 3611 | try ip.addDependency( |
| 3367 | 3612 | gpa, |
| 3368 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 3613 | .wrap(.{ .type = wip_ty.index }), | |
| 3369 | 3614 | .{ .src_hash = key.zir_index }, |
| 3370 | 3615 | ); |
| 3371 | 3616 | zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index; |
| 3372 | 3617 | // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive. |
| 3373 | 3618 | try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); |
| 3374 | 3619 | |
| 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); | |
| 3376 | 3621 | if (inst_info.inst == .main_struct_inst) { |
| 3377 | 3622 | // This is the root type of a file! Update the reference. |
| 3378 | 3623 | zcu.setFileRootType(inst_info.file, new_ty); |
| ... | ... | @@ -3382,8 +3627,8 @@ fn recreateStructType( |
| 3382 | 3627 | |
| 3383 | 3628 | fn recreateUnionType( |
| 3384 | 3629 | pt: Zcu.PerThread, |
| 3630 | old_ty: InternPool.Index, | |
| 3385 | 3631 | full_key: InternPool.Key.NamespaceType, |
| 3386 | union_obj: InternPool.LoadedUnionType, | |
| 3387 | 3632 | ) Zcu.SemaError!InternPool.Index { |
| 3388 | 3633 | const zcu = pt.zcu; |
| 3389 | 3634 | const gpa = zcu.gpa; |
| ... | ... | @@ -3422,8 +3667,7 @@ fn recreateUnionType( |
| 3422 | 3667 | |
| 3423 | 3668 | if (captures_len != key.captures.owned.len) return error.AnalysisFail; |
| 3424 | 3669 | |
| 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); | |
| 3427 | 3671 | |
| 3428 | 3672 | const namespace_index = union_obj.namespace; |
| 3429 | 3673 | |
| ... | ... | @@ -3460,22 +3704,21 @@ fn recreateUnionType( |
| 3460 | 3704 | errdefer wip_ty.cancel(ip, pt.tid); |
| 3461 | 3705 | |
| 3462 | 3706 | 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); | |
| 3464 | 3707 | try ip.addDependency( |
| 3465 | 3708 | gpa, |
| 3466 | AnalUnit.wrap(.{ .cau = new_cau_index }), | |
| 3709 | .wrap(.{ .type = wip_ty.index }), | |
| 3467 | 3710 | .{ .src_hash = key.zir_index }, |
| 3468 | 3711 | ); |
| 3469 | 3712 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; |
| 3470 | 3713 | // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive. |
| 3471 | 3714 | 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); | |
| 3473 | 3716 | } |
| 3474 | 3717 | |
| 3475 | 3718 | fn recreateEnumType( |
| 3476 | 3719 | pt: Zcu.PerThread, |
| 3720 | old_ty: InternPool.Index, | |
| 3477 | 3721 | full_key: InternPool.Key.NamespaceType, |
| 3478 | enum_obj: InternPool.LoadedEnumType, | |
| 3479 | 3722 | ) Zcu.SemaError!InternPool.Index { |
| 3480 | 3723 | const zcu = pt.zcu; |
| 3481 | 3724 | const gpa = zcu.gpa; |
| ... | ... | @@ -3544,8 +3787,7 @@ fn recreateEnumType( |
| 3544 | 3787 | if (bag != 0) break true; |
| 3545 | 3788 | } else false; |
| 3546 | 3789 | |
| 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); | |
| 3549 | 3791 | |
| 3550 | 3792 | const namespace_index = enum_obj.namespace; |
| 3551 | 3793 | |
| ... | ... | @@ -3571,12 +3813,10 @@ fn recreateEnumType( |
| 3571 | 3813 | |
| 3572 | 3814 | wip_ty.setName(ip, enum_obj.name); |
| 3573 | 3815 | |
| 3574 | const new_cau_index = try ip.createTypeCau(gpa, pt.tid, key.zir_index, namespace_index, wip_ty.index); | |
| 3575 | ||
| 3576 | 3816 | zcu.namespacePtr(namespace_index).owner_type = wip_ty.index; |
| 3577 | 3817 | // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive. |
| 3578 | 3818 | |
| 3579 | wip_ty.prepare(ip, new_cau_index, namespace_index); | |
| 3819 | wip_ty.prepare(ip, namespace_index); | |
| 3580 | 3820 | done = true; |
| 3581 | 3821 | |
| 3582 | 3822 | Sema.resolveDeclaredEnum( |
| ... | ... | @@ -3586,7 +3826,6 @@ fn recreateEnumType( |
| 3586 | 3826 | key.zir_index, |
| 3587 | 3827 | namespace_index, |
| 3588 | 3828 | enum_obj.name, |
| 3589 | new_cau_index, | |
| 3590 | 3829 | small, |
| 3591 | 3830 | body, |
| 3592 | 3831 | 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 |
| 3218 | 3218 | const zcu = pt.zcu; |
| 3219 | 3219 | const ip = &zcu.intern_pool; |
| 3220 | 3220 | |
| 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); | |
| 3230 | 3222 | if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) { |
| 3231 | 3223 | return .{ .imm32 = 0xaaaaaaaa }; |
| 3232 | 3224 | } |
src/codegen.zig+9-8| ... | ... | @@ -817,7 +817,7 @@ fn genNavRef( |
| 817 | 817 | pt: Zcu.PerThread, |
| 818 | 818 | src_loc: Zcu.LazySrcLoc, |
| 819 | 819 | val: Value, |
| 820 | ref_nav_index: InternPool.Nav.Index, | |
| 820 | nav_index: InternPool.Nav.Index, | |
| 821 | 821 | target: std.Target, |
| 822 | 822 | ) CodeGenError!GenResult { |
| 823 | 823 | const zcu = pt.zcu; |
| ... | ... | @@ -851,14 +851,15 @@ fn genNavRef( |
| 851 | 851 | } |
| 852 | 852 | } |
| 853 | 853 | |
| 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 | ||
| 860 | 861 | const single_threaded = zcu.navFileScope(nav_index).mod.single_threaded; |
| 861 | const name = ip.getNav(nav_index).name; | |
| 862 | const name = nav.name; | |
| 862 | 863 | if (lf.cast(.elf)) |elf_file| { |
| 863 | 864 | const zo = elf_file.zigObjectPtr().?; |
| 864 | 865 | if (is_extern) { |
src/codegen/c.zig+32-29| ... | ... | @@ -770,11 +770,14 @@ pub const DeclGen = struct { |
| 770 | 770 | const ctype_pool = &dg.ctype_pool; |
| 771 | 771 | |
| 772 | 772 | // 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 | }, | |
| 778 | 781 | }; |
| 779 | 782 | |
| 780 | 783 | // Render an undefined pointer if we have a pointer to a zero-bit or comptime type. |
| ... | ... | @@ -2237,7 +2240,7 @@ pub const DeclGen = struct { |
| 2237 | 2240 | Type.fromInterned(nav.typeOf(ip)), |
| 2238 | 2241 | .{ .nav = nav_index }, |
| 2239 | 2242 | CQualifiers.init(.{ .@"const" = flags.is_const }), |
| 2240 | nav.status.resolved.alignment, | |
| 2243 | nav.getAlignment(), | |
| 2241 | 2244 | .complete, |
| 2242 | 2245 | ); |
| 2243 | 2246 | try fwd.writeAll(";\n"); |
| ... | ... | @@ -2246,19 +2249,19 @@ pub const DeclGen = struct { |
| 2246 | 2249 | fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void { |
| 2247 | 2250 | const zcu = dg.pt.zcu; |
| 2248 | 2251 | 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("{ }", .{ | |
| 2251 | 2255 | 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 | }); | |
| 2262 | 2265 | } |
| 2263 | 2266 | } |
| 2264 | 2267 | |
| ... | ... | @@ -2826,7 +2829,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn |
| 2826 | 2829 | |
| 2827 | 2830 | const fwd = o.dg.fwdDeclWriter(); |
| 2828 | 2831 | 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, .{ | |
| 2830 | 2833 | .fmt_ctype_pool_string = fn_name, |
| 2831 | 2834 | }); |
| 2832 | 2835 | try fwd.writeAll(";\n"); |
| ... | ... | @@ -2867,13 +2870,13 @@ pub fn genFunc(f: *Function) !void { |
| 2867 | 2870 | try o.dg.renderFunctionSignature( |
| 2868 | 2871 | fwd, |
| 2869 | 2872 | nav_val, |
| 2870 | nav.status.resolved.alignment, | |
| 2873 | nav.status.fully_resolved.alignment, | |
| 2871 | 2874 | .forward, |
| 2872 | 2875 | .{ .nav = nav_index }, |
| 2873 | 2876 | ); |
| 2874 | 2877 | try fwd.writeAll(";\n"); |
| 2875 | 2878 | |
| 2876 | if (nav.status.resolved.@"linksection".toSlice(ip)) |s| | |
| 2879 | if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s| | |
| 2877 | 2880 | try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)}); |
| 2878 | 2881 | try o.dg.renderFunctionSignature( |
| 2879 | 2882 | o.writer(), |
| ... | ... | @@ -2952,7 +2955,7 @@ pub fn genDecl(o: *Object) !void { |
| 2952 | 2955 | const nav_ty = Type.fromInterned(nav.typeOf(ip)); |
| 2953 | 2956 | |
| 2954 | 2957 | if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return; |
| 2955 | switch (ip.indexToKey(nav.status.resolved.val)) { | |
| 2958 | switch (ip.indexToKey(nav.status.fully_resolved.val)) { | |
| 2956 | 2959 | .@"extern" => |@"extern"| { |
| 2957 | 2960 | if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{ |
| 2958 | 2961 | .is_extern = true, |
| ... | ... | @@ -2965,8 +2968,8 @@ pub fn genDecl(o: *Object) !void { |
| 2965 | 2968 | try fwd.writeAll("zig_extern "); |
| 2966 | 2969 | try o.dg.renderFunctionSignature( |
| 2967 | 2970 | 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, | |
| 2970 | 2973 | .forward, |
| 2971 | 2974 | .{ .@"export" = .{ |
| 2972 | 2975 | .main_name = nav.name, |
| ... | ... | @@ -2985,14 +2988,14 @@ pub fn genDecl(o: *Object) !void { |
| 2985 | 2988 | const w = o.writer(); |
| 2986 | 2989 | if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); |
| 2987 | 2990 | 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| | |
| 2989 | 2992 | try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)}); |
| 2990 | 2993 | try o.dg.renderTypeAndName( |
| 2991 | 2994 | w, |
| 2992 | 2995 | nav_ty, |
| 2993 | 2996 | .{ .nav = o.dg.pass.nav }, |
| 2994 | 2997 | .{}, |
| 2995 | nav.status.resolved.alignment, | |
| 2998 | nav.status.fully_resolved.alignment, | |
| 2996 | 2999 | .complete, |
| 2997 | 3000 | ); |
| 2998 | 3001 | try w.writeAll(" = "); |
| ... | ... | @@ -3002,10 +3005,10 @@ pub fn genDecl(o: *Object) !void { |
| 3002 | 3005 | }, |
| 3003 | 3006 | else => try genDeclValue( |
| 3004 | 3007 | o, |
| 3005 | Value.fromInterned(nav.status.resolved.val), | |
| 3008 | Value.fromInterned(nav.status.fully_resolved.val), | |
| 3006 | 3009 | .{ .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", | |
| 3009 | 3012 | ), |
| 3010 | 3013 | } |
| 3011 | 3014 | } |
src/codegen/llvm.zig+29-38| ... | ... | @@ -1476,7 +1476,7 @@ pub const Object = struct { |
| 1476 | 1476 | } }, &o.builder); |
| 1477 | 1477 | } |
| 1478 | 1478 | |
| 1479 | if (nav.status.resolved.@"linksection".toSlice(ip)) |section| | |
| 1479 | if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |section| | |
| 1480 | 1480 | function_index.setSection(try o.builder.string(section), &o.builder); |
| 1481 | 1481 | |
| 1482 | 1482 | var deinit_wip = true; |
| ... | ... | @@ -1684,7 +1684,7 @@ pub const Object = struct { |
| 1684 | 1684 | const file = try o.getDebugFile(file_scope); |
| 1685 | 1685 | |
| 1686 | 1686 | 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"; | |
| 1688 | 1688 | const debug_decl_type = try o.lowerDebugType(fn_ty); |
| 1689 | 1689 | |
| 1690 | 1690 | const subprogram = try o.builder.debugSubprogram( |
| ... | ... | @@ -2928,9 +2928,7 @@ pub const Object = struct { |
| 2928 | 2928 | const gpa = o.gpa; |
| 2929 | 2929 | const nav = ip.getNav(nav_index); |
| 2930 | 2930 | 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)); | |
| 2934 | 2932 | const gop = try o.nav_map.getOrPut(gpa, nav_index); |
| 2935 | 2933 | if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function; |
| 2936 | 2934 | |
| ... | ... | @@ -2938,15 +2936,14 @@ pub const Object = struct { |
| 2938 | 2936 | const target = owner_mod.resolved_target.result; |
| 2939 | 2937 | const sret = firstParamSRet(fn_info, zcu, target); |
| 2940 | 2938 | |
| 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 }; | |
| 2946 | 2943 | const function_index = try o.builder.addFunction( |
| 2947 | 2944 | try o.lowerType(ty), |
| 2948 | 2945 | try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)), |
| 2949 | toLlvmAddressSpace(resolved.@"addrspace", target), | |
| 2946 | toLlvmAddressSpace(nav.getAddrspace(), target), | |
| 2950 | 2947 | ); |
| 2951 | 2948 | gop.value_ptr.* = function_index.ptrConst(&o.builder).global; |
| 2952 | 2949 | |
| ... | ... | @@ -3064,8 +3061,8 @@ pub const Object = struct { |
| 3064 | 3061 | } |
| 3065 | 3062 | } |
| 3066 | 3063 | |
| 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); | |
| 3069 | 3066 | |
| 3070 | 3067 | // Function attributes that are independent of analysis results of the function body. |
| 3071 | 3068 | try o.addCommonFnAttributes( |
| ... | ... | @@ -3250,17 +3247,21 @@ pub const Object = struct { |
| 3250 | 3247 | const zcu = pt.zcu; |
| 3251 | 3248 | const ip = &zcu.intern_pool; |
| 3252 | 3249 | 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 }, | |
| 3258 | 3259 | }; |
| 3259 | 3260 | |
| 3260 | 3261 | const variable_index = try o.builder.addVariable( |
| 3261 | 3262 | try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)), |
| 3262 | 3263 | try o.lowerType(Type.fromInterned(nav.typeOf(ip))), |
| 3263 | toLlvmGlobalAddressSpace(resolved.@"addrspace", zcu.getTarget()), | |
| 3264 | toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()), | |
| 3264 | 3265 | ); |
| 3265 | 3266 | gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; |
| 3266 | 3267 | |
| ... | ... | @@ -4529,20 +4530,10 @@ pub const Object = struct { |
| 4529 | 4530 | const zcu = pt.zcu; |
| 4530 | 4531 | const ip = &zcu.intern_pool; |
| 4531 | 4532 | |
| 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); | |
| 4543 | 4534 | |
| 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); | |
| 4546 | 4537 | |
| 4547 | 4538 | const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn"; |
| 4548 | 4539 | if ((!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) or |
| ... | ... | @@ -4552,13 +4543,13 @@ pub const Object = struct { |
| 4552 | 4543 | } |
| 4553 | 4544 | |
| 4554 | 4545 | 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 | |
| 4556 | 4547 | else |
| 4557 | (try o.resolveGlobalNav(owner_nav_index)).ptrConst(&o.builder).global; | |
| 4548 | (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global; | |
| 4558 | 4549 | |
| 4559 | 4550 | const llvm_val = try o.builder.convConst( |
| 4560 | 4551 | 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())), | |
| 4562 | 4553 | ); |
| 4563 | 4554 | |
| 4564 | 4555 | return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty)); |
| ... | ... | @@ -4800,10 +4791,10 @@ pub const NavGen = struct { |
| 4800 | 4791 | const ip = &zcu.intern_pool; |
| 4801 | 4792 | const nav_index = ng.nav_index; |
| 4802 | 4793 | const nav = ip.getNav(nav_index); |
| 4803 | const resolved = nav.status.resolved; | |
| 4794 | const resolved = nav.status.fully_resolved; | |
| 4804 | 4795 | |
| 4805 | 4796 | 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 }, | |
| 4807 | 4798 | .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav }, |
| 4808 | 4799 | else => .{ false, .none, false, false, false, true, resolved.val, nav_index }, |
| 4809 | 4800 | }; |
| ... | ... | @@ -5766,7 +5757,7 @@ pub const FuncGen = struct { |
| 5766 | 5757 | const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?; |
| 5767 | 5758 | const msg_nav = ip.getNav(msg_nav_index); |
| 5768 | 5759 | 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); | |
| 5770 | 5761 | const null_opt_addr_global = try fg.resolveNullOptUsize(); |
| 5771 | 5762 | const target = zcu.getTarget(); |
| 5772 | 5763 | const llvm_usize = try o.lowerType(Type.usize); |
src/codegen/spirv.zig+16-13| ... | ... | @@ -268,7 +268,7 @@ pub const Object = struct { |
| 268 | 268 | // TODO: Extern fn? |
| 269 | 269 | const kind: SpvModule.Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip))) |
| 270 | 270 | .func |
| 271 | else switch (nav.status.resolved.@"addrspace") { | |
| 271 | else switch (nav.getAddrspace()) { | |
| 272 | 272 | .generic => .invocation_global, |
| 273 | 273 | else => .global, |
| 274 | 274 | }; |
| ... | ... | @@ -1279,17 +1279,20 @@ const NavGen = struct { |
| 1279 | 1279 | const ip = &zcu.intern_pool; |
| 1280 | 1280 | const ty_id = try self.resolveType(ty, .direct); |
| 1281 | 1281 | 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 => {}, | |
| 1290 | 1295 | }, |
| 1291 | .@"extern" => assert(!ip.isFunctionType(nav_ty.toIntern())), // TODO | |
| 1292 | else => {}, | |
| 1293 | 1296 | } |
| 1294 | 1297 | |
| 1295 | 1298 | if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) { |
| ... | ... | @@ -1305,7 +1308,7 @@ const NavGen = struct { |
| 1305 | 1308 | .global, .invocation_global => spv_decl.result_id, |
| 1306 | 1309 | }; |
| 1307 | 1310 | |
| 1308 | const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace"); | |
| 1311 | const storage_class = self.spvStorageClass(nav.getAddrspace()); | |
| 1309 | 1312 | try self.addFunctionDep(spv_decl_index, storage_class); |
| 1310 | 1313 | |
| 1311 | 1314 | const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class); |
| ... | ... | @@ -3182,7 +3185,7 @@ const NavGen = struct { |
| 3182 | 3185 | }; |
| 3183 | 3186 | assert(maybe_init_val == null); // TODO |
| 3184 | 3187 | |
| 3185 | const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace"); | |
| 3188 | const storage_class = self.spvStorageClass(nav.getAddrspace()); | |
| 3186 | 3189 | assert(storage_class != .Generic); // These should be instance globals |
| 3187 | 3190 | |
| 3188 | 3191 | const ptr_ty_id = try self.ptrType(ty, storage_class); |
src/link.zig+1-1| ... | ... | @@ -692,7 +692,7 @@ pub const File = struct { |
| 692 | 692 | /// May be called before or after updateExports for any given Nav. |
| 693 | 693 | pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void { |
| 694 | 694 | const nav = pt.zcu.intern_pool.getNav(nav_index); |
| 695 | assert(nav.status == .resolved); | |
| 695 | assert(nav.status == .fully_resolved); | |
| 696 | 696 | switch (base.tag) { |
| 697 | 697 | inline else => |tag| { |
| 698 | 698 | dev.check(tag.devFeature()); |
src/link/C.zig+9-11| ... | ... | @@ -217,7 +217,7 @@ pub fn updateFunc( |
| 217 | 217 | .mod = zcu.navFileScope(func.owner_nav).mod, |
| 218 | 218 | .error_msg = null, |
| 219 | 219 | .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, | |
| 221 | 221 | .fwd_decl = fwd_decl.toManaged(gpa), |
| 222 | 222 | .ctype_pool = ctype_pool.*, |
| 223 | 223 | .scratch = .{}, |
| ... | ... | @@ -320,11 +320,11 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) ! |
| 320 | 320 | const ip = &zcu.intern_pool; |
| 321 | 321 | |
| 322 | 322 | 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)) { | |
| 324 | 324 | .func => return, |
| 325 | 325 | .@"extern" => .none, |
| 326 | 326 | .variable => |variable| variable.init, |
| 327 | else => nav.status.resolved.val, | |
| 327 | else => nav.status.fully_resolved.val, | |
| 328 | 328 | }; |
| 329 | 329 | if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) return; |
| 330 | 330 | |
| ... | ... | @@ -499,7 +499,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: |
| 499 | 499 | av_block, |
| 500 | 500 | self.exported_navs.getPtr(nav), |
| 501 | 501 | export_names, |
| 502 | if (ip.indexToKey(zcu.navValue(nav).toIntern()) == .@"extern") | |
| 502 | if (ip.getNav(nav).getExtern(ip) != null) | |
| 503 | 503 | ip.getNav(nav).name.toOptional() |
| 504 | 504 | else |
| 505 | 505 | .none, |
| ... | ... | @@ -544,13 +544,11 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: |
| 544 | 544 | }, |
| 545 | 545 | self.getString(av_block.code), |
| 546 | 546 | ); |
| 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)); | |
| 554 | 552 | |
| 555 | 553 | const file = self.base.file.?; |
| 556 | 554 | 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, |
| 1110 | 1110 | const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav); |
| 1111 | 1111 | coff.freeRelocations(atom_index); |
| 1112 | 1112 | |
| 1113 | coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?; | |
| 1114 | ||
| 1113 | 1115 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1114 | 1116 | defer code_buffer.deinit(); |
| 1115 | 1117 | |
| ... | ... | @@ -1223,6 +1225,8 @@ pub fn updateNav( |
| 1223 | 1225 | coff.freeRelocations(atom_index); |
| 1224 | 1226 | const atom = coff.getAtom(atom_index); |
| 1225 | 1227 | |
| 1228 | coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index); | |
| 1229 | ||
| 1226 | 1230 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1227 | 1231 | defer code_buffer.deinit(); |
| 1228 | 1232 | |
| ... | ... | @@ -1342,7 +1346,8 @@ pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom |
| 1342 | 1346 | if (!gop.found_existing) { |
| 1343 | 1347 | gop.value_ptr.* = .{ |
| 1344 | 1348 | .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.?, | |
| 1346 | 1351 | .exports = .{}, |
| 1347 | 1352 | }; |
| 1348 | 1353 | } |
| ... | ... | @@ -1355,7 +1360,7 @@ fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 { |
| 1355 | 1360 | const nav = ip.getNav(nav_index); |
| 1356 | 1361 | const ty = Type.fromInterned(nav.typeOf(ip)); |
| 1357 | 1362 | 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); | |
| 1359 | 1364 | const index: u16 = blk: { |
| 1360 | 1365 | if (val.isUndefDeep(zcu)) { |
| 1361 | 1366 | // TODO in release-fast and release-small, we should put undef in .bss |
| ... | ... | @@ -2348,10 +2353,10 @@ pub fn getNavVAddr( |
| 2348 | 2353 | const ip = &zcu.intern_pool; |
| 2349 | 2354 | const nav = ip.getNav(nav_index); |
| 2350 | 2355 | 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().?; | |
| 2355 | 2360 | const atom_index = coff.getAtomIndexForSymbol(.{ |
| 2356 | 2361 | .sym_index = reloc_info.parent.atom_index, |
| 2357 | 2362 | .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 |
| 2259 | 2259 | switch (ip.indexToKey(nav_val.toIntern())) { |
| 2260 | 2260 | else => { |
| 2261 | 2261 | assert(file.zir_loaded); |
| 2262 | const decl = file.zir.getDeclaration(inst_info.inst)[0]; | |
| 2262 | const decl = file.zir.getDeclaration(inst_info.inst); | |
| 2263 | 2263 | |
| 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); | |
| 2266 | 2266 | break :parent .{ |
| 2267 | 2267 | 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, | |
| 2280 | 2269 | }; |
| 2281 | 2270 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2282 | 2271 | |
| ... | ... | @@ -2292,7 +2281,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In |
| 2292 | 2281 | const nav_ty = nav_val.typeOf(zcu); |
| 2293 | 2282 | const nav_ty_reloc_index = try wip_nav.refForward(); |
| 2294 | 2283 | 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 | |
| 2296 | 2285 | nav_ty.abiAlignment(zcu).toByteUnits().?); |
| 2297 | 2286 | try diw.writeByte(@intFromBool(false)); |
| 2298 | 2287 | wip_nav.finishForward(nav_ty_reloc_index); |
| ... | ... | @@ -2301,24 +2290,13 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In |
| 2301 | 2290 | }, |
| 2302 | 2291 | .variable => |variable| { |
| 2303 | 2292 | assert(file.zir_loaded); |
| 2304 | const decl = file.zir.getDeclaration(inst_info.inst)[0]; | |
| 2293 | const decl = file.zir.getDeclaration(inst_info.inst); | |
| 2305 | 2294 | |
| 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); | |
| 2308 | 2297 | break :parent .{ |
| 2309 | 2298 | 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, | |
| 2322 | 2300 | }; |
| 2323 | 2301 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2324 | 2302 | |
| ... | ... | @@ -2335,30 +2313,19 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In |
| 2335 | 2313 | try wip_nav.refType(ty); |
| 2336 | 2314 | const addr: Loc = .{ .addr = .{ .sym = sym_index } }; |
| 2337 | 2315 | 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 | |
| 2339 | 2317 | ty.abiAlignment(zcu).toByteUnits().?); |
| 2340 | 2318 | try diw.writeByte(@intFromBool(false)); |
| 2341 | 2319 | }, |
| 2342 | 2320 | .func => |func| { |
| 2343 | 2321 | assert(file.zir_loaded); |
| 2344 | const decl = file.zir.getDeclaration(inst_info.inst)[0]; | |
| 2322 | const decl = file.zir.getDeclaration(inst_info.inst); | |
| 2345 | 2323 | |
| 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); | |
| 2348 | 2326 | break :parent .{ |
| 2349 | 2327 | 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, | |
| 2362 | 2329 | }; |
| 2363 | 2330 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2364 | 2331 | |
| ... | ... | @@ -2421,7 +2388,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In |
| 2421 | 2388 | wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len); |
| 2422 | 2389 | try diw.writeInt(u32, 0, dwarf.endian); |
| 2423 | 2390 | 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) { | |
| 2425 | 2392 | .none => target_info.defaultFunctionAlignment(target), |
| 2426 | 2393 | else => |a| a.maxStrict(target_info.minFunctionAlignment(target)), |
| 2427 | 2394 | }.toByteUnits().?); |
| ... | ... | @@ -2585,23 +2552,22 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 2585 | 2552 | const inst_info = nav.srcInst(ip).resolveFull(ip).?; |
| 2586 | 2553 | const file = zcu.fileByIndex(inst_info.file); |
| 2587 | 2554 | assert(file.zir_loaded); |
| 2588 | const decl = file.zir.getDeclaration(inst_info.inst)[0]; | |
| 2555 | const decl = file.zir.getDeclaration(inst_info.inst); | |
| 2589 | 2556 | |
| 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, | |
| 2594 | 2560 | }; |
| 2595 | 2561 | if (is_test) { |
| 2596 | 2562 | // This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime. |
| 2597 | 2563 | return; |
| 2598 | 2564 | } |
| 2599 | 2565 | |
| 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); | |
| 2602 | 2568 | break :parent .{ |
| 2603 | 2569 | 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, | |
| 2605 | 2571 | }; |
| 2606 | 2572 | } else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private }; |
| 2607 | 2573 | |
| ... | ... | @@ -2986,7 +2952,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 2986 | 2952 | const nav_ty = nav_val.typeOf(zcu); |
| 2987 | 2953 | try wip_nav.refType(nav_ty); |
| 2988 | 2954 | 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 | |
| 2990 | 2956 | nav_ty.abiAlignment(zcu).toByteUnits().?); |
| 2991 | 2957 | try diw.writeByte(@intFromBool(false)); |
| 2992 | 2958 | }, |
| ... | ... | @@ -3011,7 +2977,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 3011 | 2977 | try wip_nav.strp(nav.name.toSlice(ip)); |
| 3012 | 2978 | try wip_nav.strp(nav.fqn.toSlice(ip)); |
| 3013 | 2979 | 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 | |
| 3015 | 2981 | nav_ty.abiAlignment(zcu).toByteUnits().?); |
| 3016 | 2982 | try diw.writeByte(@intFromBool(false)); |
| 3017 | 2983 | 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 |
| 4198 | 4164 | assert(inst_info.inst != .main_struct_inst); |
| 4199 | 4165 | const file = zcu.fileByIndex(inst_info.file); |
| 4200 | 4166 | |
| 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; | |
| 4204 | 4168 | var line_buf: [4]u8 = undefined; |
| 4205 | 4169 | std.mem.writeInt(u32, &line_buf, line, dwarf.endian); |
| 4206 | 4170 |
src/link/Elf/ZigObject.zig+10-15| ... | ... | @@ -925,14 +925,11 @@ pub fn getNavVAddr( |
| 925 | 925 | const ip = &zcu.intern_pool; |
| 926 | 926 | const nav = ip.getNav(nav_index); |
| 927 | 927 | 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); | |
| 936 | 933 | const this_sym = self.symbol(this_sym_index); |
| 937 | 934 | const vaddr = this_sym.address(.{}, elf_file); |
| 938 | 935 | switch (reloc_info.parent) { |
| ... | ... | @@ -1107,15 +1104,13 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index |
| 1107 | 1104 | |
| 1108 | 1105 | pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index { |
| 1109 | 1106 | const gpa = zcu.gpa; |
| 1107 | const ip = &zcu.intern_pool; | |
| 1110 | 1108 | const gop = try self.navs.getOrPut(gpa, nav_index); |
| 1111 | 1109 | if (!gop.found_existing) { |
| 1112 | 1110 | const symbol_index = try self.newSymbolWithAtom(gpa, 0); |
| 1113 | const nav_val = Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val); | |
| 1114 | 1111 | 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; | |
| 1119 | 1114 | } |
| 1120 | 1115 | gop.value_ptr.* = .{ .symbol_index = symbol_index }; |
| 1121 | 1116 | } |
| ... | ... | @@ -1547,7 +1542,7 @@ pub fn updateNav( |
| 1547 | 1542 | |
| 1548 | 1543 | log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index }); |
| 1549 | 1544 | |
| 1550 | const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { | |
| 1545 | const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) { | |
| 1551 | 1546 | .func => .none, |
| 1552 | 1547 | .variable => |variable| variable.init, |
| 1553 | 1548 | .@"extern" => |@"extern"| { |
| ... | ... | @@ -1560,7 +1555,7 @@ pub fn updateNav( |
| 1560 | 1555 | self.symbol(sym_index).flags.is_extern_ptr = true; |
| 1561 | 1556 | return; |
| 1562 | 1557 | }, |
| 1563 | else => nav.status.resolved.val, | |
| 1558 | else => nav.status.fully_resolved.val, | |
| 1564 | 1559 | }; |
| 1565 | 1560 | |
| 1566 | 1561 | 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( |
| 608 | 608 | const ip = &zcu.intern_pool; |
| 609 | 609 | const nav = ip.getNav(nav_index); |
| 610 | 610 | 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); | |
| 619 | 616 | const sym = self.symbols.items[sym_index]; |
| 620 | 617 | const vaddr = sym.getAddress(.{}, macho_file); |
| 621 | 618 | switch (reloc_info.parent) { |
| ... | ... | @@ -882,7 +879,7 @@ pub fn updateNav( |
| 882 | 879 | const ip = &zcu.intern_pool; |
| 883 | 880 | const nav = ip.getNav(nav_index); |
| 884 | 881 | |
| 885 | const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) { | |
| 882 | const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) { | |
| 886 | 883 | .func => .none, |
| 887 | 884 | .variable => |variable| variable.init, |
| 888 | 885 | .@"extern" => |@"extern"| { |
| ... | ... | @@ -895,7 +892,7 @@ pub fn updateNav( |
| 895 | 892 | sym.flags.is_extern_ptr = true; |
| 896 | 893 | return; |
| 897 | 894 | }, |
| 898 | else => nav.status.resolved.val, | |
| 895 | else => nav.status.fully_resolved.val, | |
| 899 | 896 | }; |
| 900 | 897 | |
| 901 | 898 | 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 { |
| 1561 | 1558 | if (!macho_file.base.comp.config.any_non_single_threaded) |
| 1562 | 1559 | return false; |
| 1563 | 1560 | 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); | |
| 1569 | 1562 | } |
| 1570 | 1563 | |
| 1571 | 1564 | fn 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) |
| 1021 | 1021 | const atom_idx = gop.value_ptr.index; |
| 1022 | 1022 | // handle externs here because they might not get updateDecl called on them |
| 1023 | 1023 | const nav = ip.getNav(nav_index); |
| 1024 | if (ip.indexToKey(nav.status.resolved.val) == .@"extern") { | |
| 1024 | if (nav.getExtern(ip) != null) { | |
| 1025 | 1025 | // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs |
| 1026 | 1026 | if (nav.name.eqlSlice("etext", ip)) { |
| 1027 | 1027 | self.etext_edata_end_atom_indices[0] = atom_idx; |
| ... | ... | @@ -1370,7 +1370,7 @@ pub fn getNavVAddr( |
| 1370 | 1370 | const ip = &pt.zcu.intern_pool; |
| 1371 | 1371 | const nav = ip.getNav(nav_index); |
| 1372 | 1372 | log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)}); |
| 1373 | if (ip.indexToKey(nav.status.resolved.val) == .@"extern") { | |
| 1373 | if (nav.getExtern(ip) != null) { | |
| 1374 | 1374 | if (nav.name.eqlSlice("etext", ip)) { |
| 1375 | 1375 | try self.addReloc(reloc_info.parent.atom_index, .{ |
| 1376 | 1376 | .target = undefined, |
src/link/Wasm/ZigObject.zig+7-8| ... | ... | @@ -241,7 +241,7 @@ pub fn updateNav( |
| 241 | 241 | |
| 242 | 242 | const nav_val = zcu.navValue(nav_index); |
| 243 | 243 | 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) }, | |
| 245 | 245 | .func => return, |
| 246 | 246 | .@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip))) |
| 247 | 247 | return |
| ... | ... | @@ -734,15 +734,14 @@ pub fn getNavVAddr( |
| 734 | 734 | const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index); |
| 735 | 735 | const target_atom = wasm.getAtom(target_atom_index); |
| 736 | 736 | 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( | |
| 739 | 739 | wasm, |
| 740 | 740 | nav.name.toSlice(ip), |
| 741 | 741 | target_atom.sym_index, |
| 742 | 742 | @"extern".lib_name.toSlice(ip), |
| 743 | 743 | null, |
| 744 | ), | |
| 745 | else => {}, | |
| 744 | ); | |
| 746 | 745 | } |
| 747 | 746 | |
| 748 | 747 | 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 |
| 945 | 944 | segment.name = &.{}; // Ensure no accidental double free |
| 946 | 945 | } |
| 947 | 946 | |
| 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) { | |
| 950 | 949 | std.debug.assert(zig_object.imports.remove(atom.sym_index)); |
| 951 | 950 | } |
| 952 | 951 | 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 |
| 960 | 959 | if (sym.isGlobal()) { |
| 961 | 960 | std.debug.assert(zig_object.global_syms.remove(atom.sym_index)); |
| 962 | 961 | } |
| 963 | if (ip.isFunctionType(ip.typeOf(nav_val))) { | |
| 962 | if (ip.isFunctionType(nav.typeOf(ip))) { | |
| 964 | 963 | zig_object.functions_free_list.append(gpa, sym.index) catch {}; |
| 965 | 964 | std.debug.assert(zig_object.atom_types.remove(atom_index)); |
| 966 | 965 | } else { |
src/print_zir.zig+29-69| ... | ... | @@ -542,7 +542,6 @@ const Writer = struct { |
| 542 | 542 | |
| 543 | 543 | .@"asm" => try self.writeAsm(stream, extended, false), |
| 544 | 544 | .asm_expr => try self.writeAsm(stream, extended, true), |
| 545 | .variable => try self.writeVarExtended(stream, extended), | |
| 546 | 545 | .alloc => try self.writeAllocExtended(stream, extended), |
| 547 | 546 | |
| 548 | 547 | .compile_log => try self.writeNodeMultiOp(stream, extended), |
| ... | ... | @@ -2347,7 +2346,6 @@ const Writer = struct { |
| 2347 | 2346 | inferred_error_set, |
| 2348 | 2347 | false, |
| 2349 | 2348 | false, |
| 2350 | false, | |
| 2351 | 2349 | |
| 2352 | 2350 | .none, |
| 2353 | 2351 | &.{}, |
| ... | ... | @@ -2371,13 +2369,6 @@ const Writer = struct { |
| 2371 | 2369 | var ret_ty_ref: Zir.Inst.Ref = .none; |
| 2372 | 2370 | var ret_ty_body: []const Zir.Inst.Index = &.{}; |
| 2373 | 2371 | |
| 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 | ||
| 2381 | 2372 | if (extra.data.bits.has_cc_body) { |
| 2382 | 2373 | const body_len = self.code.extra[extra_index]; |
| 2383 | 2374 | extra_index += 1; |
| ... | ... | @@ -2414,7 +2405,6 @@ const Writer = struct { |
| 2414 | 2405 | stream, |
| 2415 | 2406 | extra.data.bits.is_inferred_error, |
| 2416 | 2407 | extra.data.bits.is_var_args, |
| 2417 | extra.data.bits.is_extern, | |
| 2418 | 2408 | extra.data.bits.is_noinline, |
| 2419 | 2409 | cc_ref, |
| 2420 | 2410 | cc_body, |
| ... | ... | @@ -2427,36 +2417,6 @@ const Writer = struct { |
| 2427 | 2417 | ); |
| 2428 | 2418 | } |
| 2429 | 2419 | |
| 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 | ||
| 2460 | 2420 | fn writeAllocExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { |
| 2461 | 2421 | const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand); |
| 2462 | 2422 | const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small)); |
| ... | ... | @@ -2604,7 +2564,6 @@ const Writer = struct { |
| 2604 | 2564 | stream: anytype, |
| 2605 | 2565 | inferred_error_set: bool, |
| 2606 | 2566 | var_args: bool, |
| 2607 | is_extern: bool, | |
| 2608 | 2567 | is_noinline: bool, |
| 2609 | 2568 | cc_ref: Zir.Inst.Ref, |
| 2610 | 2569 | cc_body: []const Zir.Inst.Index, |
| ... | ... | @@ -2618,7 +2577,6 @@ const Writer = struct { |
| 2618 | 2577 | try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body); |
| 2619 | 2578 | try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body); |
| 2620 | 2579 | try self.writeFlag(stream, "vargs, ", var_args); |
| 2621 | try self.writeFlag(stream, "extern, ", is_extern); | |
| 2622 | 2580 | try self.writeFlag(stream, "inferror, ", inferred_error_set); |
| 2623 | 2581 | try self.writeFlag(stream, "noinline, ", is_noinline); |
| 2624 | 2582 | |
| ... | ... | @@ -2664,56 +2622,58 @@ const Writer = struct { |
| 2664 | 2622 | } |
| 2665 | 2623 | |
| 2666 | 2624 | 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); | |
| 2669 | 2626 | |
| 2670 | 2627 | const prev_parent_decl_node = self.parent_decl_node; |
| 2671 | 2628 | 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; | |
| 2673 | 2630 | |
| 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) { | |
| 2677 | 2638 | .@"comptime" => try stream.writeAll("comptime"), |
| 2678 | 2639 | .@"usingnamespace" => try stream.writeAll("usingnamespace"), |
| 2679 | 2640 | .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) }); | |
| 2686 | 2643 | }, |
| 2687 | 2644 | } |
| 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 | }); | |
| 2696 | 2651 | |
| 2697 | 2652 | { |
| 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 | } | |
| 2702 | 2657 | |
| 2703 | if (bodies.align_body) |b| { | |
| 2658 | if (decl.align_body) |b| { | |
| 2704 | 2659 | try stream.writeAll(" align="); |
| 2705 | 2660 | try self.writeBracedDecl(stream, b); |
| 2706 | 2661 | } |
| 2707 | 2662 | |
| 2708 | if (bodies.linksection_body) |b| { | |
| 2663 | if (decl.linksection_body) |b| { | |
| 2709 | 2664 | try stream.writeAll(" linksection="); |
| 2710 | 2665 | try self.writeBracedDecl(stream, b); |
| 2711 | 2666 | } |
| 2712 | 2667 | |
| 2713 | if (bodies.addrspace_body) |b| { | |
| 2668 | if (decl.addrspace_body) |b| { | |
| 2714 | 2669 | try stream.writeAll(" addrspace="); |
| 2715 | 2670 | try self.writeBracedDecl(stream, b); |
| 2716 | 2671 | } |
| 2672 | ||
| 2673 | if (decl.value_body) |b| { | |
| 2674 | try stream.writeAll(" value="); | |
| 2675 | try self.writeBracedDecl(stream, b); | |
| 2676 | } | |
| 2717 | 2677 | } |
| 2718 | 2678 | |
| 2719 | 2679 | try stream.writeAll(") "); |
test/behavior/globals.zig+96| ... | ... | @@ -66,3 +66,99 @@ test "global loads can affect liveness" { |
| 66 | 66 | S.f(); |
| 67 | 67 | try std.testing.expect(y.a == 1); |
| 68 | 68 | } |
| 69 | ||
| 70 | test "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 | ||
| 85 | test "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 | ||
| 112 | test "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 | ||
| 136 | test "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 { |
| 10 | 10 | // target=native |
| 11 | 11 | // |
| 12 | 12 | // :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 @@ |
| 1 | const S = struct { self: *S, x: u32 }; | |
| 2 | const s: S = .{ .self = &s, .x = 123 }; | |
| 3 | ||
| 4 | comptime { | |
| 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 { |
| 7 | 7 | // backend=stage2 |
| 8 | 8 | // target=native |
| 9 | 9 | // |
| 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 { |
| 8 | 8 | // backend=stage2 |
| 9 | 9 | // target=native |
| 10 | 10 | // |
| 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 |