authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-23 20:39:19+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-12-24 02:18:41+00:00
log3afda4322c34dedc2319701fdfac3505c8d311e9
tree467873c408750cb4223f3ccf31775e42ec9fbd5c
parent40aafcd6a85d3c517f445f17149c17523c832420
signaturelock-open Commit is signed but in an unrecognized format.

compiler: analyze type and value of global declaration separately

This commit separates semantic analysis of the annotated type vs value of a global declaration, therefore allowing recursive and mutually recursive values to be declared. Every `Nav` which undergoes analysis now has *two* corresponding `AnalUnit`s: `.{ .nav_val = n }` and `.{ .nav_ty = n }`. The `nav_val` unit is responsible for *fully resolving* the `Nav`: determining its value, linksection, addrspace, etc. The `nav_ty` unit, on the other hand, resolves only the information necessary to construct a *pointer* to the `Nav`: its type, addrspace, etc. (It does also analyze its linksection, but that could be moved to `nav_val` I think; it doesn't make any difference). Analyzing a `nav_ty` for a declaration with no type annotation will just mark a dependency on the `nav_val`, analyze it, and finish. Conversely, analyzing a `nav_val` for a declaration *with* a type annotation will first mark a dependency on the `nav_ty` and analyze it, using this as the result type when evaluating the value body. The `nav_val` and `nav_ty` units always have references to one another: so, if a `Nav`'s type is referenced, its value implicitly is too, and vice versa. However, these dependencies are trivial, so, to save memory, are only known implicitly by logic in `resolveReferences`. In general, analyzing ZIR `decl_val` will only analyze `nav_ty` of the corresponding `Nav`. There are two exceptions to this. If the declaration is an `extern` declaration, then we immediately ensure the `Nav` value is resolved (which doesn't actually require any more analysis, since such a declaration has no value body anyway). Additionally, if the resolved type has type tag `.@"fn"`, we again immediately resolve the `Nav` value. The latter restriction is in place for two reasons: * Functions are special, in that their externs are allowed to trivially alias; i.e. with a declaration `extern fn foo(...)`, you can write `const bar = foo;`. This is not allowed for non-function externs, and it means that function types are the only place where it is possible for a declaration `Nav` to have a `.@"extern"` value without actually being declared `extern`. We need to identify this situation immediately so that the `decl_ref` can create a pointer to the *real* extern `Nav`, not this alias. * In certain situations, such as taking a pointer to a `Nav`, Sema needs to queue analysis of a runtime function if the value is a function. To do this, the function value needs to be known, so we need to resolve the value immediately upon `&foo` where `foo` is a function. This restriction is simple to codify into the eventual language specification, and doesn't limit the utility of this feature in practice. A consequence of this commit is that codegen and linking logic needs to be more careful when looking at `Nav`s. In general: * When `updateNav` or `updateFunc` is called, it is safe to assume that the `Nav` being updated (the owner `Nav` for `updateFunc`) is fully resolved. * Any `Nav` whose value is/will be an `@"extern"` or a function is fully resolved; see `Nav.getExtern` for a helper for a common case here. * Any other `Nav` may only have its type resolved. This didn't seem to be too tricky to satisfy in any of the existing codegen/linker backends. Resolves: #131

22 files changed, 1033 insertions(+), 410 deletions(-)

src/Compilation.zig+10-4
...@@ -2906,6 +2906,7 @@ const Header = extern struct {...@@ -2906,6 +2906,7 @@ const Header = extern struct {
2906 file_deps_len: u32,2906 file_deps_len: u32,
2907 src_hash_deps_len: u32,2907 src_hash_deps_len: u32,
2908 nav_val_deps_len: u32,2908 nav_val_deps_len: u32,
2909 nav_ty_deps_len: u32,
2909 namespace_deps_len: u32,2910 namespace_deps_len: u32,
2910 namespace_name_deps_len: u32,2911 namespace_name_deps_len: u32,
2911 first_dependency_len: u32,2912 first_dependency_len: u32,
...@@ -2949,6 +2950,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2949,6 +2950,7 @@ pub fn saveState(comp: *Compilation) !void {
2949 .file_deps_len = @intCast(ip.file_deps.count()),2950 .file_deps_len = @intCast(ip.file_deps.count()),
2950 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),2951 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
2951 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),2952 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
2953 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
2952 .namespace_deps_len = @intCast(ip.namespace_deps.count()),2954 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
2953 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),2955 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
2954 .first_dependency_len = @intCast(ip.first_dependency.count()),2956 .first_dependency_len = @intCast(ip.first_dependency.count()),
...@@ -2979,6 +2981,8 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2979,6 +2981,8 @@ pub fn saveState(comp: *Compilation) !void {
2979 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));2981 addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
2980 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));2982 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
2981 addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));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()));
2982 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));2986 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));
2983 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));2987 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));
2984 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));2988 addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
...@@ -3145,7 +3149,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3145,7 +3149,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
31453149
3146 const file_index = switch (anal_unit.unwrap()) {3150 const file_index = switch (anal_unit.unwrap()) {
3147 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),3151 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
3148 .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),3152 .nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
3149 .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),3153 .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
3150 .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),3154 .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
3151 };3155 };
...@@ -3380,7 +3384,7 @@ pub fn addModuleErrorMsg(...@@ -3380,7 +3384,7 @@ pub fn addModuleErrorMsg(
3380 defer gpa.free(rt_file_path);3384 defer gpa.free(rt_file_path);
3381 const name = switch (ref.referencer.unwrap()) {3385 const name = switch (ref.referencer.unwrap()) {
3382 .@"comptime" => "comptime",3386 .@"comptime" => "comptime",
3383 .nav_val => |nav| ip.getNav(nav).name.toSlice(ip),3387 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
3384 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),3388 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
3385 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),3389 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
3386 };3390 };
...@@ -3647,6 +3651,7 @@ fn performAllTheWorkInner(...@@ -3647,6 +3651,7 @@ fn performAllTheWorkInner(
3647 try comp.queueJob(switch (outdated.unwrap()) {3651 try comp.queueJob(switch (outdated.unwrap()) {
3648 .func => |f| .{ .analyze_func = f },3652 .func => |f| .{ .analyze_func = f },
3649 .@"comptime",3653 .@"comptime",
3654 .nav_ty,
3650 .nav_val,3655 .nav_val,
3651 .type,3656 .type,
3652 => .{ .analyze_comptime_unit = outdated },3657 => .{ .analyze_comptime_unit = outdated },
...@@ -3679,7 +3684,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3679,7 +3684,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3679 return;3684 return;
3680 }3685 }
3681 }3686 }
3682 assert(nav.status == .resolved);3687 assert(nav.status == .fully_resolved);
3683 comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index });3688 comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index });
3684 },3689 },
3685 .codegen_func => |func| {3690 .codegen_func => |func| {
...@@ -3709,6 +3714,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3709,6 +3714,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
37093714
3710 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {3715 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
3711 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),3716 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
3717 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
3712 .nav_val => |nav| pt.ensureNavValUpToDate(nav),3718 .nav_val => |nav| pt.ensureNavValUpToDate(nav),
3713 .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,3719 .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,
3714 .func => unreachable,3720 .func => unreachable,
...@@ -3734,7 +3740,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3734,7 +3740,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3734 // Tests are always emitted in test binaries. The decl_refs are created by3740 // Tests are always emitted in test binaries. The decl_refs are created by
3735 // Zcu.populateTestFunctions, but this will not queue body analysis, so do3741 // Zcu.populateTestFunctions, but this will not queue body analysis, so do
3736 // that now.3742 // that now.
3737 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.resolved.val);3743 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val);
3738 }3744 }
3739 },3745 },
3740 .resolve_type_fully => |ty| {3746 .resolve_type_fully => |ty| {
src/InternPool.zig+201-54
...@@ -34,6 +34,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index),...@@ -34,6 +34,9 @@ src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index),
34/// Dependencies on the value of a Nav.34/// Dependencies on the value of a Nav.
35/// Value is index into `dep_entries` of the first dependency on this Nav value.35/// Value is index into `dep_entries` of the first dependency on this Nav value.
36nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),36nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
37/// Dependencies on the type of a Nav.
38/// Value is index into `dep_entries` of the first dependency on this Nav value.
39nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
37/// Dependencies on an interned value, either:40/// Dependencies on an interned value, either:
38/// * a runtime function (invalidated when its IES changes)41/// * a runtime function (invalidated when its IES changes)
39/// * a container type requiring resolution (invalidated when the type must be recreated at a new index)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,6 +83,7 @@ pub const empty: InternPool = .{
80 .file_deps = .empty,83 .file_deps = .empty,
81 .src_hash_deps = .empty,84 .src_hash_deps = .empty,
82 .nav_val_deps = .empty,85 .nav_val_deps = .empty,
86 .nav_ty_deps = .empty,
83 .interned_deps = .empty,87 .interned_deps = .empty,
84 .namespace_deps = .empty,88 .namespace_deps = .empty,
85 .namespace_name_deps = .empty,89 .namespace_name_deps = .empty,
...@@ -371,6 +375,7 @@ pub const AnalUnit = packed struct(u64) {...@@ -371,6 +375,7 @@ pub const AnalUnit = packed struct(u64) {
371 pub const Kind = enum(u32) {375 pub const Kind = enum(u32) {
372 @"comptime",376 @"comptime",
373 nav_val,377 nav_val,
378 nav_ty,
374 type,379 type,
375 func,380 func,
376 };381 };
...@@ -380,6 +385,8 @@ pub const AnalUnit = packed struct(u64) {...@@ -380,6 +385,8 @@ pub const AnalUnit = packed struct(u64) {
380 @"comptime": ComptimeUnit.Id,385 @"comptime": ComptimeUnit.Id,
381 /// This `AnalUnit` resolves the value of the given `Nav`.386 /// This `AnalUnit` resolves the value of the given `Nav`.
382 nav_val: Nav.Index,387 nav_val: Nav.Index,
388 /// This `AnalUnit` resolves the type of the given `Nav`.
389 nav_ty: Nav.Index,
383 /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type.390 /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type.
384 /// Generated tag enums are never used here (they do not undergo type resolution).391 /// Generated tag enums are never used here (they do not undergo type resolution).
385 type: InternPool.Index,392 type: InternPool.Index,
...@@ -483,8 +490,20 @@ pub const Nav = struct {...@@ -483,8 +490,20 @@ pub const Nav = struct {
483 status: union(enum) {490 status: union(enum) {
484 /// This `Nav` is pending semantic analysis.491 /// This `Nav` is pending semantic analysis.
485 unresolved,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 },
486 /// The value of this `Nav` is resolved.505 /// The value of this `Nav` is resolved.
487 resolved: struct {506 fully_resolved: struct {
488 val: InternPool.Index,507 val: InternPool.Index,
489 alignment: Alignment,508 alignment: Alignment,
490 @"linksection": OptionalNullTerminatedString,509 @"linksection": OptionalNullTerminatedString,
...@@ -492,14 +511,81 @@ pub const Nav = struct {...@@ -492,14 +511,81 @@ pub const Nav = struct {
492 },511 },
493 },512 },
494513
495 /// Asserts that `status == .resolved`.514 /// Asserts that `status != .unresolved`.
496 pub fn typeOf(nav: Nav, ip: *const InternPool) InternPool.Index {515 pub fn typeOf(nav: Nav, ip: *const InternPool) InternPool.Index {
497 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 };
498 }521 }
499522
500 /// Asserts that `status == .resolved`.523 /// Always returns `null` for `status == .type_resolved`. This function is inteded
501 pub fn isExtern(nav: Nav, ip: *const InternPool) bool {524 /// to be used by code generation, since semantic analysis will ensure that any `Nav`
502 return ip.indexToKey(nav.status.resolved.val) == .@"extern";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 };
536 }
537
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 };
503 }589 }
504590
505 /// Get the ZIR instruction corresponding to this `Nav`, used to resolve source locations.591 /// Get the ZIR instruction corresponding to this `Nav`, used to resolve source locations.
...@@ -509,7 +595,7 @@ pub const Nav = struct {...@@ -509,7 +595,7 @@ pub const Nav = struct {
509 return a.zir_index;595 return a.zir_index;
510 }596 }
511 // A `Nav` which does not undergo analysis always has a resolved value.597 // A `Nav` which does not undergo analysis always has a resolved value.
512 return switch (ip.indexToKey(nav.status.resolved.val)) {598 return switch (ip.indexToKey(nav.status.fully_resolved.val)) {
513 .func => |func| {599 .func => |func| {
514 // Since `analysis` was not populated, this must be an instantiation.600 // Since `analysis` was not populated, this must be an instantiation.
515 // Go up to the generic owner and consult *its* `analysis` field.601 // Go up to the generic owner and consult *its* `analysis` field.
...@@ -567,19 +653,22 @@ pub const Nav = struct {...@@ -567,19 +653,22 @@ pub const Nav = struct {
567 // The following 1 fields are either both populated, or both `.none`.653 // The following 1 fields are either both populated, or both `.none`.
568 analysis_namespace: OptionalNamespaceIndex,654 analysis_namespace: OptionalNamespaceIndex,
569 analysis_zir_index: TrackedInst.Index.Optional,655 analysis_zir_index: TrackedInst.Index.Optional,
570 /// Populated only if `bits.status == .resolved`.656 /// Populated only if `bits.status != .unresolved`.
571 val: InternPool.Index,657 type_or_val: InternPool.Index,
572 /// Populated only if `bits.status == .resolved`.658 /// Populated only if `bits.status != .unresolved`.
573 @"linksection": OptionalNullTerminatedString,659 @"linksection": OptionalNullTerminatedString,
574 bits: Bits,660 bits: Bits,
575661
576 const Bits = packed struct(u16) {662 const Bits = packed struct(u16) {
577 status: enum(u1) { unresolved, resolved },663 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
578 /// Populated only if `bits.status == .resolved`.664 /// Populated only if `bits.status != .unresolved`.
579 alignment: Alignment,665 alignment: Alignment,
580 /// Populated only if `bits.status == .resolved`.666 /// Populated only if `bits.status != .unresolved`.
581 @"addrspace": std.builtin.AddressSpace,667 @"addrspace": std.builtin.AddressSpace,
582 _: 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,
583 is_usingnamespace: bool,672 is_usingnamespace: bool,
584 };673 };
585674
...@@ -597,8 +686,17 @@ pub const Nav = struct {...@@ -597,8 +686,17 @@ pub const Nav = struct {
597 .is_usingnamespace = repr.bits.is_usingnamespace,686 .is_usingnamespace = repr.bits.is_usingnamespace,
598 .status = switch (repr.bits.status) {687 .status = switch (repr.bits.status) {
599 .unresolved => .unresolved,688 .unresolved => .unresolved,
600 .resolved => .{ .resolved = .{689 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
601 .val = repr.val,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,
602 .alignment = repr.bits.alignment,700 .alignment = repr.bits.alignment,
603 .@"linksection" = repr.@"linksection",701 .@"linksection" = repr.@"linksection",
604 .@"addrspace" = repr.bits.@"addrspace",702 .@"addrspace" = repr.bits.@"addrspace",
...@@ -616,13 +714,15 @@ pub const Nav = struct {...@@ -616,13 +714,15 @@ pub const Nav = struct {
616 .fqn = nav.fqn,714 .fqn = nav.fqn,
617 .analysis_namespace = if (nav.analysis) |a| a.namespace.toOptional() else .none,715 .analysis_namespace = if (nav.analysis) |a| a.namespace.toOptional() else .none,
618 .analysis_zir_index = if (nav.analysis) |a| a.zir_index.toOptional() else .none,716 .analysis_zir_index = if (nav.analysis) |a| a.zir_index.toOptional() else .none,
619 .val = switch (nav.status) {717 .type_or_val = switch (nav.status) {
620 .unresolved => .none,718 .unresolved => .none,
621 .resolved => |r| r.val,719 .type_resolved => |r| r.type,
720 .fully_resolved => |r| r.val,
622 },721 },
623 .@"linksection" = switch (nav.status) {722 .@"linksection" = switch (nav.status) {
624 .unresolved => .none,723 .unresolved => .none,
625 .resolved => |r| r.@"linksection",724 .type_resolved => |r| r.@"linksection",
725 .fully_resolved => |r| r.@"linksection",
626 },726 },
627 .bits = switch (nav.status) {727 .bits = switch (nav.status) {
628 .unresolved => .{728 .unresolved => .{
...@@ -630,12 +730,24 @@ pub const Nav = struct {...@@ -630,12 +730,24 @@ pub const Nav = struct {
630 .alignment = .none,730 .alignment = .none,
631 .@"addrspace" = .generic,731 .@"addrspace" = .generic,
632 .is_usingnamespace = nav.is_usingnamespace,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,
633 },743 },
634 .resolved => |r| .{744 .fully_resolved => |r| .{
635 .status = .resolved,745 .status = .fully_resolved,
636 .alignment = r.alignment,746 .alignment = r.alignment,
637 .@"addrspace" = r.@"addrspace",747 .@"addrspace" = r.@"addrspace",
638 .is_usingnamespace = nav.is_usingnamespace,748 .is_usingnamespace = nav.is_usingnamespace,
749 .is_const = false,
750 .is_threadlocal = false,
639 },751 },
640 },752 },
641 };753 };
...@@ -646,6 +758,7 @@ pub const Dependee = union(enum) {...@@ -646,6 +758,7 @@ pub const Dependee = union(enum) {
646 file: FileIndex,758 file: FileIndex,
647 src_hash: TrackedInst.Index,759 src_hash: TrackedInst.Index,
648 nav_val: Nav.Index,760 nav_val: Nav.Index,
761 nav_ty: Nav.Index,
649 interned: Index,762 interned: Index,
650 namespace: TrackedInst.Index,763 namespace: TrackedInst.Index,
651 namespace_name: NamespaceNameKey,764 namespace_name: NamespaceNameKey,
...@@ -695,6 +808,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI...@@ -695,6 +808,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
695 .file => |x| ip.file_deps.get(x),808 .file => |x| ip.file_deps.get(x),
696 .src_hash => |x| ip.src_hash_deps.get(x),809 .src_hash => |x| ip.src_hash_deps.get(x),
697 .nav_val => |x| ip.nav_val_deps.get(x),810 .nav_val => |x| ip.nav_val_deps.get(x),
811 .nav_ty => |x| ip.nav_ty_deps.get(x),
698 .interned => |x| ip.interned_deps.get(x),812 .interned => |x| ip.interned_deps.get(x),
699 .namespace => |x| ip.namespace_deps.get(x),813 .namespace => |x| ip.namespace_deps.get(x),
700 .namespace_name => |x| ip.namespace_name_deps.get(x),814 .namespace_name => |x| ip.namespace_name_deps.get(x),
...@@ -732,6 +846,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -732,6 +846,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
732 .file => ip.file_deps,846 .file => ip.file_deps,
733 .src_hash => ip.src_hash_deps,847 .src_hash => ip.src_hash_deps,
734 .nav_val => ip.nav_val_deps,848 .nav_val => ip.nav_val_deps,
849 .nav_ty => ip.nav_ty_deps,
735 .interned => ip.interned_deps,850 .interned => ip.interned_deps,
736 .namespace => ip.namespace_deps,851 .namespace => ip.namespace_deps,
737 .namespace_name => ip.namespace_name_deps,852 .namespace_name => ip.namespace_name_deps,
...@@ -2079,36 +2194,36 @@ pub const Key = union(enum) {...@@ -2079,36 +2194,36 @@ pub const Key = union(enum) {
2079 return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered);2194 return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered);
2080 }2195 }
20812196
2082 pub fn setAnalysisState(func: Func, ip: *InternPool, state: FuncAnalysis.State) void {2197 pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void {
2083 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;2198 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2084 extra_mutex.lock();2199 extra_mutex.lock();
2085 defer extra_mutex.unlock();2200 defer extra_mutex.unlock();
20862201
2087 const analysis_ptr = func.analysisPtr(ip);2202 const analysis_ptr = func.analysisPtr(ip);
2088 var analysis = analysis_ptr.*;2203 var analysis = analysis_ptr.*;
2089 analysis.state = state;2204 analysis.calls_or_awaits_errorable_fn = value;
2090 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);2205 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
2091 }2206 }
20922207
2093 pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void {2208 pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void {
2094 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;2209 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2095 extra_mutex.lock();2210 extra_mutex.lock();
2096 defer extra_mutex.unlock();2211 defer extra_mutex.unlock();
20972212
2098 const analysis_ptr = func.analysisPtr(ip);2213 const analysis_ptr = func.analysisPtr(ip);
2099 var analysis = analysis_ptr.*;2214 var analysis = analysis_ptr.*;
2100 analysis.calls_or_awaits_errorable_fn = value;2215 analysis.branch_hint = hint;
2101 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);2216 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
2102 }2217 }
21032218
2104 pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void {2219 pub fn setAnalyzed(func: Func, ip: *InternPool) void {
2105 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;2220 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2106 extra_mutex.lock();2221 extra_mutex.lock();
2107 defer extra_mutex.unlock();2222 defer extra_mutex.unlock();
21082223
2109 const analysis_ptr = func.analysisPtr(ip);2224 const analysis_ptr = func.analysisPtr(ip);
2110 var analysis = analysis_ptr.*;2225 var analysis = analysis_ptr.*;
2111 analysis.branch_hint = hint;2226 analysis.is_analyzed = true;
2112 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);2227 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
2113 }2228 }
21142229
...@@ -5755,7 +5870,7 @@ pub const Tag = enum(u8) {...@@ -5755,7 +5870,7 @@ pub const Tag = enum(u8) {
5755/// equality or hashing, except for `inferred_error_set` which is considered5870/// equality or hashing, except for `inferred_error_set` which is considered
5756/// to be part of the type of the function.5871/// to be part of the type of the function.
5757pub const FuncAnalysis = packed struct(u32) {5872pub const FuncAnalysis = packed struct(u32) {
5758 state: State,5873 is_analyzed: bool,
5759 branch_hint: std.builtin.BranchHint,5874 branch_hint: std.builtin.BranchHint,
5760 is_noinline: bool,5875 is_noinline: bool,
5761 calls_or_awaits_errorable_fn: bool,5876 calls_or_awaits_errorable_fn: bool,
...@@ -5763,20 +5878,7 @@ pub const FuncAnalysis = packed struct(u32) {...@@ -5763,20 +5878,7 @@ pub const FuncAnalysis = packed struct(u32) {
5763 inferred_error_set: bool,5878 inferred_error_set: bool,
5764 disable_instrumentation: bool,5879 disable_instrumentation: bool,
57655880
5766 _: u23 = 0,5881 _: u24 = 0,
5767
5768 pub const State = enum(u2) {
5769 /// The runtime function has never been referenced.
5770 /// As such, it has never been analyzed, nor is it queued for analysis.
5771 unreferenced,
5772 /// The runtime function has been referenced, but has not yet been analyzed.
5773 /// Its semantic analysis is queued.
5774 queued,
5775 /// The runtime function has been (or is currently being) semantically analyzed.
5776 /// To know if analysis succeeded, consult `zcu.[transitive_]failed_analysis`.
5777 /// To know if analysis is up-to-date, consult `zcu.[potentially_]outdated`.
5778 analyzed,
5779 };
5780};5882};
57815883
5782pub const Bytes = struct {5884pub const Bytes = struct {
...@@ -6419,6 +6521,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -6419,6 +6521,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
6419 ip.file_deps.deinit(gpa);6521 ip.file_deps.deinit(gpa);
6420 ip.src_hash_deps.deinit(gpa);6522 ip.src_hash_deps.deinit(gpa);
6421 ip.nav_val_deps.deinit(gpa);6523 ip.nav_val_deps.deinit(gpa);
6524 ip.nav_ty_deps.deinit(gpa);
6422 ip.interned_deps.deinit(gpa);6525 ip.interned_deps.deinit(gpa);
6423 ip.namespace_deps.deinit(gpa);6526 ip.namespace_deps.deinit(gpa);
6424 ip.namespace_name_deps.deinit(gpa);6527 ip.namespace_name_deps.deinit(gpa);
...@@ -6875,8 +6978,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -6875,8 +6978,8 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
6875 .is_threadlocal = extra.flags.is_threadlocal,6978 .is_threadlocal = extra.flags.is_threadlocal,
6876 .is_weak_linkage = extra.flags.is_weak_linkage,6979 .is_weak_linkage = extra.flags.is_weak_linkage,
6877 .is_dll_import = extra.flags.is_dll_import,6980 .is_dll_import = extra.flags.is_dll_import,
6878 .alignment = nav.status.resolved.alignment,6981 .alignment = nav.status.fully_resolved.alignment,
6879 .@"addrspace" = nav.status.resolved.@"addrspace",6982 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
6880 .zir_index = extra.zir_index,6983 .zir_index = extra.zir_index,
6881 .owner_nav = extra.owner_nav,6984 .owner_nav = extra.owner_nav,
6882 } };6985 } };
...@@ -8794,7 +8897,7 @@ pub fn getFuncDecl(...@@ -8794,7 +8897,7 @@ pub fn getFuncDecl(
87948897
8795 const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{8898 const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{
8796 .analysis = .{8899 .analysis = .{
8797 .state = .unreferenced,8900 .is_analyzed = false,
8798 .branch_hint = .none,8901 .branch_hint = .none,
8799 .is_noinline = key.is_noinline,8902 .is_noinline = key.is_noinline,
8800 .calls_or_awaits_errorable_fn = false,8903 .calls_or_awaits_errorable_fn = false,
...@@ -8903,7 +9006,7 @@ pub fn getFuncDeclIes(...@@ -8903,7 +9006,7 @@ pub fn getFuncDeclIes(
89039006
8904 const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{9007 const func_decl_extra_index = addExtraAssumeCapacity(extra, Tag.FuncDecl{
8905 .analysis = .{9008 .analysis = .{
8906 .state = .unreferenced,9009 .is_analyzed = false,
8907 .branch_hint = .none,9010 .branch_hint = .none,
8908 .is_noinline = key.is_noinline,9011 .is_noinline = key.is_noinline,
8909 .calls_or_awaits_errorable_fn = false,9012 .calls_or_awaits_errorable_fn = false,
...@@ -9099,7 +9202,7 @@ pub fn getFuncInstance(...@@ -9099,7 +9202,7 @@ pub fn getFuncInstance(
90999202
9100 const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{9203 const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{
9101 .analysis = .{9204 .analysis = .{
9102 .state = .unreferenced,9205 .is_analyzed = false,
9103 .branch_hint = .none,9206 .branch_hint = .none,
9104 .is_noinline = arg.is_noinline,9207 .is_noinline = arg.is_noinline,
9105 .calls_or_awaits_errorable_fn = false,9208 .calls_or_awaits_errorable_fn = false,
...@@ -9197,7 +9300,7 @@ pub fn getFuncInstanceIes(...@@ -9197,7 +9300,7 @@ pub fn getFuncInstanceIes(
91979300
9198 const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{9301 const func_extra_index = addExtraAssumeCapacity(extra, Tag.FuncInstance{
9199 .analysis = .{9302 .analysis = .{
9200 .state = .unreferenced,9303 .is_analyzed = false,
9201 .branch_hint = .none,9304 .branch_hint = .none,
9202 .is_noinline = arg.is_noinline,9305 .is_noinline = arg.is_noinline,
9203 .calls_or_awaits_errorable_fn = false,9306 .calls_or_awaits_errorable_fn = false,
...@@ -9316,9 +9419,9 @@ fn finishFuncInstance(...@@ -9316,9 +9419,9 @@ fn finishFuncInstance(
9316 .name = nav_name,9419 .name = nav_name,
9317 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),9420 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
9318 .val = func_index,9421 .val = func_index,
9319 .alignment = fn_owner_nav.status.resolved.alignment,9422 .alignment = fn_owner_nav.status.fully_resolved.alignment,
9320 .@"linksection" = fn_owner_nav.status.resolved.@"linksection",9423 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
9321 .@"addrspace" = fn_owner_nav.status.resolved.@"addrspace",9424 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
9322 });9425 });
93239426
9324 // Populate the owner_nav field which was left undefined until now.9427 // Populate the owner_nav field which was left undefined until now.
...@@ -11030,7 +11133,7 @@ pub fn createNav(...@@ -11030,7 +11133,7 @@ pub fn createNav(
11030 .name = opts.name,11133 .name = opts.name,
11031 .fqn = opts.fqn,11134 .fqn = opts.fqn,
11032 .analysis = null,11135 .analysis = null,
11033 .status = .{ .resolved = .{11136 .status = .{ .fully_resolved = .{
11034 .val = opts.val,11137 .val = opts.val,
11035 .alignment = opts.alignment,11138 .alignment = opts.alignment,
11036 .@"linksection" = opts.@"linksection",11139 .@"linksection" = opts.@"linksection",
...@@ -11077,6 +11180,50 @@ pub fn createDeclNav(...@@ -11077,6 +11180,50 @@ pub fn createDeclNav(
11077 return nav;11180 return nav;
11078}11181}
1107911182
11183/// Resolve the type of a `Nav` with an analysis owner.
11184/// If its status is already `resolved`, the old value is discarded.
11185pub fn resolveNavType(
11186 ip: *InternPool,
11187 nav: Nav.Index,
11188 resolved: struct {
11189 type: InternPool.Index,
11190 alignment: Alignment,
11191 @"linksection": OptionalNullTerminatedString,
11192 @"addrspace": std.builtin.AddressSpace,
11193 is_const: bool,
11194 is_threadlocal: bool,
11195 is_extern_decl: bool,
11196 },
11197) void {
11198 const unwrapped = nav.unwrap(ip);
11199
11200 const local = ip.getLocal(unwrapped.tid);
11201 local.mutate.extra.mutex.lock();
11202 defer local.mutate.extra.mutex.unlock();
11203
11204 const navs = local.shared.navs.view();
11205
11206 const nav_analysis_namespace = navs.items(.analysis_namespace);
11207 const nav_analysis_zir_index = navs.items(.analysis_zir_index);
11208 const nav_types = navs.items(.type_or_val);
11209 const nav_linksections = navs.items(.@"linksection");
11210 const nav_bits = navs.items(.bits);
11211
11212 assert(nav_analysis_namespace[unwrapped.index] != .none);
11213 assert(nav_analysis_zir_index[unwrapped.index] != .none);
11214
11215 @atomicStore(InternPool.Index, &nav_types[unwrapped.index], resolved.type, .release);
11216 @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
11217
11218 var bits = nav_bits[unwrapped.index];
11219 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
11220 bits.alignment = resolved.alignment;
11221 bits.@"addrspace" = resolved.@"addrspace";
11222 bits.is_const = resolved.is_const;
11223 bits.is_threadlocal = resolved.is_threadlocal;
11224 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
11225}
11226
11080/// Resolve the value of a `Nav` with an analysis owner.11227/// Resolve the value of a `Nav` with an analysis owner.
11081/// If its status is already `resolved`, the old value is discarded.11228/// If its status is already `resolved`, the old value is discarded.
11082pub fn resolveNavValue(11229pub fn resolveNavValue(
...@@ -11099,7 +11246,7 @@ pub fn resolveNavValue(...@@ -11099,7 +11246,7 @@ pub fn resolveNavValue(
1109911246
11100 const nav_analysis_namespace = navs.items(.analysis_namespace);11247 const nav_analysis_namespace = navs.items(.analysis_namespace);
11101 const nav_analysis_zir_index = navs.items(.analysis_zir_index);11248 const nav_analysis_zir_index = navs.items(.analysis_zir_index);
11102 const nav_vals = navs.items(.val);11249 const nav_vals = navs.items(.type_or_val);
11103 const nav_linksections = navs.items(.@"linksection");11250 const nav_linksections = navs.items(.@"linksection");
11104 const nav_bits = navs.items(.bits);11251 const nav_bits = navs.items(.bits);
1110511252
...@@ -11110,7 +11257,7 @@ pub fn resolveNavValue(...@@ -11110,7 +11257,7 @@ pub fn resolveNavValue(
11110 @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);11257 @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
1111111258
11112 var bits = nav_bits[unwrapped.index];11259 var bits = nav_bits[unwrapped.index];
11113 bits.status = .resolved;11260 bits.status = .fully_resolved;
11114 bits.alignment = resolved.alignment;11261 bits.alignment = resolved.alignment;
11115 bits.@"addrspace" = resolved.@"addrspace";11262 bits.@"addrspace" = resolved.@"addrspace";
11116 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);11263 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
src/Sema.zig+157-46
...@@ -6495,9 +6495,9 @@ pub fn analyzeExport(...@@ -6495,9 +6495,9 @@ pub fn analyzeExport(
6495 if (options.linkage == .internal)6495 if (options.linkage == .internal)
6496 return;6496 return;
64976497
6498 try sema.ensureNavResolved(src, orig_nav_index);6498 try sema.ensureNavResolved(src, orig_nav_index, .fully);
64996499
6500 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)) {
6501 .variable => |v| v.owner_nav,6501 .variable => |v| v.owner_nav,
6502 .@"extern" => |e| e.owner_nav,6502 .@"extern" => |e| e.owner_nav,
6503 .func => |f| f.owner_nav,6503 .func => |f| f.owner_nav,
...@@ -6520,7 +6520,7 @@ pub fn analyzeExport(...@@ -6520,7 +6520,7 @@ pub fn analyzeExport(
6520 }6520 }
65216521
6522 // TODO: some backends might support re-exporting extern decls6522 // TODO: some backends might support re-exporting extern decls
6523 if (exported_nav.isExtern(ip)) {6523 if (exported_nav.getExtern(ip) != null) {
6524 return sema.fail(block, src, "export target cannot be extern", .{});6524 return sema.fail(block, src, "export target cannot be extern", .{});
6525 }6525 }
65266526
...@@ -6542,6 +6542,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {...@@ -6542,6 +6542,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
6542 .func => |func| func,6542 .func => |func| func,
6543 .@"comptime",6543 .@"comptime",
6544 .nav_val,6544 .nav_val,
6545 .nav_ty,
6545 .type,6546 .type,
6546 => return, // does nothing outside a function6547 => return, // does nothing outside a function
6547 };6548 };
...@@ -6854,8 +6855,8 @@ fn lookupInNamespace(...@@ -6854,8 +6855,8 @@ fn lookupInNamespace(
6854 }6855 }
68556856
6856 for (usingnamespaces.items) |sub_ns_nav| {6857 for (usingnamespaces.items) |sub_ns_nav| {
6857 try sema.ensureNavResolved(src, sub_ns_nav);6858 try sema.ensureNavResolved(src, sub_ns_nav, .fully);
6858 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.resolved.val);6859 const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val);
6859 const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));6860 const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu));
6860 try checked_namespaces.put(gpa, sub_ns, {});6861 try checked_namespaces.put(gpa, sub_ns, {});
6861 }6862 }
...@@ -6865,7 +6866,7 @@ fn lookupInNamespace(...@@ -6865,7 +6866,7 @@ fn lookupInNamespace(
6865 ignore_self: {6866 ignore_self: {
6866 const skip_nav = switch (sema.owner.unwrap()) {6867 const skip_nav = switch (sema.owner.unwrap()) {
6867 .@"comptime", .type, .func => break :ignore_self,6868 .@"comptime", .type, .func => break :ignore_self,
6868 .nav_val => |nav| nav,6869 .nav_ty, .nav_val => |nav| nav,
6869 };6870 };
6870 var i: usize = 0;6871 var i: usize = 0;
6871 while (i < candidates.items.len) {6872 while (i < candidates.items.len) {
...@@ -7125,7 +7126,7 @@ fn zirCall(...@@ -7125,7 +7126,7 @@ fn zirCall(
7125 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);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);
71267127
7127 switch (sema.owner.unwrap()) {7128 switch (sema.owner.unwrap()) {
7128 .@"comptime", .type, .nav_val => input_is_error = false,7129 .@"comptime", .type, .nav_ty, .nav_val => input_is_error = false,
7129 .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) {7130 .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) {
7130 // No errorable fn actually called; we have no error return trace7131 // No errorable fn actually called; we have no error return trace
7131 input_is_error = false;7132 input_is_error = false;
...@@ -7686,12 +7687,13 @@ fn analyzeCall(...@@ -7686,12 +7687,13 @@ fn analyzeCall(
7686 .ptr => |ptr| blk: {7687 .ptr => |ptr| blk: {
7687 switch (ptr.base_addr) {7688 switch (ptr.base_addr) {
7688 .nav => |nav_index| if (ptr.byte_offset == 0) {7689 .nav => |nav_index| if (ptr.byte_offset == 0) {
7690 try sema.ensureNavResolved(call_src, nav_index, .fully);
7689 const nav = ip.getNav(nav_index);7691 const nav = ip.getNav(nav_index);
7690 if (nav.isExtern(ip))7692 if (nav.getExtern(ip) != null)
7691 return sema.fail(block, call_src, "{s} call of extern function pointer", .{7693 return sema.fail(block, call_src, "{s} call of extern function pointer", .{
7692 if (is_comptime_call) "comptime" else "inline",7694 if (is_comptime_call) "comptime" else "inline",
7693 });7695 });
7694 break :blk nav.status.resolved.val;7696 break :blk nav.status.fully_resolved.val;
7695 },7697 },
7696 else => {},7698 else => {},
7697 }7699 }
...@@ -8007,7 +8009,7 @@ fn analyzeCall(...@@ -8007,7 +8009,7 @@ fn analyzeCall(
8007 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);8009 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
80088010
8009 switch (sema.owner.unwrap()) {8011 switch (sema.owner.unwrap()) {
8010 .@"comptime", .nav_val, .type => {},8012 .@"comptime", .nav_ty, .nav_val, .type => {},
8011 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {8013 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
8012 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);8014 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
8013 },8015 },
...@@ -8046,7 +8048,10 @@ fn analyzeCall(...@@ -8046,7 +8048,10 @@ fn analyzeCall(
8046 switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {8048 switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {
8047 .func => break :skip_safety,8049 .func => break :skip_safety,
8048 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {8050 .ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
8049 .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 },
8050 else => {},8055 else => {},
8051 },8056 },
8052 else => {},8057 else => {},
...@@ -8243,7 +8248,7 @@ fn instantiateGenericCall(...@@ -8243,7 +8248,7 @@ fn instantiateGenericCall(
8243 });8248 });
8244 const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {8249 const generic_owner = switch (zcu.intern_pool.indexToKey(func_val.toIntern())) {
8245 .func => func_val.toIntern(),8250 .func => func_val.toIntern(),
8246 .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.resolved.val,8251 .ptr => |ptr| ip.getNav(ptr.base_addr.nav).status.fully_resolved.val,
8247 else => unreachable,8252 else => unreachable,
8248 };8253 };
8249 const generic_owner_func = zcu.intern_pool.indexToKey(generic_owner).func;8254 const generic_owner_func = zcu.intern_pool.indexToKey(generic_owner).func;
...@@ -8471,7 +8476,7 @@ fn instantiateGenericCall(...@@ -8471,7 +8476,7 @@ fn instantiateGenericCall(
8471 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);8476 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
84728477
8473 switch (sema.owner.unwrap()) {8478 switch (sema.owner.unwrap()) {
8474 .@"comptime", .nav_val, .type => {},8479 .@"comptime", .nav_ty, .nav_val, .type => {},
8475 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {8480 .func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
8476 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);8481 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
8477 },8482 },
...@@ -19311,8 +19316,8 @@ fn typeInfoNamespaceDecls(...@@ -19311,8 +19316,8 @@ fn typeInfoNamespaceDecls(
19311 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {19316 if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) {
19312 continue;19317 continue;
19313 }19318 }
19314 try sema.ensureNavResolved(src, nav);19319 try sema.ensureNavResolved(src, nav, .fully);
19315 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.resolved.val);19320 const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val);
19316 try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);19321 try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces);
19317 }19322 }
19318}19323}
...@@ -21602,7 +21607,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -21602,7 +21607,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
21602 .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) {21607 .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) {
21603 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);21608 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
21604 },21609 },
21605 .@"comptime", .nav_val, .type => {},21610 .@"comptime", .nav_ty, .nav_val, .type => {},
21606 }21611 }
21607 return Air.internedToRef(try pt.intern(.{ .opt = .{21612 return Air.internedToRef(try pt.intern(.{ .opt = .{
21608 .ty = opt_ptr_stack_trace_ty.toIntern(),21613 .ty = opt_ptr_stack_trace_ty.toIntern(),
...@@ -27086,7 +27091,7 @@ fn zirBuiltinExtern(...@@ -27086,7 +27091,7 @@ fn zirBuiltinExtern(
27086 .zir_index = switch (sema.owner.unwrap()) {27091 .zir_index = switch (sema.owner.unwrap()) {
27087 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,27092 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
27088 .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,27093 .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,
27089 .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,27094 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
27090 .func => |func| zir_index: {27095 .func => |func| zir_index: {
27091 const func_info = zcu.funcInfo(func);27096 const func_info = zcu.funcInfo(func);
27092 const owner_func_info = if (func_info.generic_owner != .none) owner: {27097 const owner_func_info = if (func_info.generic_owner != .none) owner: {
...@@ -27741,7 +27746,7 @@ fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.Pan...@@ -27741,7 +27746,7 @@ fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.Pan
27741 error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,27746 error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
27742 error.OutOfMemory => |e| return e,27747 error.OutOfMemory => |e| return e,
27743 }).?;27748 }).?;
27744 try sema.ensureNavResolved(src, msg_nav_index);27749 try sema.ensureNavResolved(src, msg_nav_index, .fully);
27745 zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional();27750 zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional();
27746 return msg_nav_index;27751 return msg_nav_index;
27747}27752}
...@@ -32648,21 +32653,29 @@ fn addTypeReferenceEntry(...@@ -32648,21 +32653,29 @@ fn addTypeReferenceEntry(
32648 try zcu.addTypeReference(sema.owner, referenced_type, src);32653 try zcu.addTypeReference(sema.owner, referenced_type, src);
32649}32654}
3265032655
32651pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!void {32656pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
32652 const pt = sema.pt;32657 const pt = sema.pt;
32653 const zcu = pt.zcu;32658 const zcu = pt.zcu;
32654 const ip = &zcu.intern_pool;32659 const ip = &zcu.intern_pool;
3265532660
32656 const nav = ip.getNav(nav_index);32661 const nav = ip.getNav(nav_index);
32657 if (nav.analysis == null) {32662 if (nav.analysis == null) {
32658 assert(nav.status == .resolved);32663 assert(nav.status == .fully_resolved);
32659 return;32664 return;
32660 }32665 }
3266132666
32667 try sema.declareDependency(switch (kind) {
32668 .type => .{ .nav_ty = nav_index },
32669 .fully => .{ .nav_val = nav_index },
32670 });
32671
32662 // Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`32672 // Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`
32663 // to make sure the value is up-to-date on incremental updates.32673 // to make sure the value is up-to-date on incremental updates.
3266432674
32665 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_index });32675 const anal_unit: AnalUnit = .wrap(switch (kind) {
32676 .type => .{ .nav_ty = nav_index },
32677 .fully => .{ .nav_val = nav_index },
32678 });
32666 try sema.addReferenceEntry(src, anal_unit);32679 try sema.addReferenceEntry(src, anal_unit);
3266732680
32668 if (zcu.analysis_in_progress.contains(anal_unit)) {32681 if (zcu.analysis_in_progress.contains(anal_unit)) {
...@@ -32672,7 +32685,13 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav...@@ -32672,7 +32685,13 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav
32672 }, "dependency loop detected", .{}));32685 }, "dependency loop detected", .{}));
32673 }32686 }
3267432687
32675 return pt.ensureNavValUpToDate(nav_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 }
32676}32695}
3267732696
32678fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {32697fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
...@@ -32691,36 +32710,44 @@ fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index)...@@ -32691,36 +32710,44 @@ fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index)
32691 return sema.analyzeNavRefInner(src, nav_index, true);32710 return sema.analyzeNavRefInner(src, nav_index, true);
32692}32711}
3269332712
32694/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed, but32713/// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed.
32695/// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a32714/// If this pointer will be used directly, `is_ref` must be `true`.
32696/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeNavRef` wraps32715/// If this pointer will be immediately loaded (i.e. a `decl_val` instruction), `is_ref` must be `false`.
32697/// this function with `analyze_fn_body` set to true.32716fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref {
32698fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
32699 const pt = sema.pt;32717 const pt = sema.pt;
32700 const zcu = pt.zcu;32718 const zcu = pt.zcu;
32701 const ip = &zcu.intern_pool;32719 const ip = &zcu.intern_pool;
3270232720
32703 // TODO: if this is a `decl_ref` of a non-variable Nav, only depend on Nav type32721 try sema.ensureNavResolved(src, orig_nav_index, if (is_ref) .type else .fully);
32704 try sema.declareDependency(.{ .nav_val = orig_nav_index });
32705 try sema.ensureNavResolved(src, orig_nav_index);
3270632722
32707 const nav_val = zcu.navValue(orig_nav_index);32723 const nav_index = nav: {
32708 const nav_index, const is_const = switch (ip.indexToKey(nav_val.toIntern())) {32724 if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
32709 .variable => |v| .{ v.owner_nav, false },32725 // Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
32710 .func => |f| .{ f.owner_nav, true },32726 // We need to resolve the value to know for sure.
32711 .@"extern" => |e| .{ e.owner_nav, e.is_const },32727 if (is_ref) try sema.ensureNavResolved(src, orig_nav_index, .fully);
32712 else => .{ orig_nav_index, true },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 };
32736
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) },
32713 };32741 };
32714 const nav_info = ip.getNav(nav_index).status.resolved;
32715 const ptr_ty = try pt.ptrTypeSema(.{32742 const ptr_ty = try pt.ptrTypeSema(.{
32716 .child = nav_val.typeOf(zcu).toIntern(),32743 .child = ty,
32717 .flags = .{32744 .flags = .{
32718 .alignment = nav_info.alignment,32745 .alignment = alignment,
32719 .is_const = is_const,32746 .is_const = is_const,
32720 .address_space = nav_info.@"addrspace",32747 .address_space = @"addrspace",
32721 },32748 },
32722 });32749 });
32723 if (analyze_fn_body) {32750 if (is_ref) {
32724 try sema.maybeQueueFuncBodyAnalysis(src, nav_index);32751 try sema.maybeQueueFuncBodyAnalysis(src, nav_index);
32725 }32752 }
32726 return Air.internedToRef((try pt.intern(.{ .ptr = .{32753 return Air.internedToRef((try pt.intern(.{ .ptr = .{
...@@ -32731,11 +32758,22 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N...@@ -32731,11 +32758,22 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N
32731}32758}
3273232759
32733fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {32760fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void {
32734 const zcu = sema.pt.zcu;32761 const pt = sema.pt;
32762 const zcu = pt.zcu;
32735 const ip = &zcu.intern_pool;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);
32736 const nav_val = zcu.navValue(nav_index);32774 const nav_val = zcu.navValue(nav_index);
32737 if (!ip.isFuncBody(nav_val.toIntern())) return;32775 if (!ip.isFuncBody(nav_val.toIntern())) return;
32738 if (!try nav_val.typeOf(zcu).fnHasRuntimeBitsSema(sema.pt)) return;32776
32739 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));32777 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() }));
32740 try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());32778 try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
32741}32779}
...@@ -38450,11 +38488,16 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {...@@ -38450,11 +38488,16 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
38450 // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would38488 // of a type and they use `@This()`. This dependency would be unnecessary, and in fact would
38451 // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve38489 // just result in over-analysis since `Zcu.findOutdatedToAnalyze` would never be able to resolve
38452 // the loop.38490 // the loop.
38491 // Note that this also disallows a `nav_val`
38453 switch (sema.owner.unwrap()) {38492 switch (sema.owner.unwrap()) {
38454 .nav_val => |this_nav| switch (dependee) {38493 .nav_val => |this_nav| switch (dependee) {
38455 .nav_val => |other_nav| if (this_nav == other_nav) return,38494 .nav_val => |other_nav| if (this_nav == other_nav) return,
38456 else => {},38495 else => {},
38457 },38496 },
38497 .nav_ty => |this_nav| switch (dependee) {
38498 .nav_ty => |other_nav| if (this_nav == other_nav) return,
38499 else => {},
38500 },
38458 else => {},38501 else => {},
38459 }38502 }
3846038503
...@@ -38873,8 +38916,8 @@ fn getBuiltinInnerType(...@@ -38873,8 +38916,8 @@ fn getBuiltinInnerType(
38873 const nav = opt_nav orelse return sema.fail(block, src, "std.builtin.{s} missing {s}", .{38916 const nav = opt_nav orelse return sema.fail(block, src, "std.builtin.{s} missing {s}", .{
38874 compile_error_parent_name, inner_name,38917 compile_error_parent_name, inner_name,
38875 });38918 });
38876 try sema.ensureNavResolved(src, nav);38919 try sema.ensureNavResolved(src, nav, .fully);
38877 const val = Value.fromInterned(ip.getNav(nav).status.resolved.val);38920 const val = Value.fromInterned(ip.getNav(nav).status.fully_resolved.val);
38878 const ty = val.toType();38921 const ty = val.toType();
38879 try ty.resolveFully(pt);38922 try ty.resolveFully(pt);
38880 return ty;38923 return ty;
...@@ -38886,5 +38929,73 @@ fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref {...@@ -38886,5 +38929,73 @@ fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref {
38886 const ip = &zcu.intern_pool;38929 const ip = &zcu.intern_pool;
38887 const nav = try pt.getBuiltinNav(name);38930 const nav = try pt.getBuiltinNav(name);
38888 try pt.ensureNavValUpToDate(nav);38931 try pt.ensureNavValUpToDate(nav);
38889 return Air.internedToRef(ip.getNav(nav).status.resolved.val);38932 return Air.internedToRef(ip.getNav(nav).status.fully_resolved.val);
38933}
38934
38935pub const NavPtrModifiers = struct {
38936 alignment: Alignment,
38937 @"linksection": InternPool.OptionalNullTerminatedString,
38938 @"addrspace": std.builtin.AddressSpace,
38939};
38940
38941pub fn resolveNavPtrModifiers(
38942 sema: *Sema,
38943 block: *Block,
38944 zir_decl: Zir.Inst.Declaration.Unwrapped,
38945 decl_inst: Zir.Inst.Index,
38946 nav_ty: Type,
38947) CompileError!NavPtrModifiers {
38948 const pt = sema.pt;
38949 const zcu = pt.zcu;
38950 const gpa = zcu.gpa;
38951 const ip = &zcu.intern_pool;
38952
38953 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
38954 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
38955 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
38956
38957 const alignment: InternPool.Alignment = a: {
38958 const align_body = zir_decl.align_body orelse break :a .none;
38959 const align_ref = try sema.resolveInlineBody(block, align_body, decl_inst);
38960 break :a try sema.analyzeAsAlign(block, align_src, align_ref);
38961 };
38962
38963 const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
38964 const linksection_body = zir_decl.linksection_body orelse break :ls .none;
38965 const linksection_ref = try sema.resolveInlineBody(block, linksection_body, decl_inst);
38966 const bytes = try sema.toConstString(block, section_src, linksection_ref, .{
38967 .needed_comptime_reason = "linksection must be comptime-known",
38968 });
38969 if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
38970 return sema.fail(block, section_src, "linksection cannot contain null bytes", .{});
38971 } else if (bytes.len == 0) {
38972 return sema.fail(block, section_src, "linksection cannot be empty", .{});
38973 }
38974 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
38975 };
38976
38977 const @"addrspace": std.builtin.AddressSpace = as: {
38978 const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
38979 .@"var" => .variable,
38980 else => switch (nav_ty.zigTypeTag(zcu)) {
38981 .@"fn" => .function,
38982 else => .constant,
38983 },
38984 };
38985 const target = zcu.getTarget();
38986 const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {
38987 .function => target_util.defaultAddressSpace(target, .function),
38988 .variable => target_util.defaultAddressSpace(target, .global_mutable),
38989 .constant => target_util.defaultAddressSpace(target, .global_constant),
38990 else => unreachable,
38991 };
38992 const addrspace_ref = try sema.resolveInlineBody(block, addrspace_body, decl_inst);
38993 break :as try sema.analyzeAsAddressSpace(block, addrspace_src, addrspace_ref, addrspace_ctx);
38994 };
38995
38996 return .{
38997 .alignment = alignment,
38998 .@"linksection" = @"linksection",
38999 .@"addrspace" = @"addrspace",
39000 };
38890}39001}
src/Sema/comptime_ptr_access.zig+2-3
...@@ -219,9 +219,8 @@ fn loadComptimePtrInner(...@@ -219,9 +219,8 @@ fn loadComptimePtrInner(
219219
220 const base_val: MutableValue = switch (ptr.base_addr) {220 const base_val: MutableValue = switch (ptr.base_addr) {
221 .nav => |nav| val: {221 .nav => |nav| val: {
222 try sema.declareDependency(.{ .nav_val = nav });222 try sema.ensureNavResolved(src, nav, .fully);
223 try sema.ensureNavResolved(src, nav);223 const val = ip.getNav(nav).status.fully_resolved.val;
224 const val = ip.getNav(nav).status.resolved.val;
225 switch (ip.indexToKey(val)) {224 switch (ip.indexToKey(val)) {
226 .variable => return .runtime_load,225 .variable => return .runtime_load,
227 // We let `.@"extern"` through here if it's a function.226 // We let `.@"extern"` through here if it's a function.
src/Value.zig+6-1
...@@ -1343,7 +1343,12 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {...@@ -1343,7 +1343,12 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {
1343pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool {1343pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool {
1344 const ip = &zcu.intern_pool;1344 const ip = &zcu.intern_pool;
1345 const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;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 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,1352 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
1348 .variable => |v| v.is_threadlocal,1353 .variable => |v| v.is_threadlocal,
1349 else => false,1354 else => false,
src/Zcu.zig+72-9
...@@ -170,6 +170,9 @@ outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,...@@ -170,6 +170,9 @@ outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
170/// it as outdated.170/// it as outdated.
171retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,171retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
172172
173func_body_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty,
174nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
175
173/// These are the modules which we initially queue for analysis in `Compilation.update`.176/// These are the modules which we initially queue for analysis in `Compilation.update`.
174/// `resolveReferences` will use these as the root of its reachability traversal.177/// `resolveReferences` will use these as the root of its reachability traversal.
175analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},178analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
...@@ -282,7 +285,11 @@ pub const Exported = union(enum) {...@@ -282,7 +285,11 @@ pub const Exported = union(enum) {
282285
283 pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {286 pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
284 return switch (exported) {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 .uav => .none,293 .uav => .none,
287 };294 };
288 }295 }
...@@ -2241,6 +2248,9 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2241,6 +2248,9 @@ pub fn deinit(zcu: *Zcu) void {
2241 zcu.outdated_ready.deinit(gpa);2248 zcu.outdated_ready.deinit(gpa);
2242 zcu.retryable_failures.deinit(gpa);2249 zcu.retryable_failures.deinit(gpa);
22432250
2251 zcu.func_body_analysis_queued.deinit(gpa);
2252 zcu.nav_val_analysis_queued.deinit(gpa);
2253
2244 zcu.test_functions.deinit(gpa);2254 zcu.test_functions.deinit(gpa);
22452255
2246 for (zcu.global_assembly.values()) |s| {2256 for (zcu.global_assembly.values()) |s| {
...@@ -2441,6 +2451,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -2441,6 +2451,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
2441 switch (depender.unwrap()) {2451 switch (depender.unwrap()) {
2442 .@"comptime" => {},2452 .@"comptime" => {},
2443 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),2453 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
2454 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
2444 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),2455 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
2445 .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),2456 .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
2446 }2457 }
...@@ -2453,7 +2464,8 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -2453,7 +2464,8 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
2453 const ip = &zcu.intern_pool;2464 const ip = &zcu.intern_pool;
2454 const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) {2465 const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) {
2455 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies2466 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies
2456 .nav_val => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced2467 .nav_val => |nav| .{ .nav_val = nav },
2468 .nav_ty => |nav| .{ .nav_ty = nav },
2457 .type => |ty| .{ .interned = ty },2469 .type => |ty| .{ .interned = ty },
2458 .func => |func_index| .{ .interned = func_index }, // IES2470 .func => |func_index| .{ .interned = func_index }, // IES
2459 };2471 };
...@@ -2540,6 +2552,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {...@@ -2540,6 +2552,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
2540 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice2552 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
2541 .type => |ty| .{ .interned = ty },2553 .type => |ty| .{ .interned = ty },
2542 .nav_val => |nav| .{ .nav_val = nav },2554 .nav_val => |nav| .{ .nav_val = nav },
2555 .nav_ty => |nav| .{ .nav_ty = nav },
2543 });2556 });
2544 while (it.next()) |_| n += 1;2557 while (it.next()) |_| n += 1;
25452558
...@@ -2780,14 +2793,39 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo...@@ -2780,14 +2793,39 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo
2780 const ip = &zcu.intern_pool;2793 const ip = &zcu.intern_pool;
2781 const func = zcu.funcInfo(func_index);2794 const func = zcu.funcInfo(func_index);
27822795
2783 switch (func.analysisUnordered(ip).state) {2796 if (zcu.func_body_analysis_queued.contains(func_index)) return;
2784 .unreferenced => {}, // We're the first reference!2797
2785 .queued => return, // Analysis is already queued.2798 if (func.analysisUnordered(ip).is_analyzed) {
2786 .analyzed => return, // Analysis is complete; if it's out-of-date, it'll be re-analyzed later this update.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 }
2787 }2805 }
27882806
2807 try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
2789 try zcu.comp.queueJob(.{ .analyze_func = func_index });2808 try zcu.comp.queueJob(.{ .analyze_func = func_index });
2790 func.setAnalysisState(ip, .queued);2809 zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {});
2810}
2811
2812pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void {
2813 const ip = &zcu.intern_pool;
2814
2815 if (zcu.nav_val_analysis_queued.contains(nav_id)) return;
2816
2817 if (ip.getNav(nav_id).status == .fully_resolved) {
2818 if (!zcu.outdated.contains(.wrap(.{ .nav_val = nav_id })) and
2819 !zcu.potentially_outdated.contains(.wrap(.{ .nav_val = nav_id })))
2820 {
2821 // This `Nav` has been analyzed before and is definitely up-to-date.
2822 return;
2823 }
2824 }
2825
2826 try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
2827 try zcu.comp.queueJob(.{ .analyze_comptime_unit = .wrap(.{ .nav_val = nav_id }) });
2828 zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
2791}2829}
27922830
2793pub const ImportFileResult = struct {2831pub const ImportFileResult = struct {
...@@ -3424,6 +3462,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv...@@ -3424,6 +3462,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
3424 const unit = kv.key;3462 const unit = kv.key;
3425 try result.putNoClobber(gpa, unit, kv.value);3463 try result.putNoClobber(gpa, unit, kv.value);
34263464
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
3427 log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)});3476 log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)});
34283477
3429 if (zcu.reference_table.get(unit)) |first_ref_idx| {3478 if (zcu.reference_table.get(unit)) |first_ref_idx| {
...@@ -3513,7 +3562,7 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {...@@ -3513,7 +3562,7 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
3513}3562}
35143563
3515pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {3564pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
3516 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);
3517}3566}
35183567
3519pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {3568pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {
...@@ -3547,6 +3596,7 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co...@@ -3547,6 +3596,7 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
3547 }3596 }
3548 },3597 },
3549 .nav_val => |nav| return writer.print("nav_val('{}')", .{ip.getNav(nav).fqn.fmt(ip)}),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)}),
3550 .type => |ty| return writer.print("ty('{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),3600 .type => |ty| return writer.print("ty('{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
3551 .func => |func| {3601 .func => |func| {
3552 const nav = zcu.funcInfo(func).owner_nav;3602 const nav = zcu.funcInfo(func).owner_nav;
...@@ -3572,7 +3622,11 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com...@@ -3572,7 +3622,11 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
3572 },3622 },
3573 .nav_val => |nav| {3623 .nav_val => |nav| {
3574 const fqn = ip.getNav(nav).fqn;3624 const fqn = ip.getNav(nav).fqn;
3575 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)});
3576 },3630 },
3577 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {3631 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
3578 .struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),3632 .struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),
...@@ -3749,3 +3803,12 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu...@@ -3749,3 +3803,12 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
3749 if (!backend_ok) return .{ .bad_backend = backend };3803 if (!backend_ok) return .{ .bad_backend = backend };
3750 return .ok;3804 return .ok;
3751}3805}
3806
3807/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer.
3808pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool {
3809 return switch (zcu.intern_pool.indexToKey(val)) {
3810 .variable => false,
3811 .@"extern" => |e| e.is_const,
3812 else => true,
3813 };
3814}
src/Zcu/PerThread.zig+340-136
...@@ -731,10 +731,12 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -731,10 +731,12 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
731 const gpa = zcu.gpa;731 const gpa = zcu.gpa;
732 const ip = &zcu.intern_pool;732 const ip = &zcu.intern_pool;
733733
734 _ = zcu.nav_val_analysis_queued.swapRemove(nav_id);
735
734 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });736 const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
735 const nav = ip.getNav(nav_id);737 const nav = ip.getNav(nav_id);
736738
737 log.debug("ensureNavUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});739 log.debug("ensureNavValUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
738740
739 // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the741 // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
740 // status is `.unresolved`, which indicates that the value is outdated because it has *never*742 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
...@@ -763,19 +765,19 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -763,19 +765,19 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
763 } else {765 } else {
764 // We can trust the current information about this unit.766 // We can trust the current information about this unit.
765 if (prev_failed) return error.AnalysisFail;767 if (prev_failed) return error.AnalysisFail;
766 if (nav.status == .resolved) return;768 switch (nav.status) {
769 .unresolved, .type_resolved => {},
770 .fully_resolved => return,
771 }
767 }772 }
768773
769 const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0);774 const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0);
770 defer unit_prog_node.end();775 defer unit_prog_node.end();
771776
772 const sema_result: SemaNavResult, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: {777 const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: {
773 break :res .{778 break :res .{
774 .{779 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
775 // If the unit has gone from failed to success, we still need to invalidate the dependencies.780 result.val_changed or prev_failed,
776 .invalidate_nav_val = result.invalidate_nav_val or prev_failed,
777 .invalidate_nav_ref = result.invalidate_nav_ref or prev_failed,
778 },
779 false,781 false,
780 };782 };
781 } else |err| switch (err) {783 } else |err| switch (err) {
...@@ -786,10 +788,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -786,10 +788,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
786 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});788 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
787 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});789 log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(anal_unit)});
788 }790 }
789 break :res .{ .{791 break :res .{ !prev_failed, true };
790 .invalidate_nav_val = !prev_failed,
791 .invalidate_nav_ref = !prev_failed,
792 }, true };
793 },792 },
794 error.OutOfMemory => {793 error.OutOfMemory => {
795 // TODO: it's unclear how to gracefully handle this.794 // TODO: it's unclear how to gracefully handle this.
...@@ -806,10 +805,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -806,10 +805,8 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
806 };805 };
807806
808 if (was_outdated) {807 if (was_outdated) {
809 // TODO: we do not yet have separate dependencies for Nav values vs types.
810 const invalidate = sema_result.invalidate_nav_val or sema_result.invalidate_nav_ref;
811 const dependee: InternPool.Dependee = .{ .nav_val = nav_id };808 const dependee: InternPool.Dependee = .{ .nav_val = nav_id };
812 if (invalidate) {809 if (invalidate_value) {
813 // This dependency was marked as PO, meaning dependees were waiting810 // This dependency was marked as PO, meaning dependees were waiting
814 // on its analysis result, and it has turned out to be outdated.811 // on its analysis result, and it has turned out to be outdated.
815 // Update dependees accordingly.812 // Update dependees accordingly.
...@@ -824,14 +821,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -824,14 +821,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
824 if (new_failed) return error.AnalysisFail;821 if (new_failed) return error.AnalysisFail;
825}822}
826823
827const SemaNavResult = packed struct {824fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { val_changed: bool } {
828 /// Whether the value of a `decl_val` of the corresponding Nav changed.
829 invalidate_nav_val: bool,
830 /// Whether the type of a `decl_ref` of the corresponding Nav changed.
831 invalidate_nav_ref: bool,
832};
833
834fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!SemaNavResult {
835 const zcu = pt.zcu;825 const zcu = pt.zcu;
836 const gpa = zcu.gpa;826 const gpa = zcu.gpa;
837 const ip = &zcu.intern_pool;827 const ip = &zcu.intern_pool;
...@@ -875,9 +865,13 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -875,9 +865,13 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
875 };865 };
876 defer sema.deinit();866 defer sema.deinit();
877867
878 // The comptime unit declares on the source of the corresponding declaration.868 // Every `Nav` declares a dependency on the source of the corresponding declaration.
879 try sema.declareDependency(.{ .src_hash = old_nav.analysis.?.zir_index });869 try sema.declareDependency(.{ .src_hash = old_nav.analysis.?.zir_index });
880870
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
881 var block: Sema.Block = .{875 var block: Sema.Block = .{
882 .parent = null,876 .parent = null,
883 .sema = &sema,877 .sema = &sema,
...@@ -891,31 +885,44 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -891,31 +885,44 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
891 defer block.instructions.deinit(gpa);885 defer block.instructions.deinit(gpa);
892886
893 const zir_decl = zir.getDeclaration(inst_resolved.inst);887 const zir_decl = zir.getDeclaration(inst_resolved.inst);
894
895 assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));888 assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
896889
890 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
891 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
897 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });892 const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
898 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });893 const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
899 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });894 const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
900 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });895
901 const init_src = block.src(.{ .node_offset_var_decl_init = 0 });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);
902922
903 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,923 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
904 // or otherwise, we analyze the value body, populating `early_val` in the process.924 // or otherwise, we analyze the value body, populating `early_val` in the process.
905925
906 const nav_ty: Type, const early_val: ?Value = if (zir_decl.type_body) |type_body| ty: {
907 // We evaluate only the type now; no need for the value yet.
908 const uncoerced_type_ref = try sema.resolveInlineBody(&block, type_body, inst_resolved.inst);
909 const type_ref = try sema.coerce(&block, .type, uncoerced_type_ref, ty_src);
910 break :ty .{ .fromInterned(type_ref.toInterned().?), null };
911 } else ty: {
912 // We don't have a type body, so we need to evaluate the value immediately.
913 const value_body = zir_decl.value_body.?;
914 const result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
915 const val = try sema.resolveFinalDeclValue(&block, init_src, result_ref);
916 break :ty .{ val.typeOf(zcu), val };
917 };
918
919 switch (zir_decl.kind) {926 switch (zir_decl.kind) {
920 .@"comptime" => unreachable, // this is not a Nav927 .@"comptime" => unreachable, // this is not a Nav
921 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),928 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),
...@@ -932,58 +939,24 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -932,58 +939,24 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
932 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine939 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
933 // the full pointer type of this declaration.940 // the full pointer type of this declaration.
934941
935 const alignment: InternPool.Alignment = a: {942 const modifiers: Sema.NavPtrModifiers = if (zir_decl.type_body != null) m: {
936 const align_body = zir_decl.align_body orelse break :a .none;943 // `analyzeNavType` (from the `ensureNavTypeUpToDate` call above) has already populated this data into
937 const align_ref = try sema.resolveInlineBody(&block, align_body, inst_resolved.inst);944 // the `Nav`. Load the new one, and pull the modifiers out.
938 break :a try sema.analyzeAsAlign(&block, align_src, align_ref);945 switch (ip.getNav(nav_id).status) {
939 };946 .unresolved => unreachable, // `analyzeNavType` will never leave us in this state
940947 inline .type_resolved, .fully_resolved => |r| break :m .{
941 const @"linksection": InternPool.OptionalNullTerminatedString = ls: {948 .alignment = r.alignment,
942 const linksection_body = zir_decl.linksection_body orelse break :ls .none;949 .@"linksection" = r.@"linksection",
943 const linksection_ref = try sema.resolveInlineBody(&block, linksection_body, inst_resolved.inst);950 .@"addrspace" = r.@"addrspace",
944 const bytes = try sema.toConstString(&block, section_src, linksection_ref, .{
945 .needed_comptime_reason = "linksection must be comptime-known",
946 });
947 if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
948 return sema.fail(&block, section_src, "linksection cannot contain null bytes", .{});
949 } else if (bytes.len == 0) {
950 return sema.fail(&block, section_src, "linksection cannot be empty", .{});
951 }
952 break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
953 };
954
955 const @"addrspace": std.builtin.AddressSpace = as: {
956 const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
957 .@"var" => .variable,
958 else => switch (nav_ty.zigTypeTag(zcu)) {
959 .@"fn" => .function,
960 else => .constant,
961 },951 },
962 };952 }
963 const target = zcu.getTarget();953 } else m: {
964 const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {954 // `analyzeNavType` is essentially a stub which calls us. We are responsible for resolving this data.
965 .function => target_util.defaultAddressSpace(target, .function),955 break :m try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, nav_ty);
966 .variable => target_util.defaultAddressSpace(target, .global_mutable),
967 .constant => target_util.defaultAddressSpace(target, .global_constant),
968 else => unreachable,
969 };
970 const addrspace_ref = try sema.resolveInlineBody(&block, addrspace_body, inst_resolved.inst);
971 break :as try sema.analyzeAsAddressSpace(&block, addrspace_src, addrspace_ref, addrspace_ctx);
972 };956 };
973957
974 // Lastly, we must evaluate the value if we have not already done so. Note, however, that extern declarations958 // Lastly, we must figure out the actual interned value to store to the `Nav`.
975 // don't have an associated value body.959 // This isn't necessarily the same as `final_val`!
976
977 const final_val: ?Value = early_val orelse if (zir_decl.value_body) |value_body| val: {
978 // Put the resolved type into `inst_map` to be used as the result type of the init.
979 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{inst_resolved.inst});
980 sema.inst_map.putAssumeCapacity(inst_resolved.inst, Air.internedToRef(nav_ty.toIntern()));
981 const uncoerced_result_ref = try sema.resolveInlineBody(&block, value_body, inst_resolved.inst);
982 assert(sema.inst_map.remove(inst_resolved.inst));
983
984 const result_ref = try sema.coerce(&block, nav_ty, uncoerced_result_ref, init_src);
985 break :val try sema.resolveFinalDeclValue(&block, init_src, result_ref);
986 } else null;
987960
988 const nav_val: Value = switch (zir_decl.linkage) {961 const nav_val: Value = switch (zir_decl.linkage) {
989 .normal, .@"export" => switch (zir_decl.kind) {962 .normal, .@"export" => switch (zir_decl.kind) {
...@@ -1013,8 +986,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1013,8 +986,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1013 .is_threadlocal = zir_decl.is_threadlocal,986 .is_threadlocal = zir_decl.is_threadlocal,
1014 .is_weak_linkage = false,987 .is_weak_linkage = false,
1015 .is_dll_import = false,988 .is_dll_import = false,
1016 .alignment = alignment,989 .alignment = modifiers.alignment,
1017 .@"addrspace" = @"addrspace",990 .@"addrspace" = modifiers.@"addrspace",
1018 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction991 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
1019 .owner_nav = undefined, // ignored by `getExtern`992 .owner_nav = undefined, // ignored by `getExtern`
1020 }));993 }));
...@@ -1047,10 +1020,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1047,10 +1020,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1047 });1020 });
1048 // TODO: usingnamespace cannot participate in incremental compilation1021 // TODO: usingnamespace cannot participate in incremental compilation
1049 assert(zcu.analysis_in_progress.swapRemove(anal_unit));1022 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1050 return .{1023 return .{ .val_changed = true };
1051 .invalidate_nav_val = true,
1052 .invalidate_nav_ref = true,
1053 };
1054 }1024 }
10551025
1056 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {1026 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
...@@ -1087,14 +1057,22 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1087,14 +1057,22 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
10871057
1088 ip.resolveNavValue(nav_id, .{1058 ip.resolveNavValue(nav_id, .{
1089 .val = nav_val.toIntern(),1059 .val = nav_val.toIntern(),
1090 .alignment = alignment,1060 .alignment = modifiers.alignment,
1091 .@"linksection" = @"linksection",1061 .@"linksection" = modifiers.@"linksection",
1092 .@"addrspace" = @"addrspace",1062 .@"addrspace" = modifiers.@"addrspace",
1093 });1063 });
10941064
1095 // Mark the unit as completed before evaluating the export!1065 // Mark the unit as completed before evaluating the export!
1096 assert(zcu.analysis_in_progress.swapRemove(anal_unit));1066 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
10971067
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
1098 if (zir_decl.linkage == .@"export") {1076 if (zir_decl.linkage == .@"export") {
1099 const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.is_pub) });1077 const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.is_pub) });
1100 const name_slice = zir.nullTerminatedString(zir_decl.name);1078 const name_slice = zir.nullTerminatedString(zir_decl.name);
...@@ -1117,21 +1095,246 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1117,21 +1095,246 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1117 }1095 }
11181096
1119 switch (old_nav.status) {1097 switch (old_nav.status) {
1120 .unresolved => return .{1098 .unresolved, .type_resolved => return .{ .val_changed = true },
1121 .invalidate_nav_val = true,1099 .fully_resolved => |old| return .{ .val_changed = old.val != nav_val.toIntern() },
1122 .invalidate_nav_ref = true,1100 }
1101}
1102
1103pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {
1104 const tracy = trace(@src());
1105 defer tracy.end();
1106
1107 const zcu = pt.zcu;
1108 const gpa = zcu.gpa;
1109 const ip = &zcu.intern_pool;
1110
1111 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
1112 const nav = ip.getNav(nav_id);
1113
1114 log.debug("ensureNavTypeUpToDate {}", .{zcu.fmtAnalUnit(anal_unit)});
1115
1116 // Determine whether or not this `Nav`'s type is outdated. This also includes checking if the
1117 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
1118 // been analyzed so far.
1119 //
1120 // Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
1121 // ensure that the unit is definitely up-to-date when this function returns. This mechanism could
1122 // result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
1123 // carefully choosing which units to re-analyze. See `Zcu.findOutdatedToAnalyze`.
1124
1125 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1126 zcu.potentially_outdated.swapRemove(anal_unit);
1127
1128 const prev_failed = zcu.failed_analysis.contains(anal_unit) or
1129 zcu.transitive_failed_analysis.contains(anal_unit);
1130
1131 if (was_outdated) {
1132 dev.check(.incremental);
1133 _ = zcu.outdated_ready.swapRemove(anal_unit);
1134 zcu.deleteUnitExports(anal_unit);
1135 zcu.deleteUnitReferences(anal_unit);
1136 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1137 kv.value.destroy(gpa);
1138 }
1139 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1140 } else {
1141 // We can trust the current information about this unit.
1142 if (prev_failed) return error.AnalysisFail;
1143 switch (nav.status) {
1144 .unresolved => {},
1145 .type_resolved, .fully_resolved => return,
1146 }
1147 }
1148
1149 const unit_prog_node = zcu.sema_prog_node.start(nav.fqn.toSlice(ip), 0);
1150 defer unit_prog_node.end();
1151
1152 const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id)) |result| res: {
1153 break :res .{
1154 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
1155 result.type_changed or prev_failed,
1156 false,
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 };
1123 },1167 },
1124 .resolved => |old| {1168 error.OutOfMemory => {
1125 const new = ip.getNav(nav_id).status.resolved;1169 // TODO: it's unclear how to gracefully handle this.
1126 return .{1170 // To report the error cleanly, we need to add a message to `failed_analysis` and a
1127 .invalidate_nav_val = new.val != old.val,1171 // corresponding entry to `retryable_failures`; but either of these things is quite
1128 .invalidate_nav_ref = ip.typeOf(new.val) != ip.typeOf(old.val) or1172 // likely to OOM at this point.
1129 new.alignment != old.alignment or1173 // If that happens, what do we do? Perhaps we could have a special field on `Zcu`
1130 new.@"linksection" != old.@"linksection" or1174 // for reporting OOM errors without allocating.
1131 new.@"addrspace" != old.@"addrspace",1175 return error.OutOfMemory;
1132 };
1133 },1176 },
1177 error.GenericPoison => unreachable,
1178 error.ComptimeReturn => unreachable,
1179 error.ComptimeBreak => unreachable,
1180 };
1181
1182 if (was_outdated) {
1183 const dependee: InternPool.Dependee = .{ .nav_ty = nav_id };
1184 if (invalidate_type) {
1185 // This dependency was marked as PO, meaning dependees were waiting
1186 // on its analysis result, and it has turned out to be outdated.
1187 // Update dependees accordingly.
1188 try zcu.markDependeeOutdated(.marked_po, dependee);
1189 } else {
1190 // This dependency was previously PO, but turned out to be up-to-date.
1191 // We do not need to queue successive analysis.
1192 try zcu.markPoDependeeUpToDate(dependee);
1193 }
1134 }1194 }
1195
1196 if (new_failed) return error.AnalysisFail;
1197}
1198
1199fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { type_changed: bool } {
1200 const zcu = pt.zcu;
1201 const gpa = zcu.gpa;
1202 const ip = &zcu.intern_pool;
1203
1204 const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
1205 const old_nav = ip.getNav(nav_id);
1206
1207 log.debug("analyzeNavType {}", .{zcu.fmtAnalUnit(anal_unit)});
1208
1209 const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
1210 const file = zcu.fileByIndex(inst_resolved.file);
1211 // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
1212 // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
1213 // in `ensureComptimeUnitUpToDate`.
1214 if (file.status != .success_zir) return error.AnalysisFail;
1215 const zir = file.zir;
1216
1217 // We are about to re-analyze this unit; drop its depenndencies.
1218 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1219
1220 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1221 defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
1222
1223 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1224 defer analysis_arena.deinit();
1225
1226 var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
1227 defer comptime_err_ret_trace.deinit();
1228
1229 var sema: Sema = .{
1230 .pt = pt,
1231 .gpa = gpa,
1232 .arena = analysis_arena.allocator(),
1233 .code = zir,
1234 .owner = anal_unit,
1235 .func_index = .none,
1236 .func_is_naked = false,
1237 .fn_ret_ty = .void,
1238 .fn_ret_ty_ies = null,
1239 .comptime_err_ret_trace = &comptime_err_ret_trace,
1240 };
1241 defer sema.deinit();
1242
1243 // Every `Nav` declares a dependency on the source of the corresponding declaration.
1244 try sema.declareDependency(.{ .src_hash = old_nav.analysis.?.zir_index });
1245
1246 // In theory, we would also add a reference to the corresponding `nav_val` unit here: there are
1247 // always references in both directions between a `nav_val` and `nav_ty`. However, to save memory,
1248 // these references are known implicitly. See logic in `Zcu.resolveReferences`.
1249
1250 var block: Sema.Block = .{
1251 .parent = null,
1252 .sema = &sema,
1253 .namespace = old_nav.analysis.?.namespace,
1254 .instructions = .{},
1255 .inlining = null,
1256 .is_comptime = true,
1257 .src_base_inst = old_nav.analysis.?.zir_index,
1258 .type_name_ctx = old_nav.fqn,
1259 };
1260 defer block.instructions.deinit(gpa);
1261
1262 const zir_decl = zir.getDeclaration(inst_resolved.inst);
1263 assert(old_nav.is_usingnamespace == (zir_decl.kind == .@"usingnamespace"));
1264
1265 const type_body = zir_decl.type_body orelse {
1266 // The type of this `Nav` is inferred from the value.
1267 // In other words, this `nav_ty` depends on the corresponding `nav_val`.
1268 try sema.declareDependency(.{ .nav_val = nav_id });
1269 try pt.ensureNavValUpToDate(nav_id);
1270 // Note that the above call, if it did any work, has removed our `analysis_in_progress` entry for us.
1271 // (Our `defer` will run anyway, but it does nothing in this case.)
1272
1273 // There's not a great way for us to know whether the type actually changed.
1274 // For instance, perhaps the `nav_val` was already up-to-date, but this `nav_ty` is being
1275 // analyzed because this declaration had a type annotation on the *previous* update.
1276 // However, such cases are rare, and it's not unreasonable to re-analyze in them; and in
1277 // other cases where we get here, it's because the `nav_val` was already re-analyzed and
1278 // is outdated.
1279 return .{ .type_changed = true };
1280 };
1281
1282 const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
1283
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 };
1289
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);
1293
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 };
1301
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 };
1324
1325 if (!changed) return .{ .type_changed = false };
1326
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 });
1336
1337 return .{ .type_changed = true };
1135}1338}
11361339
1137pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {1340pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: InternPool.Index) Zcu.SemaError!void {
...@@ -1144,6 +1347,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter...@@ -1144,6 +1347,8 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
1144 const gpa = zcu.gpa;1347 const gpa = zcu.gpa;
1145 const ip = &zcu.intern_pool;1348 const ip = &zcu.intern_pool;
11461349
1350 _ = zcu.func_body_analysis_queued.swapRemove(maybe_coerced_func_index);
1351
1147 // We only care about the uncoerced function.1352 // We only care about the uncoerced function.
1148 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);1353 const func_index = ip.unwrapCoercedFunc(maybe_coerced_func_index);
1149 const anal_unit: AnalUnit = .wrap(.{ .func = func_index });1354 const anal_unit: AnalUnit = .wrap(.{ .func = func_index });
...@@ -1171,11 +1376,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter...@@ -1171,11 +1376,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
1171 if (prev_failed) {1376 if (prev_failed) {
1172 return error.AnalysisFail;1377 return error.AnalysisFail;
1173 }1378 }
1174 switch (func.analysisUnordered(ip).state) {1379 if (func.analysisUnordered(ip).is_analyzed) return;
1175 .unreferenced => {}, // this is the first reference
1176 .queued => {}, // we're waiting on first-time analysis
1177 .analyzed => return, // up-to-date
1178 }
1179 }1380 }
11801381
1181 const func_prog_node = zcu.sema_prog_node.start(ip.getNav(func.owner_nav).fqn.toSlice(ip), 0);1382 const func_prog_node = zcu.sema_prog_node.start(ip.getNav(func.owner_nav).fqn.toSlice(ip), 0);
...@@ -1236,7 +1437,7 @@ fn analyzeFuncBody(...@@ -1236,7 +1437,7 @@ fn analyzeFuncBody(
1236 if (func.generic_owner == .none) {1437 if (func.generic_owner == .none) {
1237 // Among another things, this ensures that the function's `zir_body_inst` is correct.1438 // Among another things, this ensures that the function's `zir_body_inst` is correct.
1238 try pt.ensureNavValUpToDate(func.owner_nav);1439 try pt.ensureNavValUpToDate(func.owner_nav);
1239 if (ip.getNav(func.owner_nav).status.resolved.val != func_index) {1440 if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {
1240 // This function is no longer referenced! There's no point in re-analyzing it.1441 // This function is no longer referenced! There's no point in re-analyzing it.
1241 // Just mark a transitive failure and move on.1442 // Just mark a transitive failure and move on.
1242 return error.AnalysisFail;1443 return error.AnalysisFail;
...@@ -1245,7 +1446,7 @@ fn analyzeFuncBody(...@@ -1245,7 +1446,7 @@ fn analyzeFuncBody(
1245 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;1446 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
1246 // Among another things, this ensures that the function's `zir_body_inst` is correct.1447 // Among another things, this ensures that the function's `zir_body_inst` is correct.
1247 try pt.ensureNavValUpToDate(go_nav);1448 try pt.ensureNavValUpToDate(go_nav);
1248 if (ip.getNav(go_nav).status.resolved.val != func.generic_owner) {1449 if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {
1249 // The generic owner is no longer referenced, so this function is also unreferenced.1450 // The generic owner is no longer referenced, so this function is also unreferenced.
1250 // There's no point in re-analyzing it. Just mark a transitive failure and move on.1451 // There's no point in re-analyzing it. Just mark a transitive failure and move on.
1251 return error.AnalysisFail;1452 return error.AnalysisFail;
...@@ -2172,7 +2373,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE...@@ -2172,7 +2373,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
2172 try zcu.analysis_in_progress.put(gpa, anal_unit, {});2373 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
2173 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);2374 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
21742375
2175 func.setAnalysisState(ip, .analyzed);2376 func.setAnalyzed(ip);
2176 if (func.analysisUnordered(ip).inferred_error_set) {2377 if (func.analysisUnordered(ip).inferred_error_set) {
2177 func.setResolvedErrorSet(ip, .none);2378 func.setResolvedErrorSet(ip, .none);
2178 }2379 }
...@@ -2550,8 +2751,8 @@ fn processExportsInner(...@@ -2550,8 +2751,8 @@ fn processExportsInner(
2550 if (zcu.transitive_failed_analysis.contains(unit)) break :failed true;2751 if (zcu.transitive_failed_analysis.contains(unit)) break :failed true;
2551 }2752 }
2552 const val = switch (nav.status) {2753 const val = switch (nav.status) {
2553 .unresolved => break :failed true,2754 .unresolved, .type_resolved => break :failed true,
2554 .resolved => |r| Value.fromInterned(r.val),2755 .fully_resolved => |r| Value.fromInterned(r.val),
2555 };2756 };
2556 // If the value is a function, we also need to check if that function succeeded analysis.2757 // If the value is a function, we also need to check if that function succeeded analysis.
2557 if (val.typeOf(zcu).zigTypeTag(zcu) == .@"fn") {2758 if (val.typeOf(zcu).zigTypeTag(zcu) == .@"fn") {
...@@ -3256,30 +3457,29 @@ pub fn getBuiltinNav(pt: Zcu.PerThread, name: []const u8) Allocator.Error!Intern...@@ -3256,30 +3457,29 @@ pub fn getBuiltinNav(pt: Zcu.PerThread, name: []const u8) Allocator.Error!Intern
3256 const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse3457 const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
3257 @panic("lib/std.zig is corrupt and missing 'builtin'");3458 @panic("lib/std.zig is corrupt and missing 'builtin'");
3258 pt.ensureNavValUpToDate(builtin_nav) catch @panic("std.builtin is corrupt");3459 pt.ensureNavValUpToDate(builtin_nav) catch @panic("std.builtin is corrupt");
3259 const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.resolved.val);3460 const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.fully_resolved.val);
3260 const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt"));3461 const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt"));
3261 const name_str = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);3462 const name_str = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
3262 return builtin_namespace.pub_decls.getKeyAdapted(name_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt");3463 return builtin_namespace.pub_decls.getKeyAdapted(name_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt");
3263}3464}
32643465
3265pub fn navPtrType(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) Allocator.Error!Type {3466pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
3266 const zcu = pt.zcu;3467 const zcu = pt.zcu;
3267 const ip = &zcu.intern_pool;3468 const ip = &zcu.intern_pool;
3268 const r = ip.getNav(nav_index).status.resolved;3469 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
3269 const ty = Value.fromInterned(r.val).typeOf(zcu);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 };
3270 return pt.ptrType(.{3474 return pt.ptrType(.{
3271 .child = ty.toIntern(),3475 .child = ty,
3272 .flags = .{3476 .flags = .{
3273 .alignment = if (r.alignment == ty.abiAlignment(zcu))3477 .alignment = if (alignment == Type.fromInterned(ty).abiAlignment(zcu))
3274 .none3478 .none
3275 else3479 else
3276 r.alignment,3480 alignment,
3277 .address_space = r.@"addrspace",3481 .address_space = @"addrspace",
3278 .is_const = switch (ip.indexToKey(r.val)) {3482 .is_const = is_const,
3279 .variable => false,
3280 .@"extern" => |e| e.is_const,
3281 else => true,
3282 },
3283 },3483 },
3284 });3484 });
3285}3485}
...@@ -3299,9 +3499,13 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!...@@ -3299,9 +3499,13 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
3299// TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`.3499// TODO: this shouldn't need a `PerThread`! Fix the signature of `Type.abiAlignment`.
3300pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPool.Alignment {3500pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPool.Alignment {
3301 const zcu = pt.zcu;3501 const zcu = pt.zcu;
3302 const r = zcu.intern_pool.getNav(nav_index).status.resolved;3502 const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
3303 if (r.alignment != .none) return r.alignment;3503 .unresolved => unreachable,
3304 return Value.fromInterned(r.val).typeOf(zcu).abiAlignment(zcu);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);
3305}3509}
33063510
3307/// Given a container type requiring resolution, ensures that it is up-to-date.3511/// Given a container type requiring resolution, ensures that it is up-to-date.
src/arch/wasm/CodeGen.zig+1-9
...@@ -3218,15 +3218,7 @@ fn lowerNavRef(func: *CodeGen, nav_index: InternPool.Nav.Index, offset: u32) Inn...@@ -3218,15 +3218,7 @@ fn lowerNavRef(func: *CodeGen, nav_index: InternPool.Nav.Index, offset: u32) Inn
3218 const zcu = pt.zcu;3218 const zcu = pt.zcu;
3219 const ip = &zcu.intern_pool;3219 const ip = &zcu.intern_pool;
32203220
3221 // check if decl is an alias to a function, in which case we3221 const nav_ty = ip.getNav(nav_index).typeOf(ip);
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);
3230 if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) {3222 if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) {
3231 return .{ .imm32 = 0xaaaaaaaa };3223 return .{ .imm32 = 0xaaaaaaaa };
3232 }3224 }
src/codegen.zig+9-8
...@@ -817,7 +817,7 @@ fn genNavRef(...@@ -817,7 +817,7 @@ fn genNavRef(
817 pt: Zcu.PerThread,817 pt: Zcu.PerThread,
818 src_loc: Zcu.LazySrcLoc,818 src_loc: Zcu.LazySrcLoc,
819 val: Value,819 val: Value,
820 ref_nav_index: InternPool.Nav.Index,820 nav_index: InternPool.Nav.Index,
821 target: std.Target,821 target: std.Target,
822) CodeGenError!GenResult {822) CodeGenError!GenResult {
823 const zcu = pt.zcu;823 const zcu = pt.zcu;
...@@ -851,14 +851,15 @@ fn genNavRef(...@@ -851,14 +851,15 @@ fn genNavRef(
851 }851 }
852 }852 }
853853
854 const nav_index, const is_extern, const lib_name, const is_threadlocal = switch (ip.indexToKey(zcu.navValue(ref_nav_index).toIntern())) {854 const nav = ip.getNav(nav_index);
855 .func => |func| .{ func.owner_nav, false, .none, false },855
856 .variable => |variable| .{ variable.owner_nav, false, .none, variable.is_threadlocal },856 const is_extern, const lib_name, const is_threadlocal = if (nav.getExtern(ip)) |e|
857 .@"extern" => |@"extern"| .{ @"extern".owner_nav, true, @"extern".lib_name, @"extern".is_threadlocal },857 .{ true, e.lib_name, e.is_threadlocal }
858 else => .{ ref_nav_index, false, .none, false },858 else
859 };859 .{ false, .none, nav.isThreadlocal(ip) };
860
860 const single_threaded = zcu.navFileScope(nav_index).mod.single_threaded;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 if (lf.cast(.elf)) |elf_file| {863 if (lf.cast(.elf)) |elf_file| {
863 const zo = elf_file.zigObjectPtr().?;864 const zo = elf_file.zigObjectPtr().?;
864 if (is_extern) {865 if (is_extern) {
src/codegen/c.zig+32-29
...@@ -770,11 +770,14 @@ pub const DeclGen = struct {...@@ -770,11 +770,14 @@ pub const DeclGen = struct {
770 const ctype_pool = &dg.ctype_pool;770 const ctype_pool = &dg.ctype_pool;
771771
772 // Chase function values in order to be able to reference the original function.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())) {773 const owner_nav = switch (ip.getNav(nav_index).status) {
774 .variable => |variable| variable.owner_nav,774 .unresolved => unreachable,
775 .func => |func| func.owner_nav,775 .type_resolved => nav_index, // this can't be an extern or a function
776 .@"extern" => |@"extern"| @"extern".owner_nav,776 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
777 else => nav_index,777 .func => |f| f.owner_nav,
778 .@"extern" => |e| e.owner_nav,
779 else => nav_index,
780 },
778 };781 };
779782
780 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.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,7 +2240,7 @@ pub const DeclGen = struct {
2237 Type.fromInterned(nav.typeOf(ip)),2240 Type.fromInterned(nav.typeOf(ip)),
2238 .{ .nav = nav_index },2241 .{ .nav = nav_index },
2239 CQualifiers.init(.{ .@"const" = flags.is_const }),2242 CQualifiers.init(.{ .@"const" = flags.is_const }),
2240 nav.status.resolved.alignment,2243 nav.getAlignment(),
2241 .complete,2244 .complete,
2242 );2245 );
2243 try fwd.writeAll(";\n");2246 try fwd.writeAll(";\n");
...@@ -2246,19 +2249,19 @@ pub const DeclGen = struct {...@@ -2246,19 +2249,19 @@ pub const DeclGen = struct {
2246 fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {2249 fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {
2247 const zcu = dg.pt.zcu;2250 const zcu = dg.pt.zcu;
2248 const ip = &zcu.intern_pool;2251 const ip = &zcu.intern_pool;
2249 switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {2252 const nav = ip.getNav(nav_index);
2250 .@"extern" => |@"extern"| try writer.print("{ }", .{2253 if (nav.getExtern(ip)) |@"extern"| {
2254 try writer.print("{ }", .{
2251 fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),2255 fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
2252 }),2256 });
2253 else => {2257 } else {
2254 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),2258 // 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.2259 // 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);2260 const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
2257 try writer.print("{}__{d}", .{2261 try writer.print("{}__{d}", .{
2258 fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),2262 fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
2259 @intFromEnum(nav_index),2263 @intFromEnum(nav_index),
2260 });2264 });
2261 },
2262 }2265 }
2263 }2266 }
22642267
...@@ -2826,7 +2829,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn...@@ -2826,7 +2829,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
28262829
2827 const fwd = o.dg.fwdDeclWriter();2830 const fwd = o.dg.fwdDeclWriter();
2828 try fwd.print("static zig_{s} ", .{@tagName(key)});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 .fmt_ctype_pool_string = fn_name,2833 .fmt_ctype_pool_string = fn_name,
2831 });2834 });
2832 try fwd.writeAll(";\n");2835 try fwd.writeAll(";\n");
...@@ -2867,13 +2870,13 @@ pub fn genFunc(f: *Function) !void {...@@ -2867,13 +2870,13 @@ pub fn genFunc(f: *Function) !void {
2867 try o.dg.renderFunctionSignature(2870 try o.dg.renderFunctionSignature(
2868 fwd,2871 fwd,
2869 nav_val,2872 nav_val,
2870 nav.status.resolved.alignment,2873 nav.status.fully_resolved.alignment,
2871 .forward,2874 .forward,
2872 .{ .nav = nav_index },2875 .{ .nav = nav_index },
2873 );2876 );
2874 try fwd.writeAll(";\n");2877 try fwd.writeAll(";\n");
28752878
2876 if (nav.status.resolved.@"linksection".toSlice(ip)) |s|2879 if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
2877 try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});2880 try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
2878 try o.dg.renderFunctionSignature(2881 try o.dg.renderFunctionSignature(
2879 o.writer(),2882 o.writer(),
...@@ -2952,7 +2955,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2952,7 +2955,7 @@ pub fn genDecl(o: *Object) !void {
2952 const nav_ty = Type.fromInterned(nav.typeOf(ip));2955 const nav_ty = Type.fromInterned(nav.typeOf(ip));
29532956
2954 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;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 .@"extern" => |@"extern"| {2959 .@"extern" => |@"extern"| {
2957 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{2960 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
2958 .is_extern = true,2961 .is_extern = true,
...@@ -2965,8 +2968,8 @@ pub fn genDecl(o: *Object) !void {...@@ -2965,8 +2968,8 @@ pub fn genDecl(o: *Object) !void {
2965 try fwd.writeAll("zig_extern ");2968 try fwd.writeAll("zig_extern ");
2966 try o.dg.renderFunctionSignature(2969 try o.dg.renderFunctionSignature(
2967 fwd,2970 fwd,
2968 Value.fromInterned(nav.status.resolved.val),2971 Value.fromInterned(nav.status.fully_resolved.val),
2969 nav.status.resolved.alignment,2972 nav.status.fully_resolved.alignment,
2970 .forward,2973 .forward,
2971 .{ .@"export" = .{2974 .{ .@"export" = .{
2972 .main_name = nav.name,2975 .main_name = nav.name,
...@@ -2985,14 +2988,14 @@ pub fn genDecl(o: *Object) !void {...@@ -2985,14 +2988,14 @@ pub fn genDecl(o: *Object) !void {
2985 const w = o.writer();2988 const w = o.writer();
2986 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");2989 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
2987 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");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 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});2992 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
2990 try o.dg.renderTypeAndName(2993 try o.dg.renderTypeAndName(
2991 w,2994 w,
2992 nav_ty,2995 nav_ty,
2993 .{ .nav = o.dg.pass.nav },2996 .{ .nav = o.dg.pass.nav },
2994 .{},2997 .{},
2995 nav.status.resolved.alignment,2998 nav.status.fully_resolved.alignment,
2996 .complete,2999 .complete,
2997 );3000 );
2998 try w.writeAll(" = ");3001 try w.writeAll(" = ");
...@@ -3002,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {...@@ -3002,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
3002 },3005 },
3003 else => try genDeclValue(3006 else => try genDeclValue(
3004 o,3007 o,
3005 Value.fromInterned(nav.status.resolved.val),3008 Value.fromInterned(nav.status.fully_resolved.val),
3006 .{ .nav = o.dg.pass.nav },3009 .{ .nav = o.dg.pass.nav },
3007 nav.status.resolved.alignment,3010 nav.status.fully_resolved.alignment,
3008 nav.status.resolved.@"linksection",3011 nav.status.fully_resolved.@"linksection",
3009 ),3012 ),
3010 }3013 }
3011}3014}
src/codegen/llvm.zig+28-36
...@@ -1476,7 +1476,7 @@ pub const Object = struct {...@@ -1476,7 +1476,7 @@ pub const Object = struct {
1476 } }, &o.builder);1476 } }, &o.builder);
1477 }1477 }
14781478
1479 if (nav.status.resolved.@"linksection".toSlice(ip)) |section|1479 if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |section|
1480 function_index.setSection(try o.builder.string(section), &o.builder);1480 function_index.setSection(try o.builder.string(section), &o.builder);
14811481
1482 var deinit_wip = true;1482 var deinit_wip = true;
...@@ -1684,7 +1684,7 @@ pub const Object = struct {...@@ -1684,7 +1684,7 @@ pub const Object = struct {
1684 const file = try o.getDebugFile(file_scope);1684 const file = try o.getDebugFile(file_scope);
16851685
1686 const line_number = zcu.navSrcLine(func.owner_nav) + 1;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 const debug_decl_type = try o.lowerDebugType(fn_ty);1688 const debug_decl_type = try o.lowerDebugType(fn_ty);
16891689
1690 const subprogram = try o.builder.debugSubprogram(1690 const subprogram = try o.builder.debugSubprogram(
...@@ -2928,9 +2928,7 @@ pub const Object = struct {...@@ -2928,9 +2928,7 @@ pub const Object = struct {
2928 const gpa = o.gpa;2928 const gpa = o.gpa;
2929 const nav = ip.getNav(nav_index);2929 const nav = ip.getNav(nav_index);
2930 const owner_mod = zcu.navFileScope(nav_index).mod;2930 const owner_mod = zcu.navFileScope(nav_index).mod;
2931 const resolved = nav.status.resolved;2931 const ty: Type = .fromInterned(nav.typeOf(ip));
2932 const val = Value.fromInterned(resolved.val);
2933 const ty = val.typeOf(zcu);
2934 const gop = try o.nav_map.getOrPut(gpa, nav_index);2932 const gop = try o.nav_map.getOrPut(gpa, nav_index);
2935 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;2933 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
29362934
...@@ -2938,14 +2936,14 @@ pub const Object = struct {...@@ -2938,14 +2936,14 @@ pub const Object = struct {
2938 const target = owner_mod.resolved_target.result;2936 const target = owner_mod.resolved_target.result;
2939 const sret = firstParamSRet(fn_info, zcu, target);2937 const sret = firstParamSRet(fn_info, zcu, target);
29402938
2941 const is_extern, const lib_name = switch (ip.indexToKey(val.toIntern())) {2939 const is_extern, const lib_name = if (nav.getExtern(ip)) |@"extern"|
2942 .@"extern" => |@"extern"| .{ true, @"extern".lib_name },2940 .{ true, @"extern".lib_name }
2943 else => .{ false, .none },2941 else
2944 };2942 .{ false, .none };
2945 const function_index = try o.builder.addFunction(2943 const function_index = try o.builder.addFunction(
2946 try o.lowerType(ty),2944 try o.lowerType(ty),
2947 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),2945 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
2948 toLlvmAddressSpace(resolved.@"addrspace", target),2946 toLlvmAddressSpace(nav.getAddrspace(), target),
2949 );2947 );
2950 gop.value_ptr.* = function_index.ptrConst(&o.builder).global;2948 gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
29512949
...@@ -3063,8 +3061,8 @@ pub const Object = struct {...@@ -3063,8 +3061,8 @@ pub const Object = struct {
3063 }3061 }
3064 }3062 }
30653063
3066 if (resolved.alignment != .none)3064 if (nav.getAlignment() != .none)
3067 function_index.setAlignment(resolved.alignment.toLlvm(), &o.builder);3065 function_index.setAlignment(nav.getAlignment().toLlvm(), &o.builder);
30683066
3069 // Function attributes that are independent of analysis results of the function body.3067 // Function attributes that are independent of analysis results of the function body.
3070 try o.addCommonFnAttributes(3068 try o.addCommonFnAttributes(
...@@ -3249,17 +3247,21 @@ pub const Object = struct {...@@ -3249,17 +3247,21 @@ pub const Object = struct {
3249 const zcu = pt.zcu;3247 const zcu = pt.zcu;
3250 const ip = &zcu.intern_pool;3248 const ip = &zcu.intern_pool;
3251 const nav = ip.getNav(nav_index);3249 const nav = ip.getNav(nav_index);
3252 const resolved = nav.status.resolved;3250 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
3253 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (ip.indexToKey(resolved.val)) {3251 .unresolved => unreachable,
3254 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },3252 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
3255 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },3253 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
3256 else => .{ false, false, false, 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 },
3257 };3259 };
32583260
3259 const variable_index = try o.builder.addVariable(3261 const variable_index = try o.builder.addVariable(
3260 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),3262 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
3261 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),3263 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
3262 toLlvmGlobalAddressSpace(resolved.@"addrspace", zcu.getTarget()),3264 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
3263 );3265 );
3264 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;3266 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
32653267
...@@ -4528,20 +4530,10 @@ pub const Object = struct {...@@ -4528,20 +4530,10 @@ pub const Object = struct {
4528 const zcu = pt.zcu;4530 const zcu = pt.zcu;
4529 const ip = &zcu.intern_pool;4531 const ip = &zcu.intern_pool;
45304532
4531 // In the case of something like:4533 const nav = ip.getNav(nav_index);
4532 // fn foo() void {}
4533 // const bar = foo;
4534 // ... &bar;
4535 // `bar` is just an alias and we actually want to lower a reference to `foo`.
4536 const owner_nav_index = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
4537 .func => |func| func.owner_nav,
4538 .@"extern" => |@"extern"| @"extern".owner_nav,
4539 else => nav_index,
4540 };
4541 const owner_nav = ip.getNav(owner_nav_index);
45424534
4543 const nav_ty = Type.fromInterned(owner_nav.typeOf(ip));4535 const nav_ty = Type.fromInterned(nav.typeOf(ip));
4544 const ptr_ty = try pt.navPtrType(owner_nav_index);4536 const ptr_ty = try pt.navPtrType(nav_index);
45454537
4546 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";4538 const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
4547 if ((!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) or4539 if ((!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) or
...@@ -4551,13 +4543,13 @@ pub const Object = struct {...@@ -4551,13 +4543,13 @@ pub const Object = struct {
4551 }4543 }
45524544
4553 const llvm_global = if (is_fn_body)4545 const llvm_global = if (is_fn_body)
4554 (try o.resolveLlvmFunction(owner_nav_index)).ptrConst(&o.builder).global4546 (try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global
4555 else4547 else
4556 (try o.resolveGlobalNav(owner_nav_index)).ptrConst(&o.builder).global;4548 (try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global;
45574549
4558 const llvm_val = try o.builder.convConst(4550 const llvm_val = try o.builder.convConst(
4559 llvm_global.toConst(),4551 llvm_global.toConst(),
4560 try o.builder.ptrType(toLlvmAddressSpace(owner_nav.status.resolved.@"addrspace", zcu.getTarget())),4552 try o.builder.ptrType(toLlvmAddressSpace(nav.getAddrspace(), zcu.getTarget())),
4561 );4553 );
45624554
4563 return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty));4555 return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty));
...@@ -4799,7 +4791,7 @@ pub const NavGen = struct {...@@ -4799,7 +4791,7 @@ pub const NavGen = struct {
4799 const ip = &zcu.intern_pool;4791 const ip = &zcu.intern_pool;
4800 const nav_index = ng.nav_index;4792 const nav_index = ng.nav_index;
4801 const nav = ip.getNav(nav_index);4793 const nav = ip.getNav(nav_index);
4802 const resolved = nav.status.resolved;4794 const resolved = nav.status.fully_resolved;
48034795
4804 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)) {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)) {
4805 .variable => |variable| .{ false, .none, 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 },
...@@ -5765,7 +5757,7 @@ pub const FuncGen = struct {...@@ -5765,7 +5757,7 @@ pub const FuncGen = struct {
5765 const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?;5757 const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?;
5766 const msg_nav = ip.getNav(msg_nav_index);5758 const msg_nav = ip.getNav(msg_nav_index);
5767 const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu);5759 const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu);
5768 const msg_ptr = try o.lowerValue(msg_nav.status.resolved.val);5760 const msg_ptr = try o.lowerValue(msg_nav.status.fully_resolved.val);
5769 const null_opt_addr_global = try fg.resolveNullOptUsize();5761 const null_opt_addr_global = try fg.resolveNullOptUsize();
5770 const target = zcu.getTarget();5762 const target = zcu.getTarget();
5771 const llvm_usize = try o.lowerType(Type.usize);5763 const llvm_usize = try o.lowerType(Type.usize);
src/codegen/spirv.zig+16-13
...@@ -268,7 +268,7 @@ pub const Object = struct {...@@ -268,7 +268,7 @@ pub const Object = struct {
268 // TODO: Extern fn?268 // TODO: Extern fn?
269 const kind: SpvModule.Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip)))269 const kind: SpvModule.Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip)))
270 .func270 .func
271 else switch (nav.status.resolved.@"addrspace") {271 else switch (nav.getAddrspace()) {
272 .generic => .invocation_global,272 .generic => .invocation_global,
273 else => .global,273 else => .global,
274 };274 };
...@@ -1279,17 +1279,20 @@ const NavGen = struct {...@@ -1279,17 +1279,20 @@ const NavGen = struct {
1279 const ip = &zcu.intern_pool;1279 const ip = &zcu.intern_pool;
1280 const ty_id = try self.resolveType(ty, .direct);1280 const ty_id = try self.resolveType(ty, .direct);
1281 const nav = ip.getNav(nav_index);1281 const nav = ip.getNav(nav_index);
1282 const nav_val = zcu.navValue(nav_index);1282 const nav_ty: Type = .fromInterned(nav.typeOf(ip));
1283 const nav_ty = nav_val.typeOf(zcu);1283
12841284 switch (nav.status) {
1285 switch (ip.indexToKey(nav_val.toIntern())) {1285 .unresolved => unreachable,
1286 .func => {1286 .type_resolved => {}, // this is not a function or extern
1287 // TODO: Properly lower function pointers. For now we are going to hack around it and1287 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
1288 // just generate an empty pointer. Function pointers are represented by a pointer to usize.1288 .func => {
1289 return try self.spv.constUndef(ty_id);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 }
12941297
1295 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {1298 if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
...@@ -1305,7 +1308,7 @@ const NavGen = struct {...@@ -1305,7 +1308,7 @@ const NavGen = struct {
1305 .global, .invocation_global => spv_decl.result_id,1308 .global, .invocation_global => spv_decl.result_id,
1306 };1309 };
13071310
1308 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");1311 const storage_class = self.spvStorageClass(nav.getAddrspace());
1309 try self.addFunctionDep(spv_decl_index, storage_class);1312 try self.addFunctionDep(spv_decl_index, storage_class);
13101313
1311 const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class);1314 const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class);
...@@ -3182,7 +3185,7 @@ const NavGen = struct {...@@ -3182,7 +3185,7 @@ const NavGen = struct {
3182 };3185 };
3183 assert(maybe_init_val == null); // TODO3186 assert(maybe_init_val == null); // TODO
31843187
3185 const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");3188 const storage_class = self.spvStorageClass(nav.getAddrspace());
3186 assert(storage_class != .Generic); // These should be instance globals3189 assert(storage_class != .Generic); // These should be instance globals
31873190
3188 const ptr_ty_id = try self.ptrType(ty, storage_class);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,7 +692,7 @@ pub const File = struct {
692 /// May be called before or after updateExports for any given Nav.692 /// May be called before or after updateExports for any given Nav.
693 pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {693 pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
694 const nav = pt.zcu.intern_pool.getNav(nav_index);694 const nav = pt.zcu.intern_pool.getNav(nav_index);
695 assert(nav.status == .resolved);695 assert(nav.status == .fully_resolved);
696 switch (base.tag) {696 switch (base.tag) {
697 inline else => |tag| {697 inline else => |tag| {
698 dev.check(tag.devFeature());698 dev.check(tag.devFeature());
src/link/C.zig+9-11
...@@ -217,7 +217,7 @@ pub fn updateFunc(...@@ -217,7 +217,7 @@ pub fn updateFunc(
217 .mod = zcu.navFileScope(func.owner_nav).mod,217 .mod = zcu.navFileScope(func.owner_nav).mod,
218 .error_msg = null,218 .error_msg = null,
219 .pass = .{ .nav = func.owner_nav },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 .fwd_decl = fwd_decl.toManaged(gpa),221 .fwd_decl = fwd_decl.toManaged(gpa),
222 .ctype_pool = ctype_pool.*,222 .ctype_pool = ctype_pool.*,
223 .scratch = .{},223 .scratch = .{},
...@@ -320,11 +320,11 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !...@@ -320,11 +320,11 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !
320 const ip = &zcu.intern_pool;320 const ip = &zcu.intern_pool;
321321
322 const nav = ip.getNav(nav_index);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 .func => return,324 .func => return,
325 .@"extern" => .none,325 .@"extern" => .none,
326 .variable => |variable| variable.init,326 .variable => |variable| variable.init,
327 else => nav.status.resolved.val,327 else => nav.status.fully_resolved.val,
328 };328 };
329 if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) return;329 if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) return;
330330
...@@ -499,7 +499,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -499,7 +499,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
499 av_block,499 av_block,
500 self.exported_navs.getPtr(nav),500 self.exported_navs.getPtr(nav),
501 export_names,501 export_names,
502 if (ip.indexToKey(zcu.navValue(nav).toIntern()) == .@"extern")502 if (ip.getNav(nav).getExtern(ip) != null)
503 ip.getNav(nav).name.toOptional()503 ip.getNav(nav).name.toOptional()
504 else504 else
505 .none,505 .none,
...@@ -544,13 +544,11 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:...@@ -544,13 +544,11 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
544 },544 },
545 self.getString(av_block.code),545 self.getString(av_block.code),
546 );546 );
547 for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(547 for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(storage: {
548 if (self.exported_navs.contains(nav)) .default else switch (ip.indexToKey(zcu.navValue(nav).toIntern())) {548 if (self.exported_navs.contains(nav)) break :storage .default;
549 .@"extern" => .zig_extern,549 if (ip.getNav(nav).getExtern(ip) != null) break :storage .zig_extern;
550 else => .static,550 break :storage .static;
551 },551 }, self.getString(av_block.code));
552 self.getString(av_block.code),
553 );
554552
555 const file = self.base.file.?;553 const file = self.base.file.?;
556 try file.setEndPos(f.file_size);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,6 +1110,8 @@ pub fn updateFunc(coff: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
1110 const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav);1110 const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav);
1111 coff.freeRelocations(atom_index);1111 coff.freeRelocations(atom_index);
11121112
1113 coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?;
1114
1113 var code_buffer = std.ArrayList(u8).init(gpa);1115 var code_buffer = std.ArrayList(u8).init(gpa);
1114 defer code_buffer.deinit();1116 defer code_buffer.deinit();
11151117
...@@ -1223,6 +1225,8 @@ pub fn updateNav(...@@ -1223,6 +1225,8 @@ pub fn updateNav(
1223 coff.freeRelocations(atom_index);1225 coff.freeRelocations(atom_index);
1224 const atom = coff.getAtom(atom_index);1226 const atom = coff.getAtom(atom_index);
12251227
1228 coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index);
1229
1226 var code_buffer = std.ArrayList(u8).init(gpa);1230 var code_buffer = std.ArrayList(u8).init(gpa);
1227 defer code_buffer.deinit();1231 defer code_buffer.deinit();
12281232
...@@ -1342,7 +1346,8 @@ pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom...@@ -1342,7 +1346,8 @@ pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom
1342 if (!gop.found_existing) {1346 if (!gop.found_existing) {
1343 gop.value_ptr.* = .{1347 gop.value_ptr.* = .{
1344 .atom = try coff.createAtom(),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 .exports = .{},1351 .exports = .{},
1347 };1352 };
1348 }1353 }
...@@ -1355,7 +1360,7 @@ fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 {...@@ -1355,7 +1360,7 @@ fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 {
1355 const nav = ip.getNav(nav_index);1360 const nav = ip.getNav(nav_index);
1356 const ty = Type.fromInterned(nav.typeOf(ip));1361 const ty = Type.fromInterned(nav.typeOf(ip));
1357 const zig_ty = ty.zigTypeTag(zcu);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 const index: u16 = blk: {1364 const index: u16 = blk: {
1360 if (val.isUndefDeep(zcu)) {1365 if (val.isUndefDeep(zcu)) {
1361 // TODO in release-fast and release-small, we should put undef in .bss1366 // TODO in release-fast and release-small, we should put undef in .bss
...@@ -2348,10 +2353,10 @@ pub fn getNavVAddr(...@@ -2348,10 +2353,10 @@ pub fn getNavVAddr(
2348 const ip = &zcu.intern_pool;2353 const ip = &zcu.intern_pool;
2349 const nav = ip.getNav(nav_index);2354 const nav = ip.getNav(nav_index);
2350 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });2355 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
2351 const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {2356 const sym_index = if (nav.getExtern(ip)) |e|
2352 .@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),2357 try coff.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip))
2353 else => coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,2358 else
2354 };2359 coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?;
2355 const atom_index = coff.getAtomIndexForSymbol(.{2360 const atom_index = coff.getAtomIndexForSymbol(.{
2356 .sym_index = reloc_info.parent.atom_index,2361 .sym_index = reloc_info.parent.atom_index,
2357 .file = null,2362 .file = null,
src/link/Dwarf.zig+5-5
...@@ -2281,7 +2281,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In...@@ -2281,7 +2281,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
2281 const nav_ty = nav_val.typeOf(zcu);2281 const nav_ty = nav_val.typeOf(zcu);
2282 const nav_ty_reloc_index = try wip_nav.refForward();2282 const nav_ty_reloc_index = try wip_nav.refForward();
2283 try wip_nav.infoExprloc(.{ .addr = .{ .sym = sym_index } });2283 try wip_nav.infoExprloc(.{ .addr = .{ .sym = sym_index } });
2284 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse2284 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
2285 nav_ty.abiAlignment(zcu).toByteUnits().?);2285 nav_ty.abiAlignment(zcu).toByteUnits().?);
2286 try diw.writeByte(@intFromBool(false));2286 try diw.writeByte(@intFromBool(false));
2287 wip_nav.finishForward(nav_ty_reloc_index);2287 wip_nav.finishForward(nav_ty_reloc_index);
...@@ -2313,7 +2313,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In...@@ -2313,7 +2313,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
2313 try wip_nav.refType(ty);2313 try wip_nav.refType(ty);
2314 const addr: Loc = .{ .addr = .{ .sym = sym_index } };2314 const addr: Loc = .{ .addr = .{ .sym = sym_index } };
2315 try wip_nav.infoExprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);2315 try wip_nav.infoExprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
2316 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse2316 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
2317 ty.abiAlignment(zcu).toByteUnits().?);2317 ty.abiAlignment(zcu).toByteUnits().?);
2318 try diw.writeByte(@intFromBool(false));2318 try diw.writeByte(@intFromBool(false));
2319 },2319 },
...@@ -2388,7 +2388,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In...@@ -2388,7 +2388,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
2388 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);2388 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
2389 try diw.writeInt(u32, 0, dwarf.endian);2389 try diw.writeInt(u32, 0, dwarf.endian);
2390 const target = file.mod.resolved_target.result;2390 const target = file.mod.resolved_target.result;
2391 try uleb128(diw, switch (nav.status.resolved.alignment) {2391 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
2392 .none => target_info.defaultFunctionAlignment(target),2392 .none => target_info.defaultFunctionAlignment(target),
2393 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),2393 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
2394 }.toByteUnits().?);2394 }.toByteUnits().?);
...@@ -2952,7 +2952,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool...@@ -2952,7 +2952,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
2952 const nav_ty = nav_val.typeOf(zcu);2952 const nav_ty = nav_val.typeOf(zcu);
2953 try wip_nav.refType(nav_ty);2953 try wip_nav.refType(nav_ty);
2954 try wip_nav.blockValue(nav_src_loc, nav_val);2954 try wip_nav.blockValue(nav_src_loc, nav_val);
2955 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse2955 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
2956 nav_ty.abiAlignment(zcu).toByteUnits().?);2956 nav_ty.abiAlignment(zcu).toByteUnits().?);
2957 try diw.writeByte(@intFromBool(false));2957 try diw.writeByte(@intFromBool(false));
2958 },2958 },
...@@ -2977,7 +2977,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool...@@ -2977,7 +2977,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
2977 try wip_nav.strp(nav.name.toSlice(ip));2977 try wip_nav.strp(nav.name.toSlice(ip));
2978 try wip_nav.strp(nav.fqn.toSlice(ip));2978 try wip_nav.strp(nav.fqn.toSlice(ip));
2979 const nav_ty_reloc_index = try wip_nav.refForward();2979 const nav_ty_reloc_index = try wip_nav.refForward();
2980 try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse2980 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
2981 nav_ty.abiAlignment(zcu).toByteUnits().?);2981 nav_ty.abiAlignment(zcu).toByteUnits().?);
2982 try diw.writeByte(@intFromBool(false));2982 try diw.writeByte(@intFromBool(false));
2983 if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val);2983 if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val);
src/link/Elf/ZigObject.zig+10-15
...@@ -925,14 +925,11 @@ pub fn getNavVAddr(...@@ -925,14 +925,11 @@ pub fn getNavVAddr(
925 const ip = &zcu.intern_pool;925 const ip = &zcu.intern_pool;
926 const nav = ip.getNav(nav_index);926 const nav = ip.getNav(nav_index);
927 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });927 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
928 const this_sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {928 const this_sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
929 .@"extern" => |@"extern"| try self.getGlobalSymbol(929 elf_file,
930 elf_file,930 nav.name.toSlice(ip),
931 nav.name.toSlice(ip),931 @"extern".lib_name.toSlice(ip),
932 @"extern".lib_name.toSlice(ip),932 ) else try self.getOrCreateMetadataForNav(zcu, nav_index);
933 ),
934 else => try self.getOrCreateMetadataForNav(zcu, nav_index),
935 };
936 const this_sym = self.symbol(this_sym_index);933 const this_sym = self.symbol(this_sym_index);
937 const vaddr = this_sym.address(.{}, elf_file);934 const vaddr = this_sym.address(.{}, elf_file);
938 switch (reloc_info.parent) {935 switch (reloc_info.parent) {
...@@ -1107,15 +1104,13 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index...@@ -1107,15 +1104,13 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index
11071104
1108pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {1105pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
1109 const gpa = zcu.gpa;1106 const gpa = zcu.gpa;
1107 const ip = &zcu.intern_pool;
1110 const gop = try self.navs.getOrPut(gpa, nav_index);1108 const gop = try self.navs.getOrPut(gpa, nav_index);
1111 if (!gop.found_existing) {1109 if (!gop.found_existing) {
1112 const symbol_index = try self.newSymbolWithAtom(gpa, 0);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 const sym = self.symbol(symbol_index);1111 const sym = self.symbol(symbol_index);
1115 if (nav_val.getVariable(zcu)) |variable| {1112 if (ip.getNav(nav_index).isThreadlocal(ip) and zcu.comp.config.any_non_single_threaded) {
1116 if (variable.is_threadlocal and zcu.comp.config.any_non_single_threaded) {1113 sym.flags.is_tls = true;
1117 sym.flags.is_tls = true;
1118 }
1119 }1114 }
1120 gop.value_ptr.* = .{ .symbol_index = symbol_index };1115 gop.value_ptr.* = .{ .symbol_index = symbol_index };
1121 }1116 }
...@@ -1547,7 +1542,7 @@ pub fn updateNav(...@@ -1547,7 +1542,7 @@ pub fn updateNav(
15471542
1548 log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });1543 log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
15491544
1550 const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {1545 const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
1551 .func => .none,1546 .func => .none,
1552 .variable => |variable| variable.init,1547 .variable => |variable| variable.init,
1553 .@"extern" => |@"extern"| {1548 .@"extern" => |@"extern"| {
...@@ -1560,7 +1555,7 @@ pub fn updateNav(...@@ -1560,7 +1555,7 @@ pub fn updateNav(
1560 self.symbol(sym_index).flags.is_extern_ptr = true;1555 self.symbol(sym_index).flags.is_extern_ptr = true;
1561 return;1556 return;
1562 },1557 },
1563 else => nav.status.resolved.val,1558 else => nav.status.fully_resolved.val,
1564 };1559 };
15651560
1566 if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {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,14 +608,11 @@ pub fn getNavVAddr(
608 const ip = &zcu.intern_pool;608 const ip = &zcu.intern_pool;
609 const nav = ip.getNav(nav_index);609 const nav = ip.getNav(nav_index);
610 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });610 log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
611 const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {611 const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
612 .@"extern" => |@"extern"| try self.getGlobalSymbol(612 macho_file,
613 macho_file,613 nav.name.toSlice(ip),
614 nav.name.toSlice(ip),614 @"extern".lib_name.toSlice(ip),
615 @"extern".lib_name.toSlice(ip),615 ) else try self.getOrCreateMetadataForNav(macho_file, nav_index);
616 ),
617 else => try self.getOrCreateMetadataForNav(macho_file, nav_index),
618 };
619 const sym = self.symbols.items[sym_index];616 const sym = self.symbols.items[sym_index];
620 const vaddr = sym.getAddress(.{}, macho_file);617 const vaddr = sym.getAddress(.{}, macho_file);
621 switch (reloc_info.parent) {618 switch (reloc_info.parent) {
...@@ -882,7 +879,7 @@ pub fn updateNav(...@@ -882,7 +879,7 @@ pub fn updateNav(
882 const ip = &zcu.intern_pool;879 const ip = &zcu.intern_pool;
883 const nav = ip.getNav(nav_index);880 const nav = ip.getNav(nav_index);
884881
885 const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {882 const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
886 .func => .none,883 .func => .none,
887 .variable => |variable| variable.init,884 .variable => |variable| variable.init,
888 .@"extern" => |@"extern"| {885 .@"extern" => |@"extern"| {
...@@ -895,7 +892,7 @@ pub fn updateNav(...@@ -895,7 +892,7 @@ pub fn updateNav(
895 sym.flags.is_extern_ptr = true;892 sym.flags.is_extern_ptr = true;
896 return;893 return;
897 },894 },
898 else => nav.status.resolved.val,895 else => nav.status.fully_resolved.val,
899 };896 };
900897
901 if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {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,11 +1558,7 @@ fn isThreadlocal(macho_file: *MachO, nav_index: InternPool.Nav.Index) bool {
1561 if (!macho_file.base.comp.config.any_non_single_threaded)1558 if (!macho_file.base.comp.config.any_non_single_threaded)
1562 return false;1559 return false;
1563 const ip = &macho_file.base.comp.zcu.?.intern_pool;1560 const ip = &macho_file.base.comp.zcu.?.intern_pool;
1564 return switch (ip.indexToKey(ip.getNav(nav_index).status.resolved.val)) {1561 return ip.getNav(nav_index).isThreadlocal(ip);
1565 .variable => |variable| variable.is_threadlocal,
1566 .@"extern" => |@"extern"| @"extern".is_threadlocal,
1567 else => false,
1568 };
1569}1562}
15701563
1571fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {1564fn 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,7 +1021,7 @@ pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
1021 const atom_idx = gop.value_ptr.index;1021 const atom_idx = gop.value_ptr.index;
1022 // handle externs here because they might not get updateDecl called on them1022 // handle externs here because they might not get updateDecl called on them
1023 const nav = ip.getNav(nav_index);1023 const nav = ip.getNav(nav_index);
1024 if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {1024 if (nav.getExtern(ip) != null) {
1025 // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs1025 // this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs
1026 if (nav.name.eqlSlice("etext", ip)) {1026 if (nav.name.eqlSlice("etext", ip)) {
1027 self.etext_edata_end_atom_indices[0] = atom_idx;1027 self.etext_edata_end_atom_indices[0] = atom_idx;
...@@ -1370,7 +1370,7 @@ pub fn getNavVAddr(...@@ -1370,7 +1370,7 @@ pub fn getNavVAddr(
1370 const ip = &pt.zcu.intern_pool;1370 const ip = &pt.zcu.intern_pool;
1371 const nav = ip.getNav(nav_index);1371 const nav = ip.getNav(nav_index);
1372 log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)});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 if (nav.name.eqlSlice("etext", ip)) {1374 if (nav.name.eqlSlice("etext", ip)) {
1375 try self.addReloc(reloc_info.parent.atom_index, .{1375 try self.addReloc(reloc_info.parent.atom_index, .{
1376 .target = undefined,1376 .target = undefined,
src/link/Wasm/ZigObject.zig+6-7
...@@ -734,15 +734,14 @@ pub fn getNavVAddr(...@@ -734,15 +734,14 @@ pub fn getNavVAddr(
734 const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);734 const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
735 const target_atom = wasm.getAtom(target_atom_index);735 const target_atom = wasm.getAtom(target_atom_index);
736 const target_symbol_index = @intFromEnum(target_atom.sym_index);736 const target_symbol_index = @intFromEnum(target_atom.sym_index);
737 switch (ip.indexToKey(nav.status.resolved.val)) {737 if (nav.getExtern(ip)) |@"extern"| {
738 .@"extern" => |@"extern"| try zig_object.addOrUpdateImport(738 try zig_object.addOrUpdateImport(
739 wasm,739 wasm,
740 nav.name.toSlice(ip),740 nav.name.toSlice(ip),
741 target_atom.sym_index,741 target_atom.sym_index,
742 @"extern".lib_name.toSlice(ip),742 @"extern".lib_name.toSlice(ip),
743 null,743 null,
744 ),744 );
745 else => {},
746 }745 }
747746
748 std.debug.assert(reloc_info.parent.atom_index != 0);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,8 +944,8 @@ pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.In
945 segment.name = &.{}; // Ensure no accidental double free944 segment.name = &.{}; // Ensure no accidental double free
946 }945 }
947946
948 const nav_val = zcu.navValue(nav_index).toIntern();947 const nav = ip.getNav(nav_index);
949 if (ip.indexToKey(nav_val) == .@"extern") {948 if (nav.getExtern(ip) != null) {
950 std.debug.assert(zig_object.imports.remove(atom.sym_index));949 std.debug.assert(zig_object.imports.remove(atom.sym_index));
951 }950 }
952 std.debug.assert(wasm.symbol_atom.remove(atom.symbolLoc()));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,7 +959,7 @@ pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.In
960 if (sym.isGlobal()) {959 if (sym.isGlobal()) {
961 std.debug.assert(zig_object.global_syms.remove(atom.sym_index));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 zig_object.functions_free_list.append(gpa, sym.index) catch {};963 zig_object.functions_free_list.append(gpa, sym.index) catch {};
965 std.debug.assert(zig_object.atom_types.remove(atom_index));964 std.debug.assert(zig_object.atom_types.remove(atom_index));
966 } else {965 } else {
test/behavior/globals.zig+96
...@@ -66,3 +66,99 @@ test "global loads can affect liveness" {...@@ -66,3 +66,99 @@ test "global loads can affect liveness" {
66 S.f();66 S.f();
67 try std.testing.expect(y.a == 1);67 try std.testing.expect(y.a == 1);
68}68}
69
70test "global const can be self-referential" {
71 const S = struct {
72 self: *const @This(),
73 x: u32,
74
75 const foo: @This() = .{ .self = &foo, .x = 123 };
76 };
77
78 try std.testing.expect(S.foo.x == 123);
79 try std.testing.expect(S.foo.self.x == 123);
80 try std.testing.expect(S.foo.self.self.x == 123);
81 try std.testing.expect(S.foo.self == &S.foo);
82 try std.testing.expect(S.foo.self.self == &S.foo);
83}
84
85test "global var can be self-referential" {
86 const S = struct {
87 self: *@This(),
88 x: u32,
89
90 var foo: @This() = .{ .self = &foo, .x = undefined };
91 };
92
93 S.foo.x = 123;
94
95 try std.testing.expect(S.foo.x == 123);
96 try std.testing.expect(S.foo.self.x == 123);
97 try std.testing.expect(S.foo.self == &S.foo);
98
99 S.foo.self.x = 456;
100
101 try std.testing.expect(S.foo.x == 456);
102 try std.testing.expect(S.foo.self.x == 456);
103 try std.testing.expect(S.foo.self == &S.foo);
104
105 S.foo.self.self.x = 789;
106
107 try std.testing.expect(S.foo.x == 789);
108 try std.testing.expect(S.foo.self.x == 789);
109 try std.testing.expect(S.foo.self == &S.foo);
110}
111
112test "global const can be indirectly self-referential" {
113 const S = struct {
114 other: *const @This(),
115 x: u32,
116
117 const foo: @This() = .{ .other = &bar, .x = 123 };
118 const bar: @This() = .{ .other = &foo, .x = 456 };
119 };
120
121 try std.testing.expect(S.foo.x == 123);
122 try std.testing.expect(S.foo.other.x == 456);
123 try std.testing.expect(S.foo.other.other.x == 123);
124 try std.testing.expect(S.foo.other.other.other.x == 456);
125 try std.testing.expect(S.foo.other == &S.bar);
126 try std.testing.expect(S.foo.other.other == &S.foo);
127
128 try std.testing.expect(S.bar.x == 456);
129 try std.testing.expect(S.bar.other.x == 123);
130 try std.testing.expect(S.bar.other.other.x == 456);
131 try std.testing.expect(S.bar.other.other.other.x == 123);
132 try std.testing.expect(S.bar.other == &S.foo);
133 try std.testing.expect(S.bar.other.other == &S.bar);
134}
135
136test "global var can be indirectly self-referential" {
137 const S = struct {
138 other: *@This(),
139 x: u32,
140
141 var foo: @This() = .{ .other = &bar, .x = undefined };
142 var bar: @This() = .{ .other = &foo, .x = undefined };
143 };
144
145 S.foo.other.x = 123; // bar.x
146 S.foo.other.other.x = 456; // foo.x
147
148 try std.testing.expect(S.foo.x == 456);
149 try std.testing.expect(S.foo.other.x == 123);
150 try std.testing.expect(S.foo.other.other.x == 456);
151 try std.testing.expect(S.foo.other.other.other.x == 123);
152 try std.testing.expect(S.foo.other == &S.bar);
153 try std.testing.expect(S.foo.other.other == &S.foo);
154
155 S.bar.other.x = 111; // foo.x
156 S.bar.other.other.x = 222; // bar.x
157
158 try std.testing.expect(S.bar.x == 222);
159 try std.testing.expect(S.bar.other.x == 111);
160 try std.testing.expect(S.bar.other.other.x == 222);
161 try std.testing.expect(S.bar.other.other.other.x == 111);
162 try std.testing.expect(S.bar.other == &S.foo);
163 try std.testing.expect(S.bar.other.other == &S.bar);
164}
test/cases/compile_errors/self_reference_missing_const.zig created+11
...@@ -0,0 +1,11 @@
1const S = struct { self: *S, x: u32 };
2const s: S = .{ .self = &s, .x = 123 };
3
4comptime {
5 _ = s;
6}
7
8// error
9//
10// :2:18: error: expected type '*tmp.S', found '*const tmp.S'
11// :2:18: note: cast discards const qualifier