commit 5d215838a79a24c21842fbc76fd77aca4c28b162 (tree)
parent 065c6e7946e712dc8563c975a4ca951927145da7
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Sun, 15 Mar 2026 10:34:13 +0000
InternPool.Nav: fix race, refactor
I've realised that the cause of at least some of our weird CI flakiness
was a bug in how `Nav` values were resolved. Consider this scenario: the
frontend resolves the type of a `Nav`, and then sends a function to the
backend, which requires the backend to lower a pointer to that `Nav`.
The backend calls `InternPool.getNav` to determine the `Nav`'s type.
However, this races with the frontend resolving the *value* of that
`Nav`. This involves writing separately to two fields, `bits` and
`type_or_value`. If only one of these changes is observed, then the
backend will incorrectly interpret the type as the value or vice versa,
leading to a crash or even a miscompilation. (Of course, there's also
the straightforward issue that the racing loads were non-atomic, making
them illegal).
The only good solution to this was to make `Nav` 4 bytes bigger, giving
it separate `type` and `value` fields. In theory that's a quite small
change, but it ended up having a bunch of nice consequences which led to
this diff being a bit bulkier than expected:
* `Nav.Repr.Bits` was simplified, because it no longer has to track
"resolution status": we can use `.none` for that. This frees up some
bits to make things more consistent between the "type resolved" and
"fully resolved" states.
* This consistency allowed the `Nav.status` union to be replaced with a
simpler field `Nav.resolved`, which is a bit nicer to work with.
* Most of the "getter" functions were able to be removed from `Nav`
because the state they were fetching had been moved to simple fields
on `Nav.resolved`.
* There were still a handful of free bits in `Nav.Repr.Bits`, which
could be used to represent the "const" and "threadlocal" flags rather
than these being stored on `Key.Extern` and `Key.Variable`. This is a
bit more convenient for linkers.
* With those bits gone, `Key.Variable` is a trivial wrapper around a
type and an initial value, and the fact that a declaration is mutable
can be represented solely through the "const" flag. Therefore,
`Key.Variable` no longer served a purpose, and could be eliminated
entirely in favour of storing the variable's initial value directly in
the "value" field of the `Nav`.
So, I'm quite pleased with this refactor! But anyway, regarding the bug
fix which actually motivated this: if I've done my job correctly, this
should solve some crashes, such as these (which were what tipped me off
to this bug in the first place):
https://codeberg.org/ziglang/zig/actions/runs/2306/jobs/7/attempt/1
https://codeberg.org/ziglang/zig/actions/runs/2173/jobs/6/attempt/1
...and, who knows, perhaps even the random SIGSEGVs we've seen on some
targets! Probably not, but one can hope.
Diffstat:
33 files changed, 593 insertions(+), 965 deletions(-)
diff --git a/src/IncrementalDebugServer.zig b/src/IncrementalDebugServer.zig
@@ -215,22 +215,25 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
try w.print(
\\name: '{f}'
\\fqn: '{f}'
- \\status: {s}
\\created on generation: {d}
\\
, .{
nav.name.fmt(ip),
nav.fqn.fmt(ip),
- @tagName(nav.status),
create_gen,
});
- switch (nav.status) {
- .unresolved => {},
- .type_resolved, .fully_resolved => {
- try w.writeAll("type: ");
- try printType(.fromInterned(nav.typeOf(ip)), zcu, w);
- try w.writeByte('\n');
- },
+ if (nav.resolved) |r| {
+ try w.writeAll("status: resolved\n type: ");
+ try printType(.fromInterned(r.type), zcu, w);
+ try w.writeAll("\n value: ");
+ if (r.value == .none) {
+ try w.writeAll("(unresolved)");
+ } else {
+ try printType(.fromInterned(r.type), zcu, w);
+ }
+ try w.writeByte('\n');
+ } else {
+ try w.writeAll("status: unresolved\n");
}
} else if (std.mem.eql(u8, cmd_str, "find_type")) {
if (arg_str.len == 0) return w.writeAll("bad usage");
diff --git a/src/InternPool.zig b/src/InternPool.zig
@@ -548,144 +548,61 @@ pub const Nav = struct {
/// The fully-qualified name of this `Nav`.
fqn: NullTerminatedString,
/// This field is populated iff this `Nav` is resolved by semantic analysis.
- /// If this is `null`, then `status == .fully_resolved` always.
+ /// If this is `null`, then `resolved` is *not* `null`.
analysis: ?struct {
namespace: NamespaceIndex,
zir_index: TrackedInst.Index,
/// Initially `false`. Set to `true` by `setWantNavAnalysis`.
wanted: bool,
},
- status: union(enum) {
- /// This `Nav` is pending semantic analysis.
- unresolved,
- /// The type of this `Nav` is resolved; the value is queued for resolution.
- type_resolved: struct {
- type: InternPool.Index,
- is_const: bool,
- alignment: Alignment,
- @"linksection": OptionalNullTerminatedString,
- @"addrspace": std.builtin.AddressSpace,
- is_threadlocal: bool,
- /// This field is whether this `Nav` is a literal `extern` definition.
- /// It does *not* tell you whether this might alias an extern fn (see #21027).
- is_extern_decl: bool,
- },
- /// The value of this `Nav` is resolved.
- fully_resolved: struct {
- val: InternPool.Index,
- is_const: bool,
- alignment: Alignment,
- @"linksection": OptionalNullTerminatedString,
- @"addrspace": std.builtin.AddressSpace,
- },
- },
-
- /// Asserts that `status != .unresolved`.
- pub fn typeOf(nav: Nav, ip: *const InternPool) InternPool.Index {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| r.type,
- .fully_resolved => |r| ip.typeOf(r.val),
- };
- }
-
- /// This function is intended to be used by code generation, since semantic
- /// analysis will ensure that any `Nav` which is potentially `extern` is
- /// fully resolved.
- /// Asserts that `status == .fully_resolved`.
- pub fn getResolvedExtern(nav: Nav, ip: *const InternPool) ?Key.Extern {
- assert(nav.status == .fully_resolved);
- return nav.getExtern(ip);
- }
-
- /// Always returns `null` for `status == .type_resolved`. This function is inteded
- /// to be used by code generation, since semantic analysis will ensure that any `Nav`
- /// which is potentially `extern` is fully resolved.
- /// Asserts that `status != .unresolved`.
+ /// If this is `null`, then `analysis` is *not* `null`, and semantic analysis is required to
+ /// resolve the type and value of this `Nav`. Otherwise, the type is resolved---therefore,
+ /// `Nav.resolved.?.type` is never `.none`. However, the *value* may not be resolved yet even
+ /// if this field is not `null`---see `Resolved.value` for details.
+ resolved: ?Resolved,
+
+ pub const Resolved = struct {
+ /// This is never `.none`
+ type: InternPool.Index,
+ @"align": Alignment,
+ @"linksection": OptionalNullTerminatedString,
+ @"addrspace": std.builtin.AddressSpace,
+ @"const": bool,
+ @"threadlocal": bool,
+ /// This field is whether this `Nav` is a literal `extern` definition.
+ /// It does *not* tell you whether this might alias an extern fn (see #21027).
+ is_extern_decl: bool,
+ /// If the type is resolved but not the value, this is `.none`. In that case, the value will
+ /// be resolved by semantic analysis, so `Nav.analysis` is definitely not `null`.
+ ///
+ /// If this is an extern, the special key `Key.@"extern"` is used.
+ ///
+ /// If this is a variable (`Resolved.@"const" == false`) and not an extern, then this value
+ /// is the global variable's initializer; the value loaded from the variable at runtime may
+ /// of course be different.
+ value: InternPool.Index,
+ };
+
+ /// If the value of this `Nav` is resolved and is an extern, returns the `Key.Extern`. If the
+ /// value is *not* an extern, *or* if the value is not yet resolved (only the type is), returns
+ /// `null`.
+ ///
+ /// This logic works because the frontend ensures that if a `Nav` *might* be extern, its value
+ /// is resolved more eagerly (see logic in `Sema.analyzeNavRefInner`). Therefore, if we see that
+ /// the value is not yet resolved, we know the frontend determined that the `Nav` is definitely
+ /// *not* extern.
+ ///
+ /// This function is only intended be used by the compiler backend (codegen/link). The guarantee
+ /// mentioned above does not necessarily hold in the compiler frontend (if we haven't reached
+ /// `Sema.analyzeNavRefInner` yet).
+ ///
+ /// Asserts that `nav.resolved != null`.
pub fn getExtern(nav: Nav, ip: *const InternPool) ?Key.Extern {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => null,
- .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
- .@"extern" => |e| e,
- else => null,
- },
- };
- }
-
- /// Asserts that `status != .unresolved`.
- pub fn getAddrspace(nav: Nav) std.builtin.AddressSpace {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| r.@"addrspace",
- .fully_resolved => |r| r.@"addrspace",
- };
- }
-
- /// Asserts that `status != .unresolved`.
- pub fn getAlignment(nav: Nav) Alignment {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| r.alignment,
- .fully_resolved => |r| r.alignment,
- };
- }
-
- /// Asserts that `status != .unresolved`.
- pub fn getLinkSection(nav: Nav) OptionalNullTerminatedString {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| r.@"linksection",
- .fully_resolved => |r| r.@"linksection",
- };
- }
-
- /// Asserts that `status != .unresolved`.
- pub fn isThreadlocal(nav: Nav, ip: *const InternPool) bool {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| r.is_threadlocal,
- .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
- .@"extern" => |e| e.is_threadlocal,
- .variable => |v| v.is_threadlocal,
- else => false,
- },
- };
- }
-
- pub fn isFn(nav: Nav, ip: *const InternPool) bool {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| {
- const tag = ip.zigTypeTag(r.type);
- return tag == .@"fn";
- },
- .fully_resolved => |r| {
- const tag = ip.zigTypeTag(ip.typeOf(r.val));
- return tag == .@"fn";
- },
- };
- }
-
- /// If this returns `true`, then a pointer to this `Nav` might actually be encoded as a pointer
- /// to some other `Nav` due to an extern definition or extern alias (see #21027).
- /// This query is valid on `Nav`s for whom only the type is resolved.
- /// Asserts that `status != .unresolved`.
- pub fn isExternOrFn(nav: Nav, ip: *const InternPool) bool {
- return switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => |r| {
- if (r.is_extern_decl) return true;
- const tag = ip.zigTypeTag(r.type);
- if (tag == .@"fn") return true;
- return false;
- },
- .fully_resolved => |r| {
- if (ip.indexToKey(r.val) == .@"extern") return true;
- const tag = ip.zigTypeTag(ip.typeOf(r.val));
- if (tag == .@"fn") return true;
- return false;
- },
+ const r = nav.resolved.?;
+ if (r.value == .none) return null;
+ return switch (ip.indexToKey(r.value)) {
+ .@"extern" => |e| e,
+ else => null,
};
}
@@ -696,7 +613,7 @@ pub const Nav = struct {
return a.zir_index;
}
// A `Nav` which does not undergo analysis always has a resolved value.
- return switch (ip.indexToKey(nav.status.fully_resolved.val)) {
+ return switch (ip.indexToKey(nav.resolved.?.value)) {
.func => |func| {
// Since `analysis` was not populated, this must be an instantiation.
// Go up to the generic owner and consult *its* `analysis` field.
@@ -747,30 +664,26 @@ pub const Nav = struct {
};
/// The compact in-memory representation of a `Nav`.
- /// 26 bytes.
+ /// 30 bytes.
const Repr = struct {
name: NullTerminatedString,
fqn: NullTerminatedString,
// The following 2 fields are either both populated, or both `.none`.
analysis_namespace: OptionalNamespaceIndex,
analysis_zir_index: TrackedInst.Index.Optional,
- /// Populated only if `bits.status != .unresolved`.
- type_or_val: InternPool.Index,
- /// Populated only if `bits.status != .unresolved`.
+ type: InternPool.Index,
+ value: InternPool.Index,
@"linksection": OptionalNullTerminatedString,
bits: Bits,
const Bits = packed struct(u16) {
- status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
- /// Populated only if `bits.status != .unresolved`.
- is_const: bool,
- /// Populated only if `bits.status != .unresolved`.
- alignment: Alignment,
- /// Populated only if `bits.status != .unresolved`.
+ @"align": Alignment,
@"addrspace": std.builtin.AddressSpace,
- /// Populated only if `bits.status == .type_resolved`.
- is_threadlocal: bool,
+ @"const": bool,
+ @"threadlocal": bool,
+ is_extern_decl: bool,
want_analysis: bool,
+ _: u1 = 0,
};
fn unpack(repr: Repr) Nav {
@@ -785,72 +698,46 @@ pub const Nav = struct {
assert(repr.analysis_zir_index == .none);
break :a null;
},
- .status = switch (repr.bits.status) {
- .unresolved => .unresolved,
- .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
- .type = repr.type_or_val,
- .is_const = repr.bits.is_const,
- .alignment = repr.bits.alignment,
- .@"linksection" = repr.@"linksection",
- .@"addrspace" = repr.bits.@"addrspace",
- .is_threadlocal = repr.bits.is_threadlocal,
- .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
- } },
- .fully_resolved => .{ .fully_resolved = .{
- .val = repr.type_or_val,
- .is_const = repr.bits.is_const,
- .alignment = repr.bits.alignment,
- .@"linksection" = repr.@"linksection",
- .@"addrspace" = repr.bits.@"addrspace",
- } },
+ .resolved = if (repr.type == .none) null else .{
+ .type = repr.type,
+ .@"align" = repr.bits.@"align",
+ .@"linksection" = repr.@"linksection",
+ .@"addrspace" = repr.bits.@"addrspace",
+ .@"const" = repr.bits.@"const",
+ .@"threadlocal" = repr.bits.@"threadlocal",
+ .is_extern_decl = repr.bits.is_extern_decl,
+ .value = repr.value,
},
};
}
};
fn pack(nav: Nav) Repr {
- // Note that in the `unresolved` case, we do not mark fields as `undefined`, even though they should not be used.
- // This is to avoid writing undefined bytes to disk when serializing buffers.
+ // Note that even if `nav.resolved == null`, we do not set any fields to `undefined`, even
+ // though they should not be used. This is to avoid writing undefined bytes to disk when
+ // serializing buffers.
return .{
.name = nav.name,
.fqn = nav.fqn,
.analysis_namespace = if (nav.analysis) |a| a.namespace.toOptional() else .none,
.analysis_zir_index = if (nav.analysis) |a| a.zir_index.toOptional() else .none,
- .type_or_val = switch (nav.status) {
- .unresolved => .none,
- .type_resolved => |r| r.type,
- .fully_resolved => |r| r.val,
- },
- .@"linksection" = switch (nav.status) {
- .unresolved => .none,
- .type_resolved => |r| r.@"linksection",
- .fully_resolved => |r| r.@"linksection",
- },
- .bits = switch (nav.status) {
- .unresolved => .{
- .status = .unresolved,
- .is_const = false,
- .alignment = .none,
- .@"addrspace" = .generic,
- .is_threadlocal = false,
- .want_analysis = if (nav.analysis) |a| a.wanted else false,
- },
- .type_resolved => |r| .{
- .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
- .is_const = r.is_const,
- .alignment = r.alignment,
- .@"addrspace" = r.@"addrspace",
- .is_threadlocal = r.is_threadlocal,
- .want_analysis = if (nav.analysis) |a| a.wanted else false,
- },
- .fully_resolved => |r| .{
- .status = .fully_resolved,
- .is_const = r.is_const,
- .alignment = r.alignment,
- .@"addrspace" = r.@"addrspace",
- .is_threadlocal = false,
- .want_analysis = if (nav.analysis) |a| a.wanted else false,
- },
+ .type = if (nav.resolved) |r| r.type else .none,
+ .value = if (nav.resolved) |r| r.value else .none,
+ .@"linksection" = if (nav.resolved) |r| r.@"linksection" else .none,
+ .bits = if (nav.resolved) |r| .{
+ .@"align" = r.@"align",
+ .@"addrspace" = r.@"addrspace",
+ .@"const" = r.@"const",
+ .@"threadlocal" = r.@"threadlocal",
+ .is_extern_decl = r.is_extern_decl,
+ .want_analysis = if (nav.analysis) |a| a.wanted else false,
+ } else .{
+ .@"align" = .none,
+ .@"addrspace" = .generic,
+ .@"const" = false,
+ .@"threadlocal" = false,
+ .is_extern_decl = false,
+ .want_analysis = if (nav.analysis) |a| a.wanted else false,
},
};
}
@@ -2110,7 +1997,6 @@ pub const Key = union(enum) {
/// via `simple_value` and has a named `Index` tag for it.
undef: Index,
simple_value: SimpleValue,
- variable: Variable,
@"extern": Extern,
func: Func,
int: Key.Int,
@@ -2311,14 +2197,6 @@ pub const Key = union(enum) {
}
};
- /// A runtime variable defined in this `Zcu`.
- pub const Variable = struct {
- ty: Index,
- init: Index,
- owner_nav: Nav.Index,
- is_threadlocal: bool,
- };
-
pub const Extern = struct {
/// The name of the extern symbol.
name: NullTerminatedString,
@@ -2543,7 +2421,7 @@ pub const Key = union(enum) {
pub const BaseAddr = union(enum) {
const Tag = @typeInfo(BaseAddr).@"union".tag_type.?;
- /// Points to the value of a single `Nav`, which may be constant or a `variable`.
+ /// Points to the value of a single `Nav`.
nav: Nav.Index,
/// Points to the value of a single comptime alloc stored in `Sema`.
@@ -2735,8 +2613,6 @@ pub const Key = union(enum) {
.payload => |y| Hash.hash(seed + 1, asBytes(&x.ty) ++ asBytes(&y)),
},
- .variable => |variable| Hash.hash(seed, asBytes(&variable.owner_nav)),
-
.opaque_type,
.enum_type,
.union_type,
@@ -3011,13 +2887,6 @@ pub const Key = union(enum) {
return a_info.ty == b_info.ty and a_info.backing_int_val == b_info.backing_int_val;
},
- .variable => |a_info| {
- const b_info = b.variable;
- return a_info.ty == b_info.ty and
- a_info.init == b_info.init and
- a_info.owner_nav == b_info.owner_nav and
- a_info.is_threadlocal == b_info.is_threadlocal;
- },
.@"extern" => |a_info| {
const b_info = b.@"extern";
return a_info.name == b_info.name and
@@ -3277,7 +3146,6 @@ pub const Key = union(enum) {
.int,
.float,
.opt,
- .variable,
.@"extern",
.func,
.err,
@@ -4390,8 +4258,6 @@ pub const Index = enum(u32) {
float_c_longdouble_f80: struct { data: *Float80 },
float_c_longdouble_f128: struct { data: *Float128 },
float_comptime_float: struct { data: *Float128 },
- variable: struct { data: *Tag.Variable },
- threadlocal_variable: struct { data: *Tag.Variable },
@"extern": struct { data: *Tag.Extern },
func_decl: struct {
const @"data.analysis.inferred_error_set" = opaque {};
@@ -5115,12 +4981,6 @@ pub const Tag = enum(u8) {
/// A comptime_float value.
/// data is extra index to Float128.
float_comptime_float,
- /// A global variable.
- /// data is extra index to Variable.
- variable,
- /// A global threadlocal variable.
- /// data is extra index to Variable.
- threadlocal_variable,
/// An extern function or variable.
/// data is extra index to Extern.
/// Some parts of the key are stored in `owner_nav`.
@@ -5457,8 +5317,6 @@ pub const Tag = enum(u8) {
.float_c_longdouble_f80 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f80 },
.float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
.float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
- .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
- .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
.@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
.func_decl = .{
.summary = .@"{.payload.owner_nav.fqn%summary#\"}",
@@ -5505,13 +5363,6 @@ pub const Tag = enum(u8) {
return @field(encodings, @tagName(tag)).payload;
}
- pub const Variable = struct {
- ty: Index,
- /// May be `none`.
- init: Index,
- owner_nav: Nav.Index,
- };
-
pub const Extern = struct {
// name, is_const, alignment, addrspace come from `owner_nav`.
ty: Index,
@@ -5525,12 +5376,11 @@ pub const Tag = enum(u8) {
pub const Flags = packed struct(u32) {
linkage: std.builtin.GlobalLinkage,
visibility: std.builtin.SymbolVisibility,
- is_threadlocal: bool,
is_dll_import: bool,
relocation: std.builtin.ExternOptions.Relocation,
source: Source,
decoration_type: DecorationType,
- _: u22 = 0,
+ _: u23 = 0,
pub const Source = enum(u1) { builtin, syntax };
pub const DecorationType = enum(u2) { none, location, descriptor };
@@ -6894,19 +6744,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.ty = .comptime_float_type,
.storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
} },
- .variable, .threadlocal_variable => {
- const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
- return .{ .variable = .{
- .ty = extra.ty,
- .init = extra.init,
- .owner_nav = extra.owner_nav,
- .is_threadlocal = switch (item.tag) {
- else => unreachable,
- .variable => false,
- .threadlocal_variable => true,
- },
- } };
- },
.@"extern" => {
const extra = extraData(unwrapped_index.getExtra(ip), Tag.Extern, data);
const nav = ip.getNav(extra.owner_nav);
@@ -6916,13 +6753,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.lib_name = extra.lib_name,
.linkage = extra.flags.linkage,
.visibility = extra.flags.visibility,
- .is_threadlocal = extra.flags.is_threadlocal,
+ .is_threadlocal = nav.resolved.?.@"threadlocal",
.is_dll_import = extra.flags.is_dll_import,
.relocation = extra.flags.relocation,
.decoration = extra.decoration(),
- .is_const = nav.status.fully_resolved.is_const,
- .alignment = nav.status.fully_resolved.alignment,
- .@"addrspace" = nav.status.fully_resolved.@"addrspace",
+ .is_const = nav.resolved.?.@"const",
+ .alignment = nav.resolved.?.@"align",
+ .@"addrspace" = nav.resolved.?.@"addrspace",
.zir_index = extra.zir_index,
.owner_nav = extra.owner_nav,
.source = extra.flags.source,
@@ -7516,22 +7353,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
.func => unreachable, // use getFuncInstance() or getFuncDecl() instead
.un => unreachable, // use getUnion instead
- .variable => |variable| {
- const has_init = variable.init != .none;
- if (has_init) assert(variable.ty == ip.typeOf(variable.init));
- items.appendAssumeCapacity(.{
- .tag = switch (variable.is_threadlocal) {
- false => .variable,
- true => .threadlocal_variable,
- },
- .data = try addExtra(extra, Tag.Variable{
- .ty = variable.ty,
- .init = variable.init,
- .owner_nav = variable.owner_nav,
- }),
- });
- },
-
.slice => |slice| {
assert(ip.indexToKey(slice.ty).ptr_type.flags.size == .slice);
assert(ip.indexToKey(ip.typeOf(slice.ptr)).ptr_type.flags.size == .many);
@@ -9245,14 +9066,15 @@ pub fn getExtern(
.tid = tid,
.index = items.mutate.len,
}, ip);
- const owner_nav = ip.createNav(gpa, io, tid, .{
- .name = key.name,
- .fqn = key.name,
- .val = extern_index,
- .is_const = key.is_const,
- .alignment = key.alignment,
+ const owner_nav = ip.createNav(gpa, io, tid, key.name, key.name, .{
+ .type = key.ty,
+ .@"align" = key.alignment,
.@"linksection" = .none,
.@"addrspace" = key.@"addrspace",
+ .@"const" = key.is_const,
+ .@"threadlocal" = key.is_threadlocal,
+ .is_extern_decl = true,
+ .value = extern_index,
}) catch unreachable; // capacity asserted above
const decoration_type, const location_or_descriptor_set, const descriptor_binding = if (key.decoration) |decoration| switch (decoration) {
.location => |location| .{ Tag.Extern.Flags.DecorationType.location, location, undefined },
@@ -9266,7 +9088,6 @@ pub fn getExtern(
.flags = .{
.linkage = key.linkage,
.visibility = key.visibility,
- .is_threadlocal = key.is_threadlocal,
.is_dll_import = key.is_dll_import,
.relocation = key.relocation,
.decoration_type = decoration_type,
@@ -9846,14 +9667,16 @@ fn finishFuncInstance(
const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{
fn_owner_nav.name.fmt(ip), @intFromEnum(func_index),
}, .no_embedded_nulls);
- const nav_index = try ip.createNav(gpa, io, tid, .{
- .name = nav_name,
- .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name),
- .val = func_index,
- .is_const = fn_owner_nav.status.fully_resolved.is_const,
- .alignment = fn_owner_nav.status.fully_resolved.alignment,
- .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
- .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
+ const nav_fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name);
+ const nav_index = try ip.createNav(gpa, io, tid, nav_name, nav_fqn, .{
+ .type = ip.typeOf(func_index),
+ .@"align" = fn_owner_nav.resolved.?.@"align",
+ .@"linksection" = fn_owner_nav.resolved.?.@"linksection",
+ .@"addrspace" = fn_owner_nav.resolved.?.@"addrspace",
+ .@"const" = true,
+ .@"threadlocal" = false,
+ .is_extern_decl = false,
+ .value = func_index,
});
// Populate the owner_nav field which was left undefined until now.
@@ -10616,20 +10439,6 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {
return ip.indexToKey(ty).error_union_type.payload_type;
}
-/// The is only legal because the initializer is not part of the hash.
-pub fn mutateVarInit(ip: *InternPool, io: Io, index: Index, init_index: Index) void {
- const unwrapped_index = index.unwrap(ip);
-
- const local = ip.getLocal(unwrapped_index.tid);
- local.mutate.extra.mutex.lockUncancelable(io);
- defer local.mutate.extra.mutex.unlock(io);
-
- const extra_items = local.shared.extra.view().items(.@"0");
- const item = unwrapped_index.getItem(ip);
- assert(item.tag == .variable);
- @atomicStore(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.Variable, "init").?], @intFromEnum(init_index), .release);
-}
-
pub fn dump(ip: *const InternPool) void {
var buffer: [4096]u8 = undefined;
const stderr = std.debug.lockStderr(&buffer);
@@ -10969,7 +10778,6 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
.float_c_longdouble_f80 => @sizeOf(Float80),
.float_c_longdouble_f128 => @sizeOf(Float128),
.float_comptime_float => @sizeOf(Float128),
- .variable, .threadlocal_variable => @sizeOf(Tag.Variable),
.@"extern" => @sizeOf(Tag.Extern),
.func_decl => @sizeOf(Tag.FuncDecl),
.func_instance => b: {
@@ -11089,8 +10897,6 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
.float_c_longdouble_f80,
.float_c_longdouble_f128,
.float_comptime_float,
- .variable,
- .threadlocal_variable,
.@"extern",
.func_decl,
.func_instance,
@@ -11175,8 +10981,24 @@ pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator,
pub fn getNav(ip: *const InternPool, index: Nav.Index) Nav {
const unwrapped = index.unwrap(ip);
- const navs = ip.getLocalShared(unwrapped.tid).navs.acquire();
- return navs.view().get(unwrapped.index).unpack();
+ const view = ip.getLocalShared(unwrapped.tid).navs.acquire().view();
+ // We can't just call `view.get(unwrapped.index)`, because a concurrent call to `resolveNav`
+ // could be writing to fields, making a non-atomic load illegal. Instead, atomically load
+ // each field. We don't need any ordering guarantees because if we need to see (e.g.) the
+ // resolved type of a `Nav`, that information should have already been released to our caller.
+ const repr: Nav.Repr = .{
+ // Load the first few fields non-atomically---they are never mutated after `Nav` creation.
+ .name = view.items(.name)[unwrapped.index],
+ .fqn = view.items(.fqn)[unwrapped.index],
+ .analysis_namespace = view.items(.analysis_namespace)[unwrapped.index],
+ .analysis_zir_index = view.items(.analysis_zir_index)[unwrapped.index],
+ // The last few fields are populated by `resolveNav` so must be loaded atomically.
+ .type = @atomicLoad(InternPool.Index, &view.items(.type)[unwrapped.index], .monotonic),
+ .value = @atomicLoad(InternPool.Index, &view.items(.value)[unwrapped.index], .monotonic),
+ .@"linksection" = @atomicLoad(OptionalNullTerminatedString, &view.items(.@"linksection")[unwrapped.index], .monotonic),
+ .bits = @atomicLoad(Nav.Repr.Bits, &view.items(.bits)[unwrapped.index], .monotonic),
+ };
+ return repr.unpack();
}
pub fn namespacePtr(ip: *InternPool, namespace_index: NamespaceIndex) *Zcu.Namespace {
@@ -11220,15 +11042,9 @@ fn createNav(
gpa: Allocator,
io: Io,
tid: Zcu.PerThread.Id,
- opts: struct {
- name: NullTerminatedString,
- fqn: NullTerminatedString,
- val: InternPool.Index,
- is_const: bool,
- alignment: Alignment,
- @"linksection": OptionalNullTerminatedString,
- @"addrspace": std.builtin.AddressSpace,
- },
+ name: NullTerminatedString,
+ fqn: NullTerminatedString,
+ resolved: @typeInfo(@FieldType(Nav, "resolved")).optional.child,
) Allocator.Error!Nav.Index {
const navs = ip.getLocal(tid).getMutableNavs(gpa, io);
const index_unwrapped: Nav.Index.Unwrapped = .{
@@ -11236,16 +11052,10 @@ fn createNav(
.index = navs.mutate.len,
};
try navs.append(Nav.pack(.{
- .name = opts.name,
- .fqn = opts.fqn,
+ .name = name,
+ .fqn = fqn,
.analysis = null,
- .status = .{ .fully_resolved = .{
- .val = opts.val,
- .is_const = opts.is_const,
- .alignment = opts.alignment,
- .@"linksection" = opts.@"linksection",
- .@"addrspace" = opts.@"addrspace",
- } },
+ .resolved = resolved,
}));
return index_unwrapped.wrap(ip);
}
@@ -11279,27 +11089,19 @@ pub fn createDeclNav(
.zir_index = zir_index,
.wanted = false,
},
- .status = .unresolved,
+ .resolved = null,
}));
return nav;
}
-/// Resolve the type of a `Nav` with an analysis owner.
+/// Resolve the type (and possibly the value) of a `Nav` with an analysis owner.
/// If its status is already `resolved`, the old value is discarded.
-pub fn resolveNavType(
+pub fn resolveNav(
ip: *InternPool,
io: Io,
nav: Nav.Index,
- resolved: struct {
- type: InternPool.Index,
- is_const: bool,
- alignment: Alignment,
- @"linksection": OptionalNullTerminatedString,
- @"addrspace": std.builtin.AddressSpace,
- is_threadlocal: bool,
- is_extern_decl: bool,
- },
+ resolved: @typeInfo(@FieldType(Nav, "resolved")).optional.child,
) void {
const unwrapped = nav.unwrap(ip);
@@ -11311,65 +11113,45 @@ pub fn resolveNavType(
const nav_analysis_namespace = navs.items(.analysis_namespace);
const nav_analysis_zir_index = navs.items(.analysis_zir_index);
- const nav_types = navs.items(.type_or_val);
+ const nav_types = navs.items(.type);
+ const nav_values = navs.items(.value);
const nav_linksections = navs.items(.@"linksection");
const nav_bits = navs.items(.bits);
assert(nav_analysis_namespace[unwrapped.index] != .none);
assert(nav_analysis_zir_index[unwrapped.index] != .none);
- @atomicStore(InternPool.Index, &nav_types[unwrapped.index], resolved.type, .release);
- @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
-
- var bits = nav_bits[unwrapped.index];
- bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
- bits.is_const = resolved.is_const;
- bits.alignment = resolved.alignment;
- bits.@"addrspace" = resolved.@"addrspace";
- bits.is_threadlocal = resolved.is_threadlocal;
- @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
-}
-
-/// Resolve the value of a `Nav` with an analysis owner.
-/// If its status is already `resolved`, the old value is discarded.
-pub fn resolveNavValue(
- ip: *InternPool,
- io: Io,
- nav: Nav.Index,
- resolved: struct {
- val: InternPool.Index,
- is_const: bool,
- alignment: Alignment,
- @"linksection": OptionalNullTerminatedString,
- @"addrspace": std.builtin.AddressSpace,
- },
-) void {
- const unwrapped = nav.unwrap(ip);
-
- const local = ip.getLocal(unwrapped.tid);
- local.mutate.extra.mutex.lockUncancelable(io);
- defer local.mutate.extra.mutex.unlock(io);
-
- const navs = local.shared.navs.view();
-
- const nav_analysis_namespace = navs.items(.analysis_namespace);
- const nav_analysis_zir_index = navs.items(.analysis_zir_index);
- const nav_vals = navs.items(.type_or_val);
- const nav_linksections = navs.items(.@"linksection");
- const nav_bits = navs.items(.bits);
-
- assert(nav_analysis_namespace[unwrapped.index] != .none);
- assert(nav_analysis_zir_index[unwrapped.index] != .none);
+ @atomicStore(
+ OptionalNullTerminatedString,
+ &nav_linksections[unwrapped.index],
+ resolved.@"linksection",
+ .monotonic,
+ );
- @atomicStore(InternPool.Index, &nav_vals[unwrapped.index], resolved.val, .release);
- @atomicStore(OptionalNullTerminatedString, &nav_linksections[unwrapped.index], resolved.@"linksection", .release);
+ const bits = &nav_bits[unwrapped.index];
+ assert(@atomicLoad(Nav.Repr.Bits, bits, .monotonic).want_analysis); // otherwise we wouldn't be resolving `nav` at all
+ @atomicStore(Nav.Repr.Bits, bits, .{
+ .@"align" = resolved.@"align",
+ .@"addrspace" = resolved.@"addrspace",
+ .@"const" = resolved.@"const",
+ .@"threadlocal" = resolved.@"threadlocal",
+ .is_extern_decl = resolved.is_extern_decl,
+ .want_analysis = true, // asserted above that this is already `true`
+ }, .monotonic);
+
+ @atomicStore(
+ InternPool.Index,
+ &nav_types[unwrapped.index],
+ resolved.type,
+ .monotonic,
+ );
- var bits = nav_bits[unwrapped.index];
- bits.status = .fully_resolved;
- bits.is_const = resolved.is_const;
- bits.alignment = resolved.alignment;
- bits.@"addrspace" = resolved.@"addrspace";
- @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
+ @atomicStore(
+ InternPool.Index,
+ &nav_values[unwrapped.index],
+ resolved.value,
+ .monotonic,
+ );
}
pub fn createNamespace(
@@ -11841,8 +11623,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
.error_set_error,
.error_union_error,
.enum_tag,
- .variable,
- .threadlocal_variable,
.@"extern",
.func_decl,
.func_instance,
@@ -11949,11 +11729,7 @@ pub fn funcTypeReturnType(ip: *const InternPool, ty: Index) Index {
}
pub fn isUndef(ip: *const InternPool, val: Index) bool {
- return val == .undef or val.unwrap(ip).getTag(ip) == .undef;
-}
-
-pub fn isVariable(ip: *const InternPool, val: Index) bool {
- return val.unwrap(ip).getTag(ip) == .variable;
+ return val.unwrap(ip).getTag(ip) == .undef;
}
pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.BaseAddr.Tag {
@@ -12220,8 +11996,6 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
.float_c_longdouble_f80,
.float_c_longdouble_f128,
.float_comptime_float,
- .variable,
- .threadlocal_variable,
.@"extern",
.func_decl,
.func_instance,
@@ -13001,11 +12775,17 @@ pub fn setWantNavAnalysis(ip: *InternPool, io: Io, nav_index: Nav.Index) bool {
return false;
}
- const bits = &navs.items(.bits)[unwrapped.index];
- if (bits.want_analysis) {
- return false;
- } else {
- bits.want_analysis = true;
- return true;
- }
+ // Mutate `bits` atomically so that we don't introduce an illegal data race with `getNav`.
+ const old_bits = @atomicRmw(
+ Nav.Repr.Bits,
+ &navs.items(.bits)[unwrapped.index],
+ .Or,
+ mask: {
+ var mask: Nav.Repr.Bits = @bitCast(@as(u16, 0));
+ mask.want_analysis = true;
+ break :mask mask;
+ },
+ .monotonic,
+ );
+ return !old_bits.want_analysis;
}
diff --git a/src/Sema.zig b/src/Sema.zig
@@ -2276,28 +2276,26 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) ?Value {
assert(inst != .none);
if (inst.toInterned()) |ip_index| {
- const val: Value = .fromInterned(ip_index);
- assert(val.getVariable(zcu) == null);
- return val;
- } else {
- // Runtime-known value.
- const air_tags = sema.air_instructions.items(.tag);
- switch (air_tags[@intFromEnum(inst.toIndex().?)]) {
- .inferred_alloc => unreachable, // assertion failure
- .inferred_alloc_comptime => unreachable, // assertion failure
- else => {},
- }
- // LLVM fails to eliminate this `classify` call in ReleaseFast, which hurts performance, so
- // we must explicitly check for `std.debug.runtime_safety`.
- if (std.debug.runtime_safety) switch (sema.typeOf(inst).classify(zcu)) {
- .no_possible_value => unreachable, // values of this type do not exist
- .one_possible_value => unreachable, // the value should be comptime-known
- .partially_comptime => unreachable, // the value should be comptime-known
- .fully_comptime => unreachable, // the value should be comptime-known
- .runtime => {},
- };
- return null;
+ return .fromInterned(ip_index);
}
+
+ // Runtime-known value. We'll be returning `null`, but first, some assertions.
+ const air_tags = sema.air_instructions.items(.tag);
+ switch (air_tags[@intFromEnum(inst.toIndex().?)]) {
+ .inferred_alloc => unreachable, // assertion failure
+ .inferred_alloc_comptime => unreachable, // assertion failure
+ else => {},
+ }
+ // LLVM fails to eliminate this `classify` call in ReleaseFast, which hurts performance, so
+ // we must explicitly check for `std.debug.runtime_safety`.
+ if (std.debug.runtime_safety) switch (sema.typeOf(inst).classify(zcu)) {
+ .no_possible_value => unreachable, // values of this type do not exist
+ .one_possible_value => unreachable, // the value should be comptime-known
+ .partially_comptime => unreachable, // the value should be comptime-known
+ .fully_comptime => unreachable, // the value should be comptime-known
+ .runtime => {},
+ };
+ return null;
}
/// Like `resolveValue`, but emits an error if the value is not comptime-known.
@@ -5738,8 +5736,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
.uav => |uav| .{ .uav = uav.val },
.nav => |orig_nav| target: {
try sema.ensureNavResolved(block, src, orig_nav, .fully);
- const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).status.fully_resolved.val)) {
- .variable => |v| v.owner_nav,
+ const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).resolved.?.value)) {
.@"extern" => |e| e.owner_nav,
.func => |f| f.owner_nav,
else => orig_nav,
@@ -5778,7 +5775,7 @@ pub fn analyzeExportSelfNav(
const ip = &zcu.intern_pool;
const orig_nav = sema.owner.unwrap().nav_val;
- const export_val: Value = .fromInterned(ip.getNav(orig_nav).status.fully_resolved.val);
+ const export_val: Value = .fromInterned(ip.getNav(orig_nav).resolved.?.value);
const export_ty = export_val.typeOf(zcu);
if (!export_ty.validateExtern(.other, zcu)) {
@@ -5792,7 +5789,6 @@ pub fn analyzeExportSelfNav(
}
const export_nav = switch (ip.indexToKey(export_val.toIntern())) {
- .variable => |v| v.owner_nav,
.@"extern" => |e| e.owner_nav,
.func => |f| export_nav: {
assert(export_ty.fnHasRuntimeBits(zcu)); // otherwise `validateExtern` failed above
@@ -30005,7 +30001,7 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:
const nav = ip.getNav(nav_index);
if (nav.analysis == null) {
- assert(nav.status == .fully_resolved);
+ assert(nav.resolved.?.value != .none);
return;
}
@@ -30066,11 +30062,20 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
try sema.ensureNavResolved(block, src, orig_nav_index, if (is_ref) .type else .fully);
const nav_index = nav: {
- if (ip.getNav(orig_nav_index).isExternOrFn(ip)) {
- // Getting a pointer to this `Nav` might mean we actually get a pointer to something else!
- // We need to resolve the value to know for sure.
- if (is_ref) try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
- switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) {
+ const orig_nav = ip.getNav(orig_nav_index);
+ if (orig_nav.resolved.?.is_extern_decl or ip.zigTypeTag(orig_nav.resolved.?.type) == .@"fn") {
+ // A pointer to this `Nav` might actually be encoded as a pointer to a different `Nav`
+ // because this is either an `extern` definition or an `extern` alias. (The latter case
+ // is unsolved language weirdness; see https://github.com/ziglang/zig/issues/21027.) To
+ // know for sure how to encode this pointer, we need to check the *value* of this `Nav`.
+ const orig_nav_value = switch (is_ref) {
+ false => orig_nav.resolved.?.value,
+ true => orig_val: {
+ try sema.ensureNavResolved(block, src, orig_nav_index, .fully);
+ break :orig_val ip.getNav(orig_nav_index).resolved.?.value;
+ },
+ };
+ switch (ip.indexToKey(orig_nav_value)) {
.func => |f| break :nav f.owner_nav,
.@"extern" => |e| break :nav e.owner_nav,
else => {},
@@ -30079,33 +30084,31 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
break :nav orig_nav_index;
};
- const nav_status = ip.getNav(nav_index).status;
+ const nav_resolved = ip.getNav(nav_index).resolved.?;
- const is_runtime = switch (nav_status) {
- .unresolved => unreachable,
- // dllimports go straight to `fully_resolved`; the only option is threadlocal
- .type_resolved => |r| r.is_threadlocal,
- .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
- .@"extern" => |e| e.is_threadlocal or e.is_dll_import or switch (e.relocation) {
- .any => false,
- .pcrel => true,
- },
- .variable => |v| v.is_threadlocal,
- else => false,
- },
+ const is_runtime: bool = runtime: {
+ if (nav_resolved.@"threadlocal") break :runtime true;
+ if (nav_resolved.value == .none) {
+ // This didn't come from `@extern`, so even if extern it couldn't be dllimport or pcrel.
+ break :runtime false;
+ }
+ const @"extern" = switch (ip.indexToKey(nav_resolved.value)) {
+ .@"extern" => |e| e,
+ else => break :runtime false,
+ };
+ if (@"extern".is_dll_import) break :runtime true;
+ break :runtime switch (@"extern".relocation) {
+ .any => false,
+ .pcrel => true,
+ };
};
- const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
- .unresolved => unreachable,
- .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
- .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
- };
const ptr_ty = try pt.ptrType(.{
- .child = ty,
+ .child = nav_resolved.type,
.flags = .{
- .alignment = alignment,
- .is_const = is_const,
- .address_space = @"addrspace",
+ .alignment = nav_resolved.@"align",
+ .is_const = nav_resolved.@"const",
+ .address_space = nav_resolved.@"addrspace",
},
});
@@ -30140,7 +30143,7 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_i
// If it is, we can resolve the *value*, and queue analysis as needed.
try sema.ensureNavResolved(block, src, nav_index, .type);
- const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
+ const nav_ty: Type = .fromInterned(ip.getNav(nav_index).resolved.?.type);
if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
if (!nav_ty.fnHasRuntimeBits(zcu)) return;
@@ -34006,7 +34009,7 @@ pub fn getBuiltin(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError
}
pub const NavPtrModifiers = struct {
- alignment: Alignment,
+ @"align": Alignment,
@"linksection": InternPool.OptionalNullTerminatedString,
@"addrspace": std.builtin.AddressSpace,
};
@@ -34029,7 +34032,7 @@ pub fn resolveNavPtrModifiers(
const section_src = block.src(.{ .node_offset_var_decl_section = .zero });
const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = .zero });
- const alignment: InternPool.Alignment = a: {
+ const @"align": InternPool.Alignment = a: {
const align_body = zir_decl.align_body orelse break :a .none;
const align_ref = try sema.resolveInlineBody(block, align_body, decl_inst);
break :a try sema.analyzeAsAlign(block, align_src, align_ref);
@@ -34067,7 +34070,7 @@ pub fn resolveNavPtrModifiers(
};
return .{
- .alignment = alignment,
+ .@"align" = @"align",
.@"linksection" = @"linksection",
.@"addrspace" = @"addrspace",
};
diff --git a/src/Sema/bitcast.zig b/src/Sema/bitcast.zig
@@ -253,7 +253,6 @@ const UnpackValueBits = struct {
.func_type,
.error_set_type,
.inferred_error_set_type,
- .variable,
.@"extern",
.func,
.err,
diff --git a/src/Sema/comptime_ptr_access.zig b/src/Sema/comptime_ptr_access.zig
@@ -225,19 +225,17 @@ fn loadComptimePtrInner(
};
const base_val: MutableValue = switch (ptr.base_addr) {
- .nav => |nav| val: {
- try sema.ensureNavResolved(block, src, nav, .fully);
- const val = ip.getNav(nav).status.fully_resolved.val;
- switch (ip.indexToKey(val)) {
- .variable => return .runtime_load,
- // We let `.@"extern"` through here if it's a function.
- // This allows you to alias `extern fn`s.
- .@"extern" => |e| if (Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn")
- break :val .{ .interned = val }
- else
- return .runtime_load,
- else => break :val .{ .interned = val },
+ .nav => |nav_id| val: {
+ try sema.ensureNavResolved(block, src, nav_id, .fully);
+ const nav = ip.getNav(nav_id);
+ if (!nav.resolved.?.@"const") return .runtime_load;
+ // We let `.@"extern"` through here if it's a fn. This allows aliasing `extern fn`s.
+ if (ip.indexToKey(nav.resolved.?.value) == .@"extern" and
+ Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu) != .@"fn")
+ {
+ return .runtime_load;
}
+ break :val .{ .interned = nav.resolved.?.value };
},
.comptime_alloc => |alloc_index| sema.getComptimeAlloc(alloc_index).val,
.uav => |uav| .{ .interned = uav.val },
diff --git a/src/Sema/type_resolution.zig b/src/Sema/type_resolution.zig
@@ -115,7 +115,6 @@ fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *cons
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
diff --git a/src/Type.zig b/src/Type.zig
@@ -239,7 +239,6 @@ pub fn classify(start_ty: Type, zcu: *const Zcu) Class {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -675,7 +674,6 @@ pub fn print(ty: Type, writer: *std.Io.Writer, pt: Zcu.PerThread, ctx: ?*Compari
// values, not types
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -814,7 +812,6 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -1046,7 +1043,6 @@ pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -1187,7 +1183,6 @@ pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -1311,7 +1306,6 @@ pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -1867,7 +1861,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -2162,7 +2155,6 @@ pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -3284,7 +3276,6 @@ pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
// values, not types
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -3362,7 +3353,6 @@ fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUn
// values, not types
.simple_value,
- .variable,
.@"extern",
.func,
.int,
diff --git a/src/Value.zig b/src/Value.zig
@@ -176,13 +176,6 @@ pub fn getFunction(val: Value, zcu: *Zcu) ?InternPool.Key.Func {
};
}
-pub fn getVariable(val: Value, mod: *Zcu) ?InternPool.Key.Variable {
- return switch (mod.intern_pool.indexToKey(val.toIntern())) {
- .variable => |variable| variable,
- else => null,
- };
-}
-
/// Asserts the value is a (defined) integer and it fits in a u64.
pub fn toUnsignedInt(val: Value, zcu: *const Zcu) u64 {
return getUnsignedInt(val, zcu).?;
@@ -808,7 +801,6 @@ pub fn canMutateComptimeVarState(val: Value, zcu: *Zcu) bool {
pub fn pointerNav(val: Value, zcu: *const Zcu) ?InternPool.Nav.Index {
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
// TODO: these 3 cases are weird; these aren't pointer values!
- .variable => |v| v.owner_nav,
.@"extern" => |e| e.owner_nav,
.func => |func| func.owner_nav,
.ptr => |ptr| if (ptr.byte_offset == 0) switch (ptr.base_addr) {
@@ -2539,7 +2531,7 @@ pub fn intFitsInType(
.zero_usize, .zero_u8 => return true,
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
.undef => return true,
- .variable, .@"extern", .func, .ptr => {
+ .@"extern", .func, .ptr => {
const target = zcu.getTarget();
const ptr_bits = target.ptrBitWidth();
return switch (info.signedness) {
diff --git a/src/Zcu.zig b/src/Zcu.zig
@@ -723,11 +723,7 @@ pub const Exported = union(enum) {
pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
return switch (exported) {
- .nav => |nav| switch (zcu.intern_pool.getNav(nav).status) {
- .unresolved => unreachable,
- .type_resolved => |r| r.alignment,
- .fully_resolved => |r| r.alignment,
- },
+ .nav => |nav| zcu.intern_pool.getNav(nav).resolved.?.@"align",
.uav => .none,
};
}
@@ -4252,8 +4248,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.AutoArrayHashMapUnmanag
}
}
// Non-fatal AstGen errors could mean this test decl failed
- if (nav.status == .fully_resolved) {
- const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.status.fully_resolved.val }));
+ if (nav.resolved != null and nav.resolved.?.value != .none) {
+ const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.resolved.?.value }));
if (!gop.found_existing) gop.value_ptr.* = referencer;
}
}
@@ -4419,7 +4415,7 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
}
pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
- return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.fully_resolved.val);
+ return .fromInterned(zcu.intern_pool.getNav(nav_index).resolved.?.value);
}
pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {
@@ -4431,14 +4427,12 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
}
-pub fn navAlignment(zcu: *Zcu, nav_index: InternPool.Nav.Index) InternPool.Alignment {
- const ty: Type, const alignment = switch (zcu.intern_pool.getNav(nav_index).status) {
- .unresolved => unreachable,
- .type_resolved => |r| .{ .fromInterned(r.type), r.alignment },
- .fully_resolved => |r| .{ Value.fromInterned(r.val).typeOf(zcu), r.alignment },
+pub fn navAlignment(zcu: *Zcu, nav_id: InternPool.Nav.Index) InternPool.Alignment {
+ const resolved = zcu.intern_pool.getNav(nav_id).resolved.?;
+ return switch (resolved.@"align") {
+ else => |a| a,
+ .none => Type.fromInterned(resolved.type).abiAlignment(zcu),
};
- if (alignment != .none) return alignment;
- return ty.abiAlignment(zcu);
}
pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) {
diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig
@@ -1584,10 +1584,6 @@ pub fn ensureNavValUpToDate(
try zcu.ensureNavValAnalysisQueued(nav_id);
- // Determine whether or not this `Nav`'s value is outdated. This also includes checking if the
- // status is `.unresolved`, which indicates that the value is outdated because it has *never*
- // been analyzed so far.
- //
// Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
// ensure that the unit is definitely up-to-date when this function returns. This mechanism could
// result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
@@ -1603,7 +1599,7 @@ pub fn ensureNavValUpToDate(
} else {
// We can trust the current information about this unit.
if (prev_failed) return error.AnalysisFail;
- assert(nav.status == .fully_resolved);
+ assert(nav.resolved.?.value != .none);
return;
}
@@ -1740,7 +1736,7 @@ fn analyzeNavVal(
const maybe_ty: ?Type = if (zir_decl.type_body != null) ty: {
// Since we have a type body, the type is resolved separately!
try sema.ensureNavResolved(&block, init_src, nav_id, .type);
- break :ty .fromInterned(ip.getNav(nav_id).typeOf(ip));
+ break :ty .fromInterned(ip.getNav(nav_id).resolved.?.type);
} else null;
const final_val: ?Value = if (zir_decl.value_body) |value_body| val: {
@@ -1786,14 +1782,12 @@ fn analyzeNavVal(
const modifiers: Sema.NavPtrModifiers = if (zir_decl.type_body != null) m: {
// `analyzeNavType` (from the `ensureNavTypeUpToDate` call above) has already populated this data into
// the `Nav`. Load the new one, and pull the modifiers out.
- switch (ip.getNav(nav_id).status) {
- .unresolved => unreachable, // `analyzeNavType` will never leave us in this state
- inline .type_resolved, .fully_resolved => |r| break :m .{
- .alignment = r.alignment,
- .@"linksection" = r.@"linksection",
- .@"addrspace" = r.@"addrspace",
- },
- }
+ const r = ip.getNav(nav_id).resolved.?;
+ break :m .{
+ .@"align" = r.@"align",
+ .@"linksection" = r.@"linksection",
+ .@"addrspace" = r.@"addrspace",
+ };
} else m: {
// `analyzeNavType` is essentially a stub which calls us. We are responsible for resolving this data.
break :m try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, nav_ty);
@@ -1803,15 +1797,7 @@ fn analyzeNavVal(
// This isn't necessarily the same as `final_val`!
const nav_val: Value = switch (zir_decl.linkage) {
- .normal, .@"export" => switch (zir_decl.kind) {
- .@"var" => .fromInterned(try pt.intern(.{ .variable = .{
- .ty = nav_ty.toIntern(),
- .init = final_val.?.toIntern(),
- .owner_nav = nav_id,
- .is_threadlocal = zir_decl.is_threadlocal,
- } })),
- else => final_val.?,
- },
+ .normal, .@"export" => final_val.?,
.@"extern" => val: {
assert(final_val == null); // extern decls do not have a value body
const lib_name: ?[]const u8 = if (zir_decl.lib_name != .empty) l: {
@@ -1832,7 +1818,7 @@ fn analyzeNavVal(
.relocation = .any,
.decoration = null,
.is_const = is_const,
- .alignment = modifiers.alignment,
+ .alignment = modifiers.@"align",
.@"addrspace" = modifiers.@"addrspace",
.zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
.owner_nav = undefined, // ignored by `getExtern`
@@ -1852,11 +1838,7 @@ fn analyzeNavVal(
const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
.func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
- .variable => |v| .{ v.owner_nav == nav_id, false },
- .@"extern" => |e| .{
- false,
- Type.fromInterned(e.ty).zigTypeTag(zcu) == .@"fn" and zir_decl.linkage == .@"extern",
- },
+ .@"extern" => .{ false, nav_ty.zigTypeTag(zcu) == .@"fn" and zir_decl.linkage == .@"extern" },
else => .{ true, false },
};
@@ -1895,23 +1877,22 @@ fn analyzeNavVal(
info.last_update_gen = zcu.generation;
info.deps.clearRetainingCapacity();
}
- const type_changed: bool = switch (old_nav.status) {
- .unresolved => true,
- .type_resolved => |old| old.type != nav_ty.toIntern(),
- .fully_resolved => |old| ip.typeOf(old.val) != nav_ty.toIntern(),
- };
+ const type_changed: bool = if (old_nav.resolved) |r| r.type != nav_ty.toIntern() else true;
if (type_changed) {
try zcu.markDependeeOutdated(.marked_po, .{ .nav_ty = nav_id });
} else {
try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav_id });
}
}
- ip.resolveNavValue(io, nav_id, .{
- .val = nav_val.toIntern(),
- .is_const = is_const,
- .alignment = modifiers.alignment,
+ ip.resolveNav(io, nav_id, .{
+ .type = nav_ty.toIntern(),
+ .@"align" = modifiers.@"align",
.@"linksection" = modifiers.@"linksection",
.@"addrspace" = modifiers.@"addrspace",
+ .@"const" = is_const,
+ .@"threadlocal" = zir_decl.is_threadlocal,
+ .is_extern_decl = zir_decl.linkage == .@"extern",
+ .value = nav_val.toIntern(),
});
if (zir_decl.linkage == .@"export") {
@@ -1943,9 +1924,10 @@ fn analyzeNavVal(
try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern());
}
- return switch (old_nav.status) {
- .unresolved, .type_resolved => .{ .val_changed = true },
- .fully_resolved => |old| .{ .val_changed = old.val != nav_val.toIntern() },
+ return if (old_nav.resolved) |old_resolved| .{
+ .val_changed = old_resolved.value != nav_val.toIntern(),
+ } else .{
+ .val_changed = true,
};
}
@@ -1971,10 +1953,6 @@ pub fn ensureNavTypeUpToDate(
try zcu.ensureNavValAnalysisQueued(nav_id);
- // Determine whether or not this `Nav`'s type is outdated. This also includes checking if the
- // status is `.unresolved`, which indicates that the value is outdated because it has *never*
- // been analyzed so far.
- //
// Note that if the unit is PO, we pessimistically assume that it *does* require re-analysis, to
// ensure that the unit is definitely up-to-date when this function returns. This mechanism could
// result in over-analysis if analysis occurs in a poor order; we do our best to avoid this by
@@ -1990,7 +1968,7 @@ pub fn ensureNavTypeUpToDate(
} else {
// We can trust the current information about this unit.
if (prev_failed) return error.AnalysisFail;
- assert(nav.status != .unresolved);
+ assert(nav.resolved != null);
return;
}
@@ -2124,24 +2102,16 @@ fn analyzeNavType(
// the previous update. As such, after this call, we will be able to determine whether the
// type changed.
try sema.ensureNavResolved(&block, init_src, nav_id, .fully);
- const new = ip.getNav(nav_id).status.fully_resolved;
- const new_is_extern_decl = ip.indexToKey(new.val) == .@"extern";
- const changed = switch (old_nav.status) {
- .unresolved => true,
- .type_resolved => |r| r.type != ip.typeOf(new.val) or
- r.alignment != new.alignment or
- r.@"linksection" != new.@"linksection" or
- r.@"addrspace" != new.@"addrspace" or
- r.is_const != new.is_const or
- r.is_extern_decl != new_is_extern_decl,
- .fully_resolved => |r| ip.typeOf(r.val) != ip.typeOf(new.val) or
- r.alignment != new.alignment or
- r.@"linksection" != new.@"linksection" or
- r.@"addrspace" != new.@"addrspace" or
- r.is_const != new.is_const or
- (old_nav.getExtern(ip) != null) != new_is_extern_decl,
- };
- return .{ .type_changed = changed };
+ const new = ip.getNav(nav_id).resolved.?;
+ return if (old_nav.resolved) |old| .{
+ .type_changed = old.type != new.type or
+ old.@"align" != new.@"align" or
+ old.@"linksection" != new.@"linksection" or
+ old.@"addrspace" != new.@"addrspace" or
+ old.@"const" != new.@"const" or
+ old.@"threadlocal" != new.@"threadlocal" or
+ old.is_extern_decl != new.is_extern_decl,
+ } else .{ .type_changed = true };
};
block.comptime_reason = .{ .reason = .{
@@ -2169,37 +2139,34 @@ fn analyzeNavType(
const is_extern_decl = zir_decl.linkage == .@"extern";
- // Now for the question of the day: are the type and modifiers the same as before?
- // If they are, then we should actually keep the `Nav` as `fully_resolved` if it currently is.
- // That's because `analyzeNavVal` will later want to look at the resolved value to figure out
- // whether it's changed: if we threw that data away now, it would have to assume that the value
- // had changed, potentially spinning off loads of unnecessary re-analysis!
- const changed = switch (old_nav.status) {
- .unresolved => true,
- .type_resolved => |r| r.type != resolved_ty.toIntern() or
- r.alignment != modifiers.alignment or
- r.@"linksection" != modifiers.@"linksection" or
- r.@"addrspace" != modifiers.@"addrspace" or
- r.is_const != is_const or
- r.is_extern_decl != is_extern_decl,
- .fully_resolved => |r| ip.typeOf(r.val) != resolved_ty.toIntern() or
- r.alignment != modifiers.alignment or
- r.@"linksection" != modifiers.@"linksection" or
- r.@"addrspace" != modifiers.@"addrspace" or
- r.is_const != is_const or
- (old_nav.getExtern(ip) != null) != is_extern_decl,
- };
+ // Now for the question of the day: are the type and modifiers the same as before? If they are,
+ // then we should actually avoid calling `ip.resolveNav`. This is because `analyzeNavVal` will
+ // later wanmt to look at the resolved *value* to figure out whether *that* has changed: if we
+ // threw that data away now, it would have to assume the value *had* changed even if it actually
+ // hadn't, which could spin off a bunch of unnecessary re-analysis! OTOH, if the type *has*
+ // changed, then we obviously know that the value will also have changed, so resetting the value
+ // to `.none` is fine in that case.
+ const changed: bool = if (old_nav.resolved) |old| changed: {
+ break :changed old.type != resolved_ty.toIntern() or
+ old.@"align" != modifiers.@"align" or
+ old.@"linksection" != modifiers.@"linksection" or
+ old.@"addrspace" != modifiers.@"addrspace" or
+ old.@"const" != is_const or
+ old.@"threadlocal" != zir_decl.is_threadlocal or
+ old.is_extern_decl != is_extern_decl;
+ } else true;
if (!changed) return .{ .type_changed = false };
- ip.resolveNavType(io, nav_id, .{
+ ip.resolveNav(io, nav_id, .{
.type = resolved_ty.toIntern(),
- .is_const = is_const,
- .alignment = modifiers.alignment,
+ .@"align" = modifiers.@"align",
.@"linksection" = modifiers.@"linksection",
.@"addrspace" = modifiers.@"addrspace",
- .is_threadlocal = zir_decl.is_threadlocal,
+ .@"const" = is_const,
+ .@"threadlocal" = zir_decl.is_threadlocal,
.is_extern_decl = is_extern_decl,
+ .value = .none,
});
return .{ .type_changed = true };
@@ -3358,13 +3325,13 @@ fn analyzeFuncBodyInner(
if (func.generic_owner == .none) {
try pt.ensureNavValUpToDate(func.owner_nav, reason);
- if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {
+ if (ip.getNav(func.owner_nav).resolved.?.value != func_index) {
return error.AnalysisFail;
}
} else {
const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
try pt.ensureNavValUpToDate(go_nav, reason);
- if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {
+ if (ip.getNav(go_nav).resolved.?.value != func.generic_owner) {
return error.AnalysisFail;
}
}
@@ -3757,9 +3724,9 @@ fn processExportsInner(
if (zcu.failed_analysis.contains(unit)) break :failed true;
if (zcu.transitive_failed_analysis.contains(unit)) break :failed true;
}
- const val = switch (nav.status) {
- .unresolved, .type_resolved => break :failed true,
- .fully_resolved => |r| Value.fromInterned(r.val),
+ const val: Value = switch ((nav.resolved orelse break :failed true).value) {
+ .none => break :failed true,
+ else => |val| .fromInterned(val),
};
// If the value is a function, we also need to check if that function succeeded analysis.
if (val.typeOf(zcu).zigTypeTag(zcu) == .@"fn") {
@@ -3805,14 +3772,16 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void {
if (builtin_root_type == .none) return; // `@import("builtin")` never analyzed
const builtin_namespace = Type.fromInterned(builtin_root_type).getNamespace(zcu).unwrap().?;
// We know that the namespace has a `test_functions`...
- const nav_index = zcu.namespacePtr(builtin_namespace).pub_decls.getKeyAdapted(
+ const test_fns_nav_index = zcu.namespacePtr(builtin_namespace).pub_decls.getKeyAdapted(
try ip.getOrPutString(gpa, io, pt.tid, "test_functions", .no_embedded_nulls),
Zcu.Namespace.NameAdapter{ .zcu = zcu },
).?;
+ const test_fns_nav = ip.getNav(test_fns_nav_index);
// ...but it might not be populated, so let's check that!
- if (zcu.failed_analysis.contains(.wrap(.{ .nav_val = nav_index })) or
- zcu.transitive_failed_analysis.contains(.wrap(.{ .nav_val = nav_index })) or
- ip.getNav(nav_index).status != .fully_resolved)
+ if (zcu.failed_analysis.contains(.wrap(.{ .nav_val = test_fns_nav_index })) or
+ zcu.transitive_failed_analysis.contains(.wrap(.{ .nav_val = test_fns_nav_index })) or
+ test_fns_nav.resolved == null or
+ test_fns_nav.resolved.?.value == .none)
{
// The value of `builtin.test_functions` was either never referenced, or failed analysis.
// Either way, we don't need to do anything.
@@ -3822,8 +3791,7 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void {
// Okay, `builtin.test_functions` is (potentially) referenced and valid. Our job now is to swap
// its placeholder `&.{}` value for the actual list of all test functions.
- const test_fns_val = zcu.navValue(nav_index);
- const test_fn_ty = test_fns_val.typeOf(zcu).slicePtrFieldType(zcu).childType(zcu);
+ const test_fn_ty = Type.fromInterned(test_fns_nav.resolved.?.type).slicePtrFieldType(zcu).childType(zcu);
const array_anon_decl: InternPool.Key.Ptr.BaseAddr.Uav = array: {
// Add zcu.test_functions to an array decl then make the test_functions
@@ -3914,10 +3882,12 @@ pub fn populateTestFunctions(pt: Zcu.PerThread) Allocator.Error!void {
} }),
.len = (try pt.intValue(Type.usize, zcu.test_functions.count())).toIntern(),
} });
- ip.mutateVarInit(io, test_fns_val.toIntern(), new_init);
+ var new_resolved_test_fns = test_fns_nav.resolved.?;
+ new_resolved_test_fns.value = new_init;
+ ip.resolveNav(io, test_fns_nav_index, new_resolved_test_fns);
}
// The linker thread is not running, so we actually need to dispatch this task directly.
- @import("../link.zig").linkTestFunctionsNav(pt, nav_index);
+ @import("../link.zig").linkTestFunctionsNav(pt, test_fns_nav_index);
}
/// Stores an error in `pt.zcu.failed_files` for this file, and sets the file
@@ -4402,17 +4372,13 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {
pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
- .unresolved => unreachable,
- .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
- .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
- };
+ const resolved_nav = ip.getNav(nav_id).resolved.?;
return pt.ptrType(.{
- .child = ty,
+ .child = resolved_nav.type,
.flags = .{
- .alignment = alignment,
- .address_space = @"addrspace",
- .is_const = is_const,
+ .alignment = resolved_nav.@"align",
+ .address_space = resolved_nav.@"addrspace",
+ .is_const = resolved_nav.@"const",
},
});
}
diff --git a/src/codegen.zig b/src/codegen.zig
@@ -352,7 +352,6 @@ pub fn generateSymbol(
else => unreachable,
}),
},
- .variable,
.@"extern",
.func,
.enum_literal,
@@ -787,7 +786,7 @@ fn lowerNavRef(
const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
const is_obj = lf.comp.config.output_mode == .Obj;
- const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
+ const nav_ty = Type.fromInterned(ip.getNav(nav_index).resolved.?.type);
if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) {
try w.splatByteAll(0xaa, ptr_width_bytes);
@@ -876,10 +875,11 @@ pub fn genNavRef(
const nav = ip.getNav(nav_index);
log.debug("genNavRef({f})", .{nav.fqn.fmt(ip)});
- const lib_name, const linkage, const is_threadlocal = if (nav.getExtern(ip)) |e|
- .{ e.lib_name, e.linkage, e.is_threadlocal and zcu.comp.config.any_non_single_threaded }
+ const is_threadlocal = nav.resolved.?.@"threadlocal" and zcu.comp.config.any_non_single_threaded;
+ const lib_name, const linkage = if (nav.getExtern(ip)) |e|
+ .{ e.lib_name, e.linkage }
else
- .{ .none, .internal, false };
+ .{ .none, .internal };
if (lf.cast(.elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
switch (linkage) {
@@ -1038,7 +1038,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
.nav => |nav_index| {
const nav = ip.getNav(nav_index);
- const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ const nav_ty: Type = .fromInterned(nav.resolved.?.type);
if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) or nav.getExtern(ip) != null) {
return .{ .lea_nav = nav_index };
} else {
diff --git a/src/codegen/aarch64/Mir.zig b/src/codegen/aarch64/Mir.zig
@@ -69,7 +69,7 @@ pub fn emit(
const target = &mod.resolved_target.result;
mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
- const func_align = switch (nav.status.fully_resolved.alignment) {
+ const func_align = switch (nav.resolved.?.@"align") {
.none => switch (mod.optimize_mode) {
.Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
.ReleaseSmall => target_util.minFunctionAlignment(target),
diff --git a/src/codegen/aarch64/Select.zig b/src/codegen/aarch64/Select.zig
@@ -7207,7 +7207,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
const ptr_ra = try ptr_vi.value.defReg(isel) orelse break :unused;
const ty_nav = air.data(air.inst_index).ty_nav;
- if (ZigType.fromInterned(ip.getNav(ty_nav.nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
+ if (ZigType.fromInterned(ip.getNav(ty_nav.nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
false => {
try isel.nav_relocs.append(gpa, .{
.nav = ty_nav.nav,
@@ -10577,7 +10577,6 @@ pub const Value = struct {
=> continue :type_key .{ .simple_type = .anyerror },
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -10914,7 +10913,7 @@ pub const Value = struct {
.ptr => |ptr| {
assert(offset == 0 and size == 8);
break :free switch (ptr.base_addr) {
- .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).typeOf(ip)).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
+ .nav => |nav| if (ZigType.fromInterned(ip.getNav(nav).resolved.?.type).isRuntimeFnOrHasRuntimeBits(zcu)) switch (true) {
false => {
try isel.nav_relocs.append(zcu.gpa, .{
.nav = nav,
@@ -12300,7 +12299,6 @@ pub const CallAbiIterator = struct {
=> continue :type_key .{ .simple_type = .anyerror },
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
@@ -669,11 +669,9 @@ pub const DeclGen = struct {
return dg.renderUndefValue(w, ptr_ty, location);
}
- // Chase function values in order to be able to reference the original function.
switch (ip.indexToKey(uav.val)) {
- .variable => unreachable,
- .func => |func| return dg.renderNav(w, func.owner_nav, location),
- .@"extern" => |@"extern"| return dg.renderNav(w, @"extern".owner_nav, location),
+ .func => unreachable,
+ .@"extern" => unreachable,
else => {},
}
@@ -721,10 +719,9 @@ pub const DeclGen = struct {
const ip = &zcu.intern_pool;
// Chase function values in order to be able to reference the original function.
- const owner_nav = switch (ip.getNav(nav_index).status) {
- .unresolved => unreachable,
- .type_resolved => nav_index, // this can't be an extern or a function
- .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
+ const owner_nav = switch (ip.getNav(nav_index).resolved.?.value) {
+ .none => nav_index, // this can't be an extern or a function
+ else => |value| switch (ip.indexToKey(value)) {
.func => |f| f.owner_nav,
.@"extern" => |e| e.owner_nav,
else => nav_index,
@@ -732,7 +729,7 @@ pub const DeclGen = struct {
};
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
- const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).typeOf(ip));
+ const nav_ty: Type = .fromInterned(ip.getNav(owner_nav).resolved.?.type);
const ptr_ty = try pt.navPtrType(owner_nav);
if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
return dg.renderUndefValue(w, ptr_ty, location);
@@ -924,7 +921,6 @@ pub const DeclGen = struct {
.false => try w.writeAll("false"),
.true => try w.writeAll("true"),
},
- .variable,
.@"extern",
.func,
.enum_literal,
@@ -1575,7 +1571,6 @@ pub const DeclGen = struct {
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -2276,13 +2271,13 @@ pub fn genFunc(f: *Function, fwd_decl_writer: *Writer, header_writer: *Writer) E
try f.dg.renderFunctionSignature(
fwd_decl_writer,
nav_val,
- nav.status.fully_resolved.alignment,
+ nav.resolved.?.@"align",
.forward_decl,
.{ .nav = nav_index },
);
try fwd_decl_writer.writeAll(";\n");
- if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
+ if (nav.resolved.?.@"linksection".toSlice(ip)) |s|
try header_writer.print("zig_linksection_fn({f}) ", .{fmtStringLiteral(s, null)});
try f.dg.renderFunctionSignature(
header_writer,
@@ -2360,28 +2355,26 @@ pub fn genDecl(dg: *DeclGen, w: *Writer) Error!void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(dg.owner_nav.unwrap().?);
- const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ const nav_ty: Type = .fromInterned(nav.resolved.?.type);
- const is_const: bool, const is_threadlocal: bool, const init_val: Value = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
- else => .{ true, false, .fromInterned(nav.status.fully_resolved.val) },
- .variable => |v| .{ false, v.is_threadlocal, .fromInterned(v.init) },
- .@"extern" => return,
- };
+ if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return;
- if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s| {
+ const init_val: Value = .fromInterned(nav.resolved.?.value);
+
+ if (nav.resolved.?.@"linksection".toSlice(ip)) |s| {
try w.print("zig_linksection({f}) ", .{fmtStringLiteral(s, null)});
}
// We don't bother underaligning---it's unnecessary and hurts compatibility.
- const a = nav.status.fully_resolved.alignment;
+ const a = nav.resolved.?.@"align";
if (a != .none and a.compareStrict(.gt, nav_ty.abiAlignment(zcu))) {
try w.print("zig_align({d}) ", .{a.toByteUnits().?});
}
try genDeclValue(dg, w, .{
.name = .{ .nav = dg.owner_nav.unwrap().? },
- .@"const" = is_const,
- .@"threadlocal" = is_threadlocal,
+ .@"const" = nav.resolved.?.@"const",
+ .@"threadlocal" = nav.resolved.?.@"threadlocal",
.init_val = init_val,
});
}
@@ -2393,19 +2386,18 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(dg.owner_nav.unwrap().?);
- const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ const nav_ty: Type = .fromInterned(nav.resolved.?.type);
- const is_const: bool, const is_threadlocal: bool, const init_val: Value = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
- else => .{ true, false, .fromInterned(nav.status.fully_resolved.val) },
- .variable => |v| .{ false, v.is_threadlocal, .fromInterned(v.init) },
+ const init_val: Value = switch (ip.indexToKey(nav.resolved.?.value)) {
+ else => .fromInterned(nav.resolved.?.value),
.@"extern" => |@"extern"| switch (nav_ty.zigTypeTag(zcu)) {
.@"fn" => {
try w.writeAll("zig_extern ");
try dg.renderFunctionSignature(
w,
- Value.fromInterned(nav.status.fully_resolved.val),
- nav.status.fully_resolved.alignment,
+ .fromInterned(nav.resolved.?.value),
+ nav.resolved.?.@"align",
.forward_decl,
.{ .@"export" = .{
.main_name = nav.name,
@@ -2422,15 +2414,15 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void {
.weak => try w.print("zig_extern zig_weak_linkage zig_visibility({t}) ", .{@"extern".visibility}),
.link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
}
- if (@"extern".is_threadlocal and !dg.mod.single_threaded) {
+ if (nav.resolved.?.@"threadlocal" and !dg.mod.single_threaded) {
try w.writeAll("zig_threadlocal ");
}
try dg.renderTypeAndName(
w,
- .fromInterned(nav.typeOf(ip)),
+ .fromInterned(nav.resolved.?.type),
.{ .nav = dg.owner_nav.unwrap().? },
- .{ .@"const" = @"extern".is_const },
- nav.getAlignment(),
+ .{ .@"const" = nav.resolved.?.@"const" },
+ nav.resolved.?.@"align",
);
try w.writeAll(";\n");
return;
@@ -2439,15 +2431,15 @@ pub fn genDeclFwd(dg: *DeclGen, w: *Writer) Error!void {
};
// We don't bother underaligning---it's unnecessary and hurts compatibility.
- const a = nav.status.fully_resolved.alignment;
+ const a = nav.resolved.?.@"align";
if (a != .none and a.compareStrict(.gt, nav_ty.abiAlignment(zcu))) {
try w.print("zig_align({d}) ", .{a.toByteUnits().?});
}
try genDeclValueFwd(dg, w, .{
.name = .{ .nav = dg.owner_nav.unwrap().? },
- .@"const" = is_const,
- .@"threadlocal" = is_threadlocal,
+ .@"const" = nav.resolved.?.@"const",
+ .@"threadlocal" = nav.resolved.?.@"threadlocal",
.init_val = init_val,
});
}
@@ -2514,11 +2506,9 @@ pub fn genExports(dg: *DeclGen, w: *Writer, exported: Zcu.Exported, export_indic
);
try w.writeAll(";\n");
};
- const is_const = switch (ip.indexToKey(exported_val.toIntern())) {
- .func => unreachable,
- .@"extern" => |@"extern"| @"extern".is_const,
- .variable => false,
- else => true,
+ const is_const = switch (exported) {
+ .nav => |nav| ip.getNav(nav).resolved.?.@"const",
+ .uav => true,
};
for (export_indices) |export_index| {
const @"export" = export_index.ptr(zcu);
diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig
@@ -990,7 +990,6 @@ pub const CType = union(enum) {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
@@ -1279,7 +1279,7 @@ pub const Object = struct {
} }, &o.builder);
}
- if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |section|
+ if (nav.resolved.?.@"linksection".toSlice(ip)) |section|
function_index.setSection(try o.builder.string(section), &o.builder);
var deinit_wip = true;
@@ -1487,7 +1487,7 @@ pub const Object = struct {
const file = try o.getDebugFile(pt, file_scope);
const line_number = zcu.navSrcLine(func.owner_nav) + 1;
- const is_internal_linkage = ip.indexToKey(nav.status.fully_resolved.val) != .@"extern";
+ const is_internal_linkage = ip.indexToKey(nav.resolved.?.value) != .@"extern";
const debug_decl_type = try o.getDebugType(pt, fn_ty);
const subprogram = try o.builder.debugSubprogram(
@@ -1662,7 +1662,7 @@ pub const Object = struct {
.elf, .wasm => break :coff_export_flags,
.coff => |*coff| coff,
};
- if (!ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) break :coff_export_flags;
+ if (!ip.isFunctionType(ip.getNav(nav_index).resolved.?.type)) break :coff_export_flags;
const flags = &coff.lld_export_flags;
for (export_indices) |export_index| {
const name = export_index.ptr(zcu).opts.name;
@@ -2677,7 +2677,7 @@ pub const Object = struct {
const gpa = o.gpa;
const nav = ip.getNav(nav_index);
const owner_mod = zcu.navFileScope(nav_index).mod.?;
- const ty: Type = .fromInterned(nav.typeOf(ip));
+ const ty: Type = .fromInterned(nav.resolved.?.type);
const gop = try o.nav_map.getOrPut(gpa, nav_index);
if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
@@ -2692,7 +2692,7 @@ pub const Object = struct {
const function_index = try o.builder.addFunction(
try o.lowerType(pt, ty),
try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
- toLlvmAddressSpace(nav.getAddrspace(), target),
+ toLlvmAddressSpace(nav.resolved.?.@"addrspace", target),
);
gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
@@ -2809,8 +2809,8 @@ pub const Object = struct {
}
}
- if (nav.getAlignment() != .none)
- function_index.setAlignment(nav.getAlignment().toLlvm(), &o.builder);
+ if (nav.resolved.?.@"align" != .none)
+ function_index.setAlignment(nav.resolved.?.@"align".toLlvm(), &o.builder);
// Function attributes that are independent of analysis results of the function body.
try o.addCommonFnAttributes(
@@ -2951,15 +2951,12 @@ pub const Object = struct {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) {
- .unresolved => unreachable,
- .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
- .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
- .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
- else => .{ .internal, .default, false, false },
+ const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_dll_import: bool = switch (nav.resolved.?.value) {
+ .none => .{ .internal, .default, false }, // this is a source declaration which is *not* marked `extern`
+ else => |val| switch (ip.indexToKey(val)) {
+ else => .{ .internal, .default, false },
+ .@"extern" => |e| .{ e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import },
},
- // This means it's a source declaration which is not `extern`!
- .type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false },
};
const variable_index = try o.builder.addVariable(
@@ -2968,8 +2965,8 @@ pub const Object = struct {
.strong, .weak => nav.name,
.link_once => unreachable,
}.toSlice(ip)),
- try o.lowerType(pt, Type.fromInterned(nav.typeOf(ip))),
- toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
+ try o.lowerType(pt, .fromInterned(nav.resolved.?.type)),
+ toLlvmGlobalAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget()),
);
gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
@@ -2987,7 +2984,7 @@ pub const Object = struct {
.link_once => unreachable,
}, &o.builder);
variable_index.setUnnamedAddr(.default, &o.builder);
- if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
+ if (nav.resolved.?.@"threadlocal" and !zcu.navFileScope(nav_index).mod.?.single_threaded)
variable_index.setThreadLocal(.generaldynamic, &o.builder);
if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
},
@@ -3422,7 +3419,6 @@ pub const Object = struct {
// values, not types
.undef,
.simple_value,
- .variable,
.@"extern",
.func,
.int,
@@ -3553,9 +3549,7 @@ pub const Object = struct {
.false => .false,
.true => .true,
},
- .variable,
- .enum_literal,
- => unreachable, // non-runtime values
+ .enum_literal => unreachable, // non-runtime value
.@"extern" => |@"extern"| {
const function_index = try o.resolveLlvmFunction(pt, @"extern".owner_nav);
return function_index.ptrConst(&o.builder).global.toConst();
@@ -4131,7 +4125,7 @@ pub const Object = struct {
const nav = ip.getNav(nav_index);
- const nav_ty = Type.fromInterned(nav.typeOf(ip));
+ const nav_ty: Type = .fromInterned(nav.resolved.?.type);
const ptr_ty = try pt.navPtrType(nav_index);
if (nav.getExtern(ip) == null and !nav_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
@@ -4145,7 +4139,7 @@ pub const Object = struct {
const llvm_val = try o.builder.convConst(
llvm_global.toConst(),
- try o.builder.ptrType(toLlvmAddressSpace(nav.getAddrspace(), zcu.getTarget())),
+ try o.builder.ptrType(toLlvmAddressSpace(nav.resolved.?.@"addrspace", zcu.getTarget())),
);
return o.builder.convConst(llvm_val, try o.lowerType(pt, ptr_ty));
@@ -4398,14 +4392,13 @@ pub const NavGen = struct {
const ip = &zcu.intern_pool;
const nav_index = ng.nav_index;
const nav = ip.getNav(nav_index);
- const resolved = nav.status.fully_resolved;
+ const resolved = nav.resolved.?;
- const lib_name, const linkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
- .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav },
- .@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
- else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
+ const lib_name, const linkage, const visibility: Builder.Visibility, const is_dll_import, const init_val, const owner_nav = switch (ip.indexToKey(resolved.value)) {
+ else => .{ .none, .internal, .default, false, resolved.value, nav_index },
+ .@"extern" => |e| .{ e.lib_name, e.linkage, .fromSymbolVisibility(e.visibility), e.is_dll_import, .none, e.owner_nav },
};
- const ty = Type.fromInterned(nav.typeOf(ip));
+ const ty: Type = .fromInterned(nav.resolved.?.type);
if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
const function_index = try o.resolveLlvmFunction(pt, owner_nav);
@@ -4448,7 +4441,7 @@ pub const NavGen = struct {
variable_index.setAlignment(zcu.navAlignment(nav_index).toLlvm(), &o.builder);
if (resolved.@"linksection".toSlice(ip)) |section|
variable_index.setSection(try o.builder.string(section), &o.builder);
- if (is_const) variable_index.setMutability(.constant, &o.builder);
+ if (resolved.@"const") variable_index.setMutability(.constant, &o.builder);
try variable_index.setInitializer(switch (init_val) {
.none => .no_init,
else => try o.lowerValue(pt, init_val),
@@ -4457,7 +4450,7 @@ pub const NavGen = struct {
const file_scope = zcu.navFileScopeIndex(nav_index);
const mod = zcu.fileByIndex(file_scope).mod.?;
- if (is_threadlocal and !mod.single_threaded)
+ if (resolved.@"threadlocal" and !mod.single_threaded)
variable_index.setThreadLocal(.generaldynamic, &o.builder);
const line_number = zcu.navSrcLine(nav_index) + 1;
@@ -5475,7 +5468,7 @@ pub const FuncGen = struct {
_ = try self.wip.retVoid();
return;
}
- const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).typeOf(ip))).?;
+ const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).resolved.?.type)).?;
if (!ret_ty.hasRuntimeBits(zcu)) {
if (Type.fromInterned(fn_info.return_type).isError(zcu)) {
// Functions with an empty error set are emitted with an error code
@@ -5540,7 +5533,7 @@ pub const FuncGen = struct {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const ptr_ty = self.typeOf(un_op);
const ret_ty = ptr_ty.childType(zcu);
- const fn_info = zcu.typeToFunc(Type.fromInterned(ip.getNav(self.ng.nav_index).typeOf(ip))).?;
+ const fn_info = zcu.typeToFunc(.fromInterned(ip.getNav(self.ng.nav_index).resolved.?.type)).?;
if (!ret_ty.hasRuntimeBits(zcu)) {
if (Type.fromInterned(fn_info.return_type).isError(zcu)) {
// Functions with an empty error set are emitted with an error code
diff --git a/src/codegen/spirv/CodeGen.zig b/src/codegen/spirv/CodeGen.zig
@@ -256,7 +256,7 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
.global => {
const key = ip.indexToKey(val.toIntern()).@"extern";
- const storage_class = cg.module.storageClass(nav.getAddrspace());
+ const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace");
assert(storage_class != .generic); // These should be instance globals
const ty_id = try cg.resolveType(ty, .indirect);
@@ -314,64 +314,47 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
try cg.module.debugName(result_id, nav.fqn.toSlice(ip));
},
.invocation_global => {
- const maybe_init_val: ?Value = switch (ip.indexToKey(val.toIntern())) {
- .func => unreachable,
- .variable => |variable| .fromInterned(variable.init),
- .@"extern" => null,
- else => val,
- };
-
const ty_id = try cg.resolveType(ty, .indirect);
const ptr_ty_id = try cg.module.ptrType(ty_id, .function);
- if (maybe_init_val) |init_val| {
- // TODO: Combine with resolveAnonDecl?
- const void_ty_id = try cg.resolveType(.void, .direct);
- const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
-
- const initializer_id = cg.module.allocId();
- try cg.prologue.emit(gpa, .OpFunction, .{
- .id_result_type = try cg.resolveType(.void, .direct),
- .id_result = initializer_id,
- .function_control = .{},
- .function_type = initializer_proto_ty_id,
- });
+ // TODO: Combine with resolveAnonDecl?
+ const void_ty_id = try cg.resolveType(.void, .direct);
+ const initializer_proto_ty_id = try cg.module.functionType(void_ty_id, &.{});
- const root_block_id = cg.module.allocId();
- try cg.prologue.emit(gpa, .OpLabel, .{
- .id_result = root_block_id,
- });
- cg.block_label = root_block_id;
+ const initializer_id = cg.module.allocId();
+ try cg.prologue.emit(gpa, .OpFunction, .{
+ .id_result_type = try cg.resolveType(.void, .direct),
+ .id_result = initializer_id,
+ .function_control = .{},
+ .function_type = initializer_proto_ty_id,
+ });
- const val_id = try cg.constant(ty, init_val, .indirect);
- try cg.body.emit(gpa, .OpStore, .{
- .pointer = result_id,
- .object = val_id,
- });
+ const root_block_id = cg.module.allocId();
+ try cg.prologue.emit(gpa, .OpLabel, .{
+ .id_result = root_block_id,
+ });
+ cg.block_label = root_block_id;
- try cg.body.emit(gpa, .OpReturn, {});
- try cg.body.emit(gpa, .OpFunctionEnd, {});
- try cg.module.sections.functions.append(gpa, cg.prologue);
- try cg.module.sections.functions.append(gpa, cg.body);
+ const val_id = try cg.constant(ty, val, .indirect);
+ try cg.body.emit(gpa, .OpStore, .{
+ .pointer = result_id,
+ .object = val_id,
+ });
- try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
+ try cg.body.emit(gpa, .OpReturn, {});
+ try cg.body.emit(gpa, .OpFunctionEnd, {});
+ try cg.module.sections.functions.append(gpa, cg.prologue);
+ try cg.module.sections.functions.append(gpa, cg.body);
- try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
- .id_result_type = ptr_ty_id,
- .id_result = result_id,
- .set = try cg.module.importInstructionSet(.zig),
- .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
- .id_ref_4 = &.{initializer_id},
- });
- } else {
- try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
- .id_result_type = ptr_ty_id,
- .id_result = result_id,
- .set = try cg.module.importInstructionSet(.zig),
- .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
- .id_ref_4 = &.{},
- });
- }
+ try cg.module.debugNameFmt(initializer_id, "initializer of {f}", .{nav.fqn.fmt(ip)});
+
+ try cg.module.sections.globals.emit(gpa, .OpExtInst, .{
+ .id_result_type = ptr_ty_id,
+ .id_result = result_id,
+ .set = try cg.module.importInstructionSet(.zig),
+ .instruction = .{ .inst = @intFromEnum(spec.Zig.InvocationGlobal) },
+ .id_ref_4 = &.{initializer_id},
+ });
},
}
@@ -810,7 +793,6 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id {
.undef => unreachable, // handled above
- .variable,
.@"extern",
.func,
.enum_literal,
@@ -1170,12 +1152,11 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
const ip = &zcu.intern_pool;
const ty_id = try cg.resolveType(ty, .direct);
const nav = ip.getNav(nav_index);
- const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ const nav_ty: Type = .fromInterned(nav.resolved.?.type);
- switch (nav.status) {
- .unresolved => unreachable,
- .type_resolved => {}, // this is not a function or extern
- .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
+ switch (nav.resolved.?.value) {
+ .none => {}, // this is not a function or extern
+ else => |value| switch (ip.indexToKey(value)) {
.func => {
// TODO: Properly lower function pointers. For now we are going to hack around it and
// just generate an empty pointer. Function pointers are represented by a pointer to usize.
@@ -1196,7 +1177,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id {
const spv_decl_result_id = spv_decl.result_id;
assert(spv_decl.kind != .func);
- const storage_class = cg.module.storageClass(nav.getAddrspace());
+ const storage_class = cg.module.storageClass(nav.resolved.?.@"addrspace");
try cg.addFunctionDep(spv_decl_index, storage_class);
const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
diff --git a/src/codegen/spirv/Module.zig b/src/codegen/spirv/Module.zig
@@ -252,9 +252,9 @@ pub fn resolveNav(module: *Module, ip: *InternPool, nav_index: InternPool.Nav.In
if (!entry.found_existing) {
const nav = ip.getNav(nav_index);
// TODO: Extern fn?
- const kind: Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip)))
+ const kind: Decl.Kind = if (ip.isFunctionType(nav.resolved.?.type))
.func
- else switch (nav.getAddrspace()) {
+ else switch (nav.resolved.?.@"addrspace") {
.generic => .invocation_global,
else => .global,
};
diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig
@@ -575,7 +575,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
.nav_ref => |nav_ref| {
const zcu = cg.pt.zcu;
const ip = &zcu.intern_pool;
- if (ip.getNav(nav_ref.nav_index).isFn(ip)) {
+ if (ip.zigTypeTag(ip.getNav(nav_ref.nav_index).resolved.?.type) == .@"fn") {
assert(nav_ref.offset == 0);
try cg.mir_indirect_function_set.put(cg.gpa, nav_ref.nav_index, {});
try cg.addInst(.{ .tag = .func_ref, .data = .{ .nav_index = nav_ref.nav_index } });
@@ -4401,7 +4401,6 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
else => unreachable,
} },
},
- .variable,
.@"extern",
.func,
.enum_literal,
diff --git a/src/codegen/wasm/Emit.zig b/src/codegen/wasm/Emit.zig
@@ -970,7 +970,7 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32:
const ip = &zcu.intern_pool;
const gpa = comp.gpa;
const is_obj = comp.config.output_mode == .Obj;
- const nav_ty = ip.getNav(data.nav_index).typeOf(ip);
+ const nav_ty = ip.getNav(data.nav_index).resolved.?.type;
assert(!ip.isFunctionType(nav_ty));
try code.ensureUnusedCapacity(gpa, 11);
diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig
@@ -173046,7 +173046,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
.runtime_nav_ptr => {
const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
const nav = ip.getNav(ty_nav.nav);
- const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.isThreadlocal(ip);
+ const is_threadlocal = zcu.comp.config.any_non_single_threaded and nav.resolved.?.@"threadlocal";
if (is_threadlocal) switch (cg.target.ofmt) {
.elf => if (cg.mod.pic) {
@@ -179146,7 +179146,7 @@ fn genSetMem(
.off = disp,
}).compare(.gte, src_align),
.table, .rip_inst, .lazy_sym, .extern_func => unreachable,
- .nav => |nav| ip.getNav(nav).getAlignment().compare(.gte, src_align),
+ .nav => |nav| ip.getNav(nav).resolved.?.@"align".compare(.gte, src_align),
.uav => |uav| Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).compare(.gte, src_align),
})).write(self, .{
.base = base,
diff --git a/src/codegen/x86_64/Emit.zig b/src/codegen/x86_64/Emit.zig
@@ -115,33 +115,26 @@ pub fn emitMir(emit: *Emit) Error!void {
return error.EmitFail;
},
};
- break :target switch (ip.getNav(nav).status) {
- .unresolved => unreachable,
- .type_resolved => |type_resolved| .{
+ const resolved_nav = ip.getNav(nav).resolved.?;
+ if (resolved_nav.value != .none) switch (ip.indexToKey(resolved_nav.value)) {
+ .@"extern" => |@"extern"| break :target .{
.index = sym_index,
- .is_extern = false,
- .type = if (type_resolved.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
- },
- .fully_resolved => |fully_resolved| switch (ip.indexToKey(fully_resolved.val)) {
- .@"extern" => |@"extern"| .{
- .index = sym_index,
- .is_extern = switch (@"extern".visibility) {
- .default => true,
- .hidden, .protected => false,
- },
- .type = if (@"extern".is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
- .force_pcrel_direct = switch (@"extern".relocation) {
- .any => false,
- .pcrel => true,
- },
+ .is_extern = switch (@"extern".visibility) {
+ .default => true,
+ .hidden, .protected => false,
},
- .variable => |variable| .{
- .index = sym_index,
- .is_extern = false,
- .type = if (variable.is_threadlocal and comp.config.any_non_single_threaded) .tlv else .symbol,
+ .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol,
+ .force_pcrel_direct = switch (@"extern".relocation) {
+ .any => false,
+ .pcrel => true,
},
- else => .{ .index = sym_index, .is_extern = false, .type = .symbol },
},
+ else => {},
+ };
+ break :target .{
+ .index = sym_index,
+ .is_extern = false,
+ .type = if (resolved_nav.@"threadlocal" and comp.config.any_non_single_threaded) .tlv else .symbol,
};
},
.uav => |uav| .{
diff --git a/src/link.zig b/src/link.zig
@@ -781,7 +781,7 @@ pub const File = struct {
fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
assert(base.comp.zcu.?.llvm_object == null);
const nav = pt.zcu.intern_pool.getNav(nav_index);
- assert(nav.status == .fully_resolved);
+ assert(nav.resolved.?.value != .none);
switch (base.tag) {
.lld => unreachable,
.plan9 => unreachable,
diff --git a/src/link/C.zig b/src/link/C.zig
@@ -534,11 +534,11 @@ pub fn updateNav(
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- switch (ip.indexToKey(nav.status.fully_resolved.val)) {
+ switch (ip.indexToKey(nav.resolved.?.value)) {
.func => return,
.@"extern" => {},
else => {
- const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ const nav_ty: Type = .fromInterned(nav.resolved.?.type);
if (!nav_ty.hasRuntimeBits(zcu)) {
if (c.navs.fetchSwapRemove(nav_index)) |kv| {
var old_rendered = kv.value;
@@ -762,7 +762,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog
{
const unit_references = try zcu.resolveReferences();
for (c.navs.keys()) |nav| {
- const nav_val = ip.getNav(nav).status.fully_resolved.val;
+ const nav_val = ip.getNav(nav).resolved.?.value;
const check_unit: ?InternPool.AnalUnit = switch (ip.indexToKey(nav_val)) {
else => .wrap(.{ .nav_val = nav }),
.func => .wrap(.{ .func = nav_val }),
@@ -1092,8 +1092,9 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog
// NAV forward declarations
for (need_navs.keys()) |nav| {
if (c.exported_navs.contains(nav)) continue; // the export was the declaration
- if (ip.getNav(nav).getExtern(ip)) |e| {
- if (export_names.contains(e.name)) continue;
+ switch (ip.indexToKey(ip.getNav(nav).resolved.?.value)) {
+ .@"extern" => |e| if (export_names.contains(e.name)) continue,
+ else => {},
}
const fwd_decl = c.navs.getPtr(nav).?.fwd_decl;
f.appendBufAssumeCapacity(fwd_decl.get(c));
@@ -1200,7 +1201,7 @@ pub fn flush(c: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Prog
const code = c.navs.getPtr(nav).?.code;
if (code.len == 0) continue;
if (!c.exported_navs.contains(nav)) {
- const is_extern = ip.getNav(nav).getExtern(ip) != null;
+ const is_extern = ip.indexToKey(ip.getNav(nav).resolved.?.value) == .@"extern";
f.appendBufAssumeCapacity(if (is_extern) "zig_extern " else "static ");
}
f.appendBufAssumeCapacity(code.get(c));
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
@@ -1226,34 +1226,26 @@ pub fn globalSymbol(coff: *Coff, name: []const u8, lib_name: ?[]const u8) !Symbo
fn navSection(
coff: *Coff,
zcu: *Zcu,
- nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
+ nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child,
) !Symbol.Index {
const ip = &zcu.intern_pool;
const default: String, const attributes: ObjectSectionAttributes =
- switch (ip.indexToKey(nav_fr.val)) {
- else => .{ .@".rdata", .{ .read = true } },
- .variable => |variable| if (variable.is_threadlocal and
- coff.base.comp.config.any_non_single_threaded)
- .{ .@".tls$", .{ .read = true, .write = true } }
- else
- .{ .@".data", .{ .read = true, .write = true } },
- .@"extern" => |@"extern"| if (@"extern".is_threadlocal and
- coff.base.comp.config.any_non_single_threaded)
- .{ .@".tls$", .{ .read = true, .write = true } }
- else if (ip.isFunctionType(@"extern".ty))
- .{ .@".text", .{ .read = true, .execute = true } }
- else if (@"extern".is_const)
- .{ .@".rdata", .{ .read = true } }
- else
- .{ .@".data", .{ .read = true, .write = true } },
- .func => .{ .@".text", .{ .read = true, .execute = true } },
+ if (nav_resolved.@"threadlocal" and coff.base.comp.config.any_non_single_threaded) .{
+ .@".tls$", .{ .read = true, .write = true },
+ } else if (ip.isFunctionType(nav_resolved.type)) .{
+ .@".text", .{ .read = true, .execute = true },
+ } else if (nav_resolved.@"const") .{
+ .@".rdata", .{ .read = true },
+ } else .{
+ .@".data", .{ .read = true, .write = true },
};
+
return (try coff.objectSectionMapIndex(
- (try coff.getOrPutOptionalString(nav_fr.@"linksection".toSlice(ip))).unwrap() orelse default,
- switch (nav_fr.@"linksection") {
+ (try coff.getOrPutOptionalString(nav_resolved.@"linksection".toSlice(ip))).unwrap() orelse default,
+ switch (nav_resolved.@"linksection") {
.none => coff.mf.flags.block_size,
- else => switch (nav_fr.alignment) {
- .none => Type.fromInterned(ip.typeOf(nav_fr.val)).abiAlignment(zcu),
+ else => switch (nav_resolved.@"align") {
+ .none => Type.fromInterned(ip.typeOf(nav_resolved.value)).abiAlignment(zcu),
else => |alignment| alignment,
}.toStdMem(),
},
@@ -1536,20 +1528,15 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- const nav_val = nav.status.fully_resolved.val;
- const nav_init = switch (ip.indexToKey(nav_val)) {
- else => nav_val,
- .variable => |variable| variable.init,
- .@"extern", .func => .none,
- };
- if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
+ if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return;
+ if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
const nmi = try coff.navMapIndex(zcu, nav_index);
const si = nmi.symbol(coff);
const ni = ni: {
switch (si.get(coff).ni) {
.none => {
- const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
+ const sec_si = try coff.navSection(zcu, nav.resolved.?);
try coff.nodes.ensureUnusedCapacity(gpa, 1);
const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
.alignment = zcu.navAlignment(nav_index).toStdMem(),
@@ -1576,7 +1563,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
&coff.base,
pt,
zcu.navSrcLoc(nav_index),
- .fromInterned(nav_init),
+ .fromInterned(nav.resolved.?.value),
&nw.interface,
.{ .atom_index = @intFromEnum(si) },
) catch |err| switch (err) {
@@ -1587,7 +1574,7 @@ fn updateNavInner(coff: *Coff, pt: Zcu.PerThread, nav_index: InternPool.Nav.Inde
si.applyLocationRelocs(coff);
}
- if (nav.status.fully_resolved.@"linksection".unwrap()) |_| {
+ if (nav.resolved.?.@"linksection".unwrap()) |_| {
try ni.resize(&coff.mf, gpa, si.get(coff).size);
var parent_ni = ni;
while (true) {
@@ -1674,12 +1661,12 @@ fn updateFuncInner(
const ni = ni: {
switch (si.get(coff).ni) {
.none => {
- const sec_si = try coff.navSection(zcu, nav.status.fully_resolved);
+ const sec_si = try coff.navSection(zcu, nav.resolved.?);
try coff.nodes.ensureUnusedCapacity(gpa, 1);
const mod = zcu.navFileScope(func.owner_nav).mod.?;
const target = &mod.resolved_target.result;
const ni = try coff.mf.addLastChildNode(gpa, sec_si.node(coff), .{
- .alignment = switch (nav.status.fully_resolved.alignment) {
+ .alignment = switch (nav.resolved.?.@"align") {
.none => switch (mod.optimize_mode) {
.Debug,
.ReleaseSafe,
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
@@ -2681,7 +2681,7 @@ fn initWipNavInner(
} else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index });
},
.syntax => switch (ip.isFunctionType(@"extern".ty)) {
- false => continue :nav_val .{ .variable = undefined },
+ false => continue :nav_val .{ .undef = @"extern".ty },
true => {
const func_type = ip.indexToKey(@"extern".ty).func_type;
const diw = &wip_nav.debug_info.writer;
@@ -2777,7 +2777,7 @@ fn initWipNavInner(
wip_nav.func_high_pc = @intCast(diw.end);
try diw.writeInt(u32, 0, dwarf.endian);
const target = &mod.resolved_target.result;
- try diw.writeUleb128(switch (nav.status.fully_resolved.alignment) {
+ try diw.writeUleb128(switch (nav.resolved.?.@"align") {
.none => target_info.defaultFunctionAlignment(target),
else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
}.toByteUnits().?);
@@ -2845,7 +2845,7 @@ fn initWipNavInner(
.@"const" => {
const const_ty_reloc_index = try wip_nav.refForward();
try wip_nav.infoExprLoc(loc);
- try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
+ try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
ty.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
wip_nav.finishForward(const_ty_reloc_index);
@@ -2855,7 +2855,7 @@ fn initWipNavInner(
.@"var" => {
try wip_nav.refType(ty);
try wip_nav.infoExprLoc(loc);
- try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
+ try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
ty.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
},
@@ -3028,10 +3028,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const nav_src_loc = zcu.navSrcLoc(nav_index);
- const nav_val = zcu.navValue(nav_index);
const nav = ip.getNav(nav_index);
const inst_info = nav.srcInst(ip).resolveFull(ip).?;
+ const nav_val: Value = .fromInterned(nav.resolved.?.value);
const file = zcu.fileByIndex(inst_info.file);
const decl = file.zir.?.getDeclaration(inst_info.inst);
log.debug("updateComptimeNav({s}:{d}:{d} %{d} = {f})", .{
@@ -3127,9 +3127,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
.aggregate,
.un,
.bitpack,
- => .@"const",
-
- .variable => .@"var",
+ => if (nav.resolved.?.@"const") .@"const" else .@"var",
.@"extern" => unreachable,
@@ -3210,7 +3208,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
const nav_ty = nav_val.typeOf(zcu);
try wip_nav.refType(nav_ty);
try wip_nav.blockValue(nav_src_loc, nav_val);
- try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
+ try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
nav_ty.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
},
@@ -3240,7 +3238,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
.@"extern", .@"export" => nav.name,
}.toSlice(ip));
const nav_ty_reloc_index = try wip_nav.refForward();
- try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
+ try diw.writeUleb128(nav.resolved.?.@"align".toByteUnits() orelse
nav_ty.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val);
@@ -4281,7 +4279,6 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
try wip_nav.refType(.null);
},
},
- .variable => unreachable, // not a value
.int => |int| {
try wip_nav.bigIntConstValue(.{
.sdata = .sdata_comptime_value,
diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig
@@ -1113,7 +1113,7 @@ pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternP
if (!gop.found_existing) {
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const sym = self.symbol(symbol_index);
- if (ip.getNav(nav_index).isThreadlocal(ip) and zcu.comp.config.any_non_single_threaded) {
+ if (ip.getNav(nav_index).resolved.?.@"threadlocal" and zcu.comp.config.any_non_single_threaded) {
sym.flags.is_tls = true;
}
gop.value_ptr.* = .{ .symbol_index = symbol_index };
@@ -1143,9 +1143,10 @@ fn getNavShdrIndex(
const gpa = elf_file.base.comp.gpa;
const ptr_size = elf_file.ptrWidthBytes();
const ip = &zcu.intern_pool;
- const nav_val = zcu.navValue(nav_index);
+ const nav = ip.getNav(nav_index);
+ const nav_val: Value = .fromInterned(nav.resolved.?.value);
const is_func = ip.isFunctionType(nav_val.typeOf(zcu).toIntern());
- if (ip.getNav(nav_index).getLinkSection().unwrap()) |@"linksection"| {
+ if (ip.getNav(nav_index).resolved.?.@"linksection".unwrap()) |@"linksection"| {
const section_name = @"linksection".toSlice(ip);
if (elf_file.sectionByName(section_name)) |osec| {
if (is_func) {
@@ -1258,13 +1259,8 @@ fn getNavShdrIndex(
self.text_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".text"), osec);
return osec;
}
- const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
- .variable => |variable| .{ false, variable.is_threadlocal, variable.init },
- .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
- else => .{ true, false, nav_val.toIntern() },
- };
const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0;
- if (is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) {
+ if (nav.resolved.?.@"threadlocal" and elf_file.base.comp.config.any_non_single_threaded) {
const is_bss = !has_relocs and for (code) |byte| {
if (byte != 0) break false;
} else true;
@@ -1291,7 +1287,7 @@ fn getNavShdrIndex(
self.tdata_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".tdata"), osec);
return osec;
}
- if (is_const) {
+ if (nav.resolved.?.@"const") {
if (self.data_relro_index) |symbol_index|
return self.symbol(symbol_index).outputShndx(elf_file).?;
const osec = try elf_file.addSection(.{
@@ -1303,7 +1299,7 @@ fn getNavShdrIndex(
self.data_relro_index = try self.addSectionSymbol(gpa, try self.addString(gpa, ".data.rel.ro"), osec);
return osec;
}
- if (nav_init != .none and Value.fromInterned(nav_init).isUndef(zcu))
+ if (nav_val.isUndef(zcu))
return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) {
.Debug, .ReleaseSafe => {
if (self.data_index) |symbol_index|
@@ -1378,7 +1374,7 @@ fn updateNavCode(
const mod = zcu.navFileScope(nav_index).mod.?;
const target = &mod.resolved_target.result;
- const required_alignment = switch (nav.status.fully_resolved.alignment) {
+ const required_alignment = switch (nav.resolved.?.@"align") {
.none => switch (mod.optimize_mode) {
.Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
.ReleaseSmall => target_util.minFunctionAlignment(target),
@@ -1647,16 +1643,17 @@ pub fn updateNav(
log.debug("updateNav {f}({d})", .{ nav.fqn.fmt(ip), nav_index });
- const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
- .func => .none,
- .variable => |variable| variable.init,
+ switch (ip.indexToKey(nav.resolved.?.value)) {
+ else => {},
.@"extern" => |@"extern"| {
const sym_index = try self.getGlobalSymbol(
elf_file,
nav.name.toSlice(ip),
@"extern".lib_name.toSlice(ip),
);
- if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true;
+ if (nav.resolved.?.@"threadlocal" and elf_file.base.comp.config.any_non_single_threaded) {
+ self.symbol(sym_index).flags.is_tls = true;
+ }
if (self.dwarf) |*dwarf| {
var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);
defer debug_wip_nav.deinit();
@@ -1668,10 +1665,9 @@ pub fn updateNav(
}
return;
},
- else => nav.status.fully_resolved.val,
- };
+ }
- if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
+ if (Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) {
const sym_index = try self.getOrCreateMetadataForNav(zcu, nav_index);
self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);
@@ -1685,7 +1681,7 @@ pub fn updateNav(
&elf_file.base,
pt,
zcu.navSrcLoc(nav_index),
- Value.fromInterned(nav_init),
+ .fromInterned(nav.resolved.?.value),
&aw.writer,
.{ .atom_index = sym_index },
) catch |err| switch (err) {
diff --git a/src/link/Elf2.zig b/src/link/Elf2.zig
@@ -1876,32 +1876,15 @@ pub fn globalSymbol(elf: *Elf, opts: struct {
fn navType(
ip: *const InternPool,
- nav_status: @FieldType(InternPool.Nav, "status"),
+ nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child,
any_non_single_threaded: bool,
) std.elf.STT {
- return switch (nav_status) {
- .unresolved => unreachable,
- .type_resolved => |tr| if (any_non_single_threaded and tr.is_threadlocal)
- .TLS
- else if (ip.isFunctionType(tr.type))
- .FUNC
- else
- .OBJECT,
- .fully_resolved => |fr| switch (ip.indexToKey(fr.val)) {
- else => .OBJECT,
- .variable => |variable| if (any_non_single_threaded and variable.is_threadlocal)
- .TLS
- else
- .OBJECT,
- .@"extern" => |@"extern"| if (any_non_single_threaded and @"extern".is_threadlocal)
- .TLS
- else if (ip.isFunctionType(@"extern".ty))
- .FUNC
- else
- .OBJECT,
- .func => .FUNC,
- },
- };
+ return if (any_non_single_threaded and nav_resolved.@"threadlocal")
+ .TLS
+ else if (ip.isFunctionType(nav_resolved.type))
+ .FUNC
+ else
+ .OBJECT;
}
fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
if (std.mem.eql(u8, name, ".rodata") or
@@ -1917,13 +1900,13 @@ fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index {
fn navSection(
elf: *Elf,
ip: *const InternPool,
- nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"),
+ nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child,
) Symbol.Index {
- if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"|
+ if (nav_resolved.@"linksection".toSlice(ip)) |@"linksection"|
if (elf.namedSection(@"linksection")) |si| return si;
return switch (navType(
ip,
- .{ .fully_resolved = nav_fr },
+ nav_resolved,
elf.base.comp.config.any_non_single_threaded,
)) {
else => unreachable,
@@ -1940,7 +1923,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavM
const nav_gop = try elf.navs.getOrPut(gpa, nav_index);
if (!nav_gop.found_existing) nav_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{
.name = nav.fqn.toSlice(ip),
- .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
+ .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
});
return @enumFromInt(nav_gop.index);
}
@@ -1950,7 +1933,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.
if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{
.name = @"extern".name.toSlice(ip),
.lib_name = @"extern".lib_name.toSlice(ip),
- .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded),
+ .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded),
.bind = switch (@"extern".linkage) {
.internal => .LOCAL,
.strong => .GLOBAL,
@@ -2889,13 +2872,8 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- const nav_val = nav.status.fully_resolved.val;
- const nav_init = switch (ip.indexToKey(nav_val)) {
- else => nav_val,
- .variable => |variable| variable.init,
- .@"extern", .func => .none,
- };
- if (nav_init == .none or !Type.fromInterned(ip.typeOf(nav_init)).hasRuntimeBits(zcu)) return;
+ if (ip.indexToKey(nav.resolved.?.value) == .@"extern") return;
+ if (!Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) return;
const nmi = try elf.navMapIndex(zcu, nav_index);
const si = nmi.symbol(elf);
@@ -2904,7 +2882,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
switch (sym.ni) {
.none => {
try elf.nodes.ensureUnusedCapacity(gpa, 1);
- const sec_si = elf.navSection(ip, nav.status.fully_resolved);
+ const sec_si = elf.navSection(ip, nav.resolved.?);
const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
.alignment = zcu.navAlignment(nav_index).toStdMem(),
.moved = true,
@@ -2930,7 +2908,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
&elf.base,
pt,
zcu.navSrcLoc(nav_index),
- .fromInterned(nav_init),
+ .fromInterned(nav.resolved.?.value),
&nw.interface,
.{ .atom_index = @intFromEnum(si) },
) catch |err| switch (err) {
@@ -3021,11 +2999,11 @@ fn updateFuncInner(
switch (sym.ni) {
.none => {
try elf.nodes.ensureUnusedCapacity(gpa, 1);
- const sec_si = elf.navSection(ip, nav.status.fully_resolved);
+ const sec_si = elf.navSection(ip, nav.resolved.?);
const mod = zcu.navFileScope(func.owner_nav).mod.?;
const target = &mod.resolved_target.result;
const ni = try elf.mf.addLastChildNode(gpa, sec_si.node(elf), .{
- .alignment = switch (nav.status.fully_resolved.alignment) {
+ .alignment = switch (nav.resolved.?.@"align") {
.none => switch (mod.optimize_mode) {
.Debug,
.ReleaseSafe,
@@ -3677,7 +3655,7 @@ fn updateExportsInner(
const exported_si: Symbol.Index, const @"type": std.elf.STT = switch (exported) {
.nav => |nav| .{
try elf.navSymbol(zcu, nav),
- navType(ip, ip.getNav(nav).status, elf.base.comp.config.any_non_single_threaded),
+ navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded),
},
.uav => |uav| .{ @enumFromInt(switch (try elf.lowerUav(
pt,
diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig
@@ -877,15 +877,14 @@ pub fn updateNav(
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
- .func => .none,
- .variable => |variable| variable.init,
+ switch (ip.indexToKey(nav.resolved.?.value)) {
+ else => {},
.@"extern" => |@"extern"| {
// Extern variable gets a __got entry only
const name = @"extern".name.toSlice(ip);
const lib_name = @"extern".lib_name.toSlice(ip);
const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
- if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
+ if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
if (self.dwarf) |*dwarf| {
var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);
defer debug_wip_nav.deinit();
@@ -897,10 +896,9 @@ pub fn updateNav(
}
return;
},
- else => nav.status.fully_resolved.val,
- };
+ }
- if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
+ if (Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) {
const sym_index = try self.getOrCreateMetadataForNav(macho_file, nav_index);
self.symbols.items[sym_index].getAtom(macho_file).?.freeRelocs(macho_file);
@@ -914,7 +912,7 @@ pub fn updateNav(
&macho_file.base,
pt,
zcu.navSrcLoc(nav_index),
- Value.fromInterned(nav_init),
+ .fromInterned(nav.resolved.?.value),
&aw.writer,
.{ .atom_index = sym_index },
) catch |err| switch (err) {
@@ -959,7 +957,7 @@ fn updateNavCode(
const mod = zcu.navFileScope(nav_index).mod.?;
const target = &mod.resolved_target.result;
- const required_alignment = switch (nav.status.fully_resolved.alignment) {
+ const required_alignment = switch (nav.resolved.?.@"align") {
.none => switch (mod.optimize_mode) {
.Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
.ReleaseSmall => target_util.minFunctionAlignment(target),
@@ -1167,14 +1165,10 @@ fn getNavOutputSection(
) error{OutOfMemory}!u8 {
_ = self;
const ip = &zcu.intern_pool;
- const nav_val = zcu.navValue(nav_index);
+ const nav = ip.getNav(nav_index);
+ const nav_val: Value = .fromInterned(nav.resolved.?.value);
if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return macho_file.zig_text_sect_index.?;
- const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
- .variable => |variable| .{ false, variable.is_threadlocal, variable.init },
- .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
- else => .{ true, false, nav_val.toIntern() },
- };
- if (is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) {
+ if (nav.resolved.?.@"threadlocal" and macho_file.base.comp.config.any_non_single_threaded) {
for (code) |byte| {
if (byte != 0) break;
} else return macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection(
@@ -1188,8 +1182,8 @@ fn getNavOutputSection(
.{ .flags = macho.S_THREAD_LOCAL_REGULAR },
);
}
- if (is_const) return macho_file.zig_const_sect_index.?;
- if (nav_init != .none and Value.fromInterned(nav_init).isUndef(zcu))
+ if (nav.resolved.?.@"const") return macho_file.zig_const_sect_index.?;
+ if (nav_val.isUndef(zcu))
return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) {
.Debug, .ReleaseSafe => macho_file.zig_data_sect_index.?,
.ReleaseFast, .ReleaseSmall => macho_file.zig_bss_sect_index.?,
@@ -1550,7 +1544,7 @@ fn isThreadlocal(macho_file: *MachO, nav_index: InternPool.Nav.Index) bool {
if (!macho_file.base.comp.config.any_non_single_threaded)
return false;
const ip = &macho_file.base.comp.zcu.?.intern_pool;
- return ip.getNav(nav_index).isThreadlocal(ip);
+ return ip.getNav(nav_index).resolved.?.@"threadlocal";
}
fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig
@@ -189,7 +189,7 @@ pub fn updateExports(
@panic("TODO: implement Linker linker code for exporting a constant value");
},
};
- const nav_ty = ip.getNav(nav_index).typeOf(ip);
+ const nav_ty = ip.getNav(nav_index).resolved.?.type;
const target = zcu.getTarget();
if (ip.isFunctionType(nav_ty)) {
const spv_decl_index = try linker.module.resolveNav(ip, nav_index);
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
@@ -420,7 +420,7 @@ pub const OutputFunctionIndex = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav = ip.getNav(nav_index);
- return fromIpIndex(wasm, nav.status.fully_resolved.val);
+ return fromIpIndex(wasm, nav.resolved.?.value);
}
pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex {
@@ -1022,7 +1022,7 @@ pub const FunctionImport = extern struct {
pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
- return fromIpIndex(wasm, ip.getNav(nav_index).status.fully_resolved.val);
+ return fromIpIndex(wasm, ip.getNav(nav_index).resolved.?.value);
}
pub fn fromZcuFunc(wasm: *const Wasm, i: ZcuFunc.Index) Resolution {
@@ -1885,7 +1885,7 @@ pub const DataSegmentId = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav = ip.getNav(i.key(wasm).*);
- if (nav.isThreadlocal(ip)) return .tls;
+ if (nav.resolved.?.@"threadlocal") return .tls;
const code = i.value(wasm).code;
return if (code.off == .none) .zero else .data;
},
@@ -1908,7 +1908,7 @@ pub const DataSegmentId = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav = ip.getNav(i.key(wasm).*);
- return nav.isThreadlocal(ip);
+ return nav.resolved.?.@"threadlocal";
},
};
}
@@ -1934,7 +1934,7 @@ pub const DataSegmentId = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav = ip.getNav(i.key(wasm).*);
- return nav.getLinkSection().toSlice(ip) orelse switch (category(id, wasm)) {
+ return nav.resolved.?.@"linksection".toSlice(ip) orelse switch (category(id, wasm)) {
.tls => ".tdata",
.data => ".data",
.zero => ".bss",
@@ -1962,9 +1962,9 @@ pub const DataSegmentId = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav = ip.getNav(i.key(wasm).*);
- const explicit = nav.getAlignment();
+ const explicit = nav.resolved.?.@"align";
if (explicit != .none) return explicit;
- const ty: Zcu.Type = .fromInterned(nav.typeOf(ip));
+ const ty: Zcu.Type = .fromInterned(nav.resolved.?.type);
const result = ty.abiAlignment(zcu);
assert(result != .none);
return result;
@@ -2269,7 +2269,7 @@ pub const ZcuImportIndex = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav_index = index.ptr(wasm).*;
- const ext = ip.getNav(nav_index).getResolvedExtern(ip).?;
+ const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern";
const name_slice = ext.name.toSlice(ip);
return wasm.getExistingString(name_slice).?;
}
@@ -2278,7 +2278,7 @@ pub const ZcuImportIndex = enum(u32) {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
const nav_index = index.ptr(wasm).*;
- const ext = ip.getNav(nav_index).getResolvedExtern(ip).?;
+ const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern";
const lib_name = ext.lib_name.toSlice(ip) orelse return .none;
return wasm.getExistingString(lib_name).?.toOptional();
}
@@ -2289,7 +2289,7 @@ pub const ZcuImportIndex = enum(u32) {
const zcu = comp.zcu.?;
const ip = &zcu.intern_pool;
const nav_index = index.ptr(wasm).*;
- const ext = ip.getNav(nav_index).getResolvedExtern(ip).?;
+ const ext = ip.indexToKey(ip.getNav(nav_index).resolved.?.value).@"extern";
const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;
return getExistingFunctionType(wasm, fn_info.cc, fn_info.param_types.get(ip), .fromInterned(fn_info.return_type), target).?;
}
@@ -2381,7 +2381,7 @@ pub const FunctionImportId = enum(u32) {
.zcu_import => |i| {
const zcu = wasm.base.comp.zcu.?;
const ip = &zcu.intern_pool;
- const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;
+ const ext = ip.indexToKey(ip.getNav(i.ptr(wasm).*).resolved.?.value).@"extern";
return ext.linkage != .weak and ext.lib_name != .none;
},
};
@@ -3288,7 +3288,8 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
const is_obj = comp.config.output_mode == .Obj;
const target = &comp.root_mod.resolved_target.result;
- const nav_init, const chased_nav_index = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
+ switch (ip.indexToKey(nav.resolved.?.value)) {
+ else => {},
.func => return, // global const which is a function alias
.@"extern" => |ext| {
if (is_obj) {
@@ -3302,7 +3303,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
try wasm.function_imports.ensureUnusedCapacity(gpa, 1);
try wasm.data_imports.ensureUnusedCapacity(gpa, 1);
const zcu_import = wasm.addZcuImportReserved(ext.owner_nav);
- if (ip.isFunctionType(nav.typeOf(ip))) {
+ if (ip.isFunctionType(nav.resolved.?.type)) {
wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm));
// Ensure there is a corresponding function type table entry.
const fn_info = zcu.typeToFunc(.fromInterned(ext.ty)).?;
@@ -3312,31 +3313,29 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
}
return;
},
- .variable => |variable| .{ variable.init, variable.owner_nav },
- else => .{ nav.status.fully_resolved.val, nav_index },
- };
- //log.debug("updateNav {f} {d}", .{ nav.fqn.fmt(ip), chased_nav_index });
- assert(!wasm.imports.contains(chased_nav_index));
+ }
+ //log.debug("updateNav {f} {d}", .{ nav.fqn.fmt(ip), nav_index });
+ assert(!wasm.imports.contains(nav_index));
- if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
+ if (!Zcu.Type.fromInterned(nav.resolved.?.type).hasRuntimeBits(zcu)) {
if (is_obj) {
- assert(!wasm.navs_obj.contains(chased_nav_index));
+ assert(!wasm.navs_obj.contains(nav_index));
} else {
- assert(!wasm.navs_exe.contains(chased_nav_index));
+ assert(!wasm.navs_exe.contains(nav_index));
}
return;
}
if (is_obj) {
const zcu_data_starts: ZcuDataStarts = .initObj(wasm);
- const navs_i = try refNavObj(wasm, chased_nav_index);
- const zcu_data = try lowerZcuData(wasm, pt, nav_init);
+ const navs_i = try refNavObj(wasm, nav_index);
+ const zcu_data = try lowerZcuData(wasm, pt, nav.resolved.?.value);
navs_i.value(wasm).* = zcu_data;
try zcu_data_starts.finishObj(wasm, pt);
} else {
const zcu_data_starts: ZcuDataStarts = .initExe(wasm);
- const navs_i = try refNavExe(wasm, chased_nav_index);
- const zcu_data = try lowerZcuData(wasm, pt, nav_init);
+ const navs_i = try refNavExe(wasm, nav_index);
+ const zcu_data = try lowerZcuData(wasm, pt, nav.resolved.?.value);
navs_i.value(wasm).code = zcu_data.code;
try zcu_data_starts.finishExe(wasm, pt);
}
@@ -4173,9 +4172,8 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
}
const zcu = comp.zcu.?;
const ip = &zcu.intern_pool;
- const nav = ip.getNav(nav_index);
- if (nav.getResolvedExtern(ip)) |ext| {
- if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| {
+ switch (ip.indexToKey(ip.getNav(nav_index).resolved.?.value)) {
+ .@"extern" => |ext| if (wasm.getExistingString(ext.name.toSlice(ip))) |symbol_name| {
if (wasm.object_data_imports.getPtr(symbol_name)) |import| {
switch (import.resolution.unpack(wasm)) {
.unresolved => unreachable,
@@ -4195,7 +4193,8 @@ pub fn navAddr(wasm: *Wasm, nav_index: InternPool.Nav.Index) u32 {
.nav_obj => @panic("TODO"),
}
}
- }
+ },
+ else => {},
}
// Otherwise it's a zero bit type; any address will do.
return 0;
diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig
@@ -211,7 +211,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
}
for (wasm.nav_exports.keys(), wasm.nav_exports.values()) |*nav_export, export_index| {
- if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {
+ if (ip.isFunctionType(ip.getNav(nav_export.nav_index).resolved.?.type)) {
log.debug("flush export '{s}' nav={d}", .{ nav_export.name.slice(wasm), nav_export.nav_index });
const function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?;
const explicit = f.missing_exports.swapRemove(nav_export.name);
diff --git a/src/print_value.zig b/src/print_value.zig
@@ -74,7 +74,6 @@ pub fn print(
.@"unreachable",
=> try writer.writeAll(@tagName(simple_value)),
},
- .variable => try writer.writeAll("(variable)"),
.@"extern" => |e| try writer.print("(extern '{f}')", .{e.name.fmt(ip)}),
.func => |func| try writer.print("(function '{f}')", .{ip.getNav(func.owner_nav).name.fmt(ip)}),
.int => |int| switch (int.storage) {