mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
Merge pull request #22303 from mlugg/131-new
compiler: analyze type and value of global declarations separately
This commit is contained in:
commit
497592c9b4
File diff suppressed because it is too large
Load Diff
@ -1868,10 +1868,6 @@ pub const Inst = struct {
|
||||
/// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
|
||||
/// `noreturn` instructions may not go here; they must be part of the main `Tag` enum.
|
||||
pub const Extended = enum(u16) {
|
||||
/// Declares a global variable.
|
||||
/// `operand` is payload index to `ExtendedVar`.
|
||||
/// `small` is `ExtendedVar.Small`.
|
||||
variable,
|
||||
/// A struct type definition. Contains references to ZIR instructions for
|
||||
/// the field types, defaults, and alignments.
|
||||
/// `operand` is payload index to `StructDecl`.
|
||||
@ -2493,26 +2489,25 @@ pub const Inst = struct {
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. lib_name: NullTerminatedString, // null terminated string index, if has_lib_name is set
|
||||
/// if (has_cc_ref and !has_cc_body) {
|
||||
/// 1. cc: Ref,
|
||||
/// 0. cc: Ref,
|
||||
/// }
|
||||
/// if (has_cc_body) {
|
||||
/// 2. cc_body_len: u32
|
||||
/// 3. cc_body: u32 // for each cc_body_len
|
||||
/// 1. cc_body_len: u32
|
||||
/// 2. cc_body: u32 // for each cc_body_len
|
||||
/// }
|
||||
/// if (has_ret_ty_ref and !has_ret_ty_body) {
|
||||
/// 4. ret_ty: Ref,
|
||||
/// 3. ret_ty: Ref,
|
||||
/// }
|
||||
/// if (has_ret_ty_body) {
|
||||
/// 5. ret_ty_body_len: u32
|
||||
/// 6. ret_ty_body: u32 // for each ret_ty_body_len
|
||||
/// 4. ret_ty_body_len: u32
|
||||
/// 5. ret_ty_body: u32 // for each ret_ty_body_len
|
||||
/// }
|
||||
/// 7. noalias_bits: u32 // if has_any_noalias
|
||||
/// 6. noalias_bits: u32 // if has_any_noalias
|
||||
/// - each bit starting with LSB corresponds to parameter indexes
|
||||
/// 8. body: Index // for each body_len
|
||||
/// 9. src_locs: Func.SrcLocs // if body_len != 0
|
||||
/// 10. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
|
||||
/// 7. body: Index // for each body_len
|
||||
/// 8. src_locs: Func.SrcLocs // if body_len != 0
|
||||
/// 9. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
|
||||
pub const FuncFancy = struct {
|
||||
/// Points to the block that contains the param instructions for this function.
|
||||
/// If this is a `declaration`, it refers to the declaration's value body.
|
||||
@ -2522,38 +2517,16 @@ pub const Inst = struct {
|
||||
|
||||
/// If both has_cc_ref and has_cc_body are false, it means auto calling convention.
|
||||
/// If both has_ret_ty_ref and has_ret_ty_body are false, it means void return type.
|
||||
pub const Bits = packed struct {
|
||||
pub const Bits = packed struct(u32) {
|
||||
is_var_args: bool,
|
||||
is_inferred_error: bool,
|
||||
is_test: bool,
|
||||
is_extern: bool,
|
||||
is_noinline: bool,
|
||||
has_cc_ref: bool,
|
||||
has_cc_body: bool,
|
||||
has_ret_ty_ref: bool,
|
||||
has_ret_ty_body: bool,
|
||||
has_lib_name: bool,
|
||||
has_any_noalias: bool,
|
||||
_: u21 = undefined,
|
||||
};
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. lib_name: NullTerminatedString, // null terminated string index, if has_lib_name is set
|
||||
/// 1. align: Ref, // if has_align is set
|
||||
/// 2. init: Ref // if has_init is set
|
||||
/// The source node is obtained from the containing `block_inline`.
|
||||
pub const ExtendedVar = struct {
|
||||
var_type: Ref,
|
||||
|
||||
pub const Small = packed struct {
|
||||
has_lib_name: bool,
|
||||
has_align: bool,
|
||||
has_init: bool,
|
||||
is_extern: bool,
|
||||
is_const: bool,
|
||||
is_threadlocal: bool,
|
||||
_: u10 = undefined,
|
||||
_: u24 = undefined,
|
||||
};
|
||||
};
|
||||
|
||||
@ -2582,39 +2555,301 @@ pub const Inst = struct {
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// 0. align_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `align`
|
||||
/// 1. linksection_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `linksection`
|
||||
/// 2. addrspace_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `addrspace`
|
||||
/// 3. value_body_inst: Zir.Inst.Index
|
||||
/// - for each `value_body_len`
|
||||
/// 0. name: NullTerminatedString // if `flags.id.hasName()`
|
||||
/// 1. lib_name: NullTerminatedString // if `flags.id.hasLibName()`
|
||||
/// 2. type_body_len: u32 // if `flags.id.hasTypeBody()`
|
||||
/// 3. align_body_len: u32 // if `flags.id.hasSpecialBodies()`
|
||||
/// 4. linksection_body_len: u32 // if `flags.id.hasSpecialBodies()`
|
||||
/// 5. addrspace_body_len: u32 // if `flags.id.hasSpecialBodies()`
|
||||
/// 6. value_body_len: u32 // if `flags.id.hasValueBody()`
|
||||
/// 7. type_body_inst: Zir.Inst.Index
|
||||
/// - for each `type_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 4. align_body_inst: Zir.Inst.Index
|
||||
/// 8. align_body_inst: Zir.Inst.Index
|
||||
/// - for each `align_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 5. linksection_body_inst: Zir.Inst.Index
|
||||
/// 9. linksection_body_inst: Zir.Inst.Index
|
||||
/// - for each `linksection_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 6. addrspace_body_inst: Zir.Inst.Index
|
||||
/// 10. addrspace_body_inst: Zir.Inst.Index
|
||||
/// - for each `addrspace_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// 11. value_body_inst: Zir.Inst.Index
|
||||
/// - for each `value_body_len`
|
||||
/// - body to be exited via `break_inline` to this `declaration` instruction
|
||||
/// - within this body, the `declaration` instruction refers to the resolved type from the type body
|
||||
pub const Declaration = struct {
|
||||
// These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
|
||||
src_hash_0: u32,
|
||||
src_hash_1: u32,
|
||||
src_hash_2: u32,
|
||||
src_hash_3: u32,
|
||||
/// The name of this `Decl`. Also indicates whether it is a test, comptime block, etc.
|
||||
name: Name,
|
||||
src_line: u32,
|
||||
src_column: u32,
|
||||
flags: Flags,
|
||||
// These fields should be concatenated and reinterpreted as a `Flags`.
|
||||
flags_0: u32,
|
||||
flags_1: u32,
|
||||
|
||||
pub const Flags = packed struct(u32) {
|
||||
value_body_len: u28,
|
||||
pub const Unwrapped = struct {
|
||||
pub const Kind = enum {
|
||||
unnamed_test,
|
||||
@"test",
|
||||
decltest,
|
||||
@"comptime",
|
||||
@"usingnamespace",
|
||||
@"const",
|
||||
@"var",
|
||||
};
|
||||
|
||||
pub const Linkage = enum {
|
||||
normal,
|
||||
@"extern",
|
||||
@"export",
|
||||
};
|
||||
|
||||
src_node: Ast.Node.Index,
|
||||
|
||||
src_line: u32,
|
||||
src_column: u32,
|
||||
|
||||
kind: Kind,
|
||||
/// Always `.empty` for `kind` of `unnamed_test`, `.@"comptime"`, `.@"usingnamespace"`.
|
||||
name: NullTerminatedString,
|
||||
/// Always `false` for `kind` of `unnamed_test`, `.@"test"`, `.decltest`, `.@"comptime"`.
|
||||
is_pub: bool,
|
||||
is_export: bool,
|
||||
test_is_decltest: bool,
|
||||
has_align_linksection_addrspace: bool,
|
||||
/// Always `false` for `kind != .@"var"`.
|
||||
is_threadlocal: bool,
|
||||
/// Always `.normal` for `kind != .@"const" and kind != .@"var"`.
|
||||
linkage: Linkage,
|
||||
/// Always `.empty` for `linkage != .@"extern"`.
|
||||
lib_name: NullTerminatedString,
|
||||
|
||||
/// Always populated for `linkage == .@"extern".
|
||||
type_body: ?[]const Inst.Index,
|
||||
align_body: ?[]const Inst.Index,
|
||||
linksection_body: ?[]const Inst.Index,
|
||||
addrspace_body: ?[]const Inst.Index,
|
||||
/// Always populated for `linkage != .@"extern".
|
||||
value_body: ?[]const Inst.Index,
|
||||
};
|
||||
|
||||
pub const Flags = packed struct(u64) {
|
||||
src_line: u30,
|
||||
src_column: u29,
|
||||
id: Id,
|
||||
|
||||
pub const Id = enum(u5) {
|
||||
unnamed_test,
|
||||
@"test",
|
||||
decltest,
|
||||
@"comptime",
|
||||
|
||||
@"usingnamespace",
|
||||
pub_usingnamespace,
|
||||
|
||||
const_simple,
|
||||
const_typed,
|
||||
@"const",
|
||||
pub_const_simple,
|
||||
pub_const_typed,
|
||||
pub_const,
|
||||
|
||||
extern_const_simple,
|
||||
extern_const,
|
||||
pub_extern_const_simple,
|
||||
pub_extern_const,
|
||||
|
||||
export_const,
|
||||
pub_export_const,
|
||||
|
||||
var_simple,
|
||||
@"var",
|
||||
var_threadlocal,
|
||||
pub_var_simple,
|
||||
pub_var,
|
||||
pub_var_threadlocal,
|
||||
|
||||
extern_var,
|
||||
extern_var_threadlocal,
|
||||
pub_extern_var,
|
||||
pub_extern_var_threadlocal,
|
||||
|
||||
export_var,
|
||||
export_var_threadlocal,
|
||||
pub_export_var,
|
||||
pub_export_var_threadlocal,
|
||||
|
||||
pub fn hasName(id: Id) bool {
|
||||
return switch (id) {
|
||||
.unnamed_test,
|
||||
.@"comptime",
|
||||
.@"usingnamespace",
|
||||
.pub_usingnamespace,
|
||||
=> false,
|
||||
else => true,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hasLibName(id: Id) bool {
|
||||
return switch (id) {
|
||||
.extern_const,
|
||||
.pub_extern_const,
|
||||
.extern_var,
|
||||
.extern_var_threadlocal,
|
||||
.pub_extern_var,
|
||||
.pub_extern_var_threadlocal,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hasTypeBody(id: Id) bool {
|
||||
return switch (id) {
|
||||
.unnamed_test,
|
||||
.@"test",
|
||||
.decltest,
|
||||
.@"comptime",
|
||||
.@"usingnamespace",
|
||||
.pub_usingnamespace,
|
||||
=> false, // these constructs are untyped
|
||||
.const_simple,
|
||||
.pub_const_simple,
|
||||
.var_simple,
|
||||
.pub_var_simple,
|
||||
=> false, // these reprs omit type bodies
|
||||
else => true,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hasValueBody(id: Id) bool {
|
||||
return switch (id) {
|
||||
.extern_const_simple,
|
||||
.extern_const,
|
||||
.pub_extern_const_simple,
|
||||
.pub_extern_const,
|
||||
.extern_var,
|
||||
.extern_var_threadlocal,
|
||||
.pub_extern_var,
|
||||
.pub_extern_var_threadlocal,
|
||||
=> false, // externs do not have values
|
||||
else => true,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn hasSpecialBodies(id: Id) bool {
|
||||
return switch (id) {
|
||||
.unnamed_test,
|
||||
.@"test",
|
||||
.decltest,
|
||||
.@"comptime",
|
||||
.@"usingnamespace",
|
||||
.pub_usingnamespace,
|
||||
=> false, // these constructs are untyped
|
||||
.const_simple,
|
||||
.const_typed,
|
||||
.pub_const_simple,
|
||||
.pub_const_typed,
|
||||
.extern_const_simple,
|
||||
.pub_extern_const_simple,
|
||||
.var_simple,
|
||||
.pub_var_simple,
|
||||
=> false, // these reprs omit special bodies
|
||||
else => true,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn linkage(id: Id) Declaration.Unwrapped.Linkage {
|
||||
return switch (id) {
|
||||
.extern_const_simple,
|
||||
.extern_const,
|
||||
.pub_extern_const_simple,
|
||||
.pub_extern_const,
|
||||
.extern_var,
|
||||
.extern_var_threadlocal,
|
||||
.pub_extern_var,
|
||||
.pub_extern_var_threadlocal,
|
||||
=> .@"extern",
|
||||
.export_const,
|
||||
.pub_export_const,
|
||||
.export_var,
|
||||
.export_var_threadlocal,
|
||||
.pub_export_var,
|
||||
.pub_export_var_threadlocal,
|
||||
=> .@"export",
|
||||
else => .normal,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn kind(id: Id) Declaration.Unwrapped.Kind {
|
||||
return switch (id) {
|
||||
.unnamed_test => .unnamed_test,
|
||||
.@"test" => .@"test",
|
||||
.decltest => .decltest,
|
||||
.@"comptime" => .@"comptime",
|
||||
.@"usingnamespace", .pub_usingnamespace => .@"usingnamespace",
|
||||
.const_simple,
|
||||
.const_typed,
|
||||
.@"const",
|
||||
.pub_const_simple,
|
||||
.pub_const_typed,
|
||||
.pub_const,
|
||||
.extern_const_simple,
|
||||
.extern_const,
|
||||
.pub_extern_const_simple,
|
||||
.pub_extern_const,
|
||||
.export_const,
|
||||
.pub_export_const,
|
||||
=> .@"const",
|
||||
.var_simple,
|
||||
.@"var",
|
||||
.var_threadlocal,
|
||||
.pub_var_simple,
|
||||
.pub_var,
|
||||
.pub_var_threadlocal,
|
||||
.extern_var,
|
||||
.extern_var_threadlocal,
|
||||
.pub_extern_var,
|
||||
.pub_extern_var_threadlocal,
|
||||
.export_var,
|
||||
.export_var_threadlocal,
|
||||
.pub_export_var,
|
||||
.pub_export_var_threadlocal,
|
||||
=> .@"var",
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isPub(id: Id) bool {
|
||||
return switch (id) {
|
||||
.pub_usingnamespace,
|
||||
.pub_const_simple,
|
||||
.pub_const_typed,
|
||||
.pub_const,
|
||||
.pub_extern_const_simple,
|
||||
.pub_extern_const,
|
||||
.pub_export_const,
|
||||
.pub_var_simple,
|
||||
.pub_var,
|
||||
.pub_var_threadlocal,
|
||||
.pub_extern_var,
|
||||
.pub_extern_var_threadlocal,
|
||||
.pub_export_var,
|
||||
.pub_export_var_threadlocal,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isThreadlocal(id: Id) bool {
|
||||
return switch (id) {
|
||||
.var_threadlocal,
|
||||
.pub_var_threadlocal,
|
||||
.extern_var_threadlocal,
|
||||
.pub_extern_var_threadlocal,
|
||||
.export_var_threadlocal,
|
||||
.pub_export_var_threadlocal,
|
||||
=> true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const Name = enum(u32) {
|
||||
@ -2647,17 +2882,24 @@ pub const Inst = struct {
|
||||
};
|
||||
|
||||
pub const Bodies = struct {
|
||||
value_body: []const Index,
|
||||
type_body: ?[]const Index,
|
||||
align_body: ?[]const Index,
|
||||
linksection_body: ?[]const Index,
|
||||
addrspace_body: ?[]const Index,
|
||||
value_body: ?[]const Index,
|
||||
};
|
||||
|
||||
pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies {
|
||||
var extra_index: u32 = extra_end;
|
||||
const value_body_len = declaration.flags.value_body_len;
|
||||
const value_body_len = declaration.value_body_len;
|
||||
const type_body_len: u32 = len: {
|
||||
if (!declaration.flags().kind.hasTypeBody()) break :len 0;
|
||||
const len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :len len;
|
||||
};
|
||||
const align_body_len, const linksection_body_len, const addrspace_body_len = lens: {
|
||||
if (!declaration.flags.has_align_linksection_addrspace) {
|
||||
if (!declaration.flags.kind.hasSpecialBodies()) {
|
||||
break :lens .{ 0, 0, 0 };
|
||||
}
|
||||
const lens = zir.extra[extra_index..][0..3].*;
|
||||
@ -2665,21 +2907,30 @@ pub const Inst = struct {
|
||||
break :lens lens;
|
||||
};
|
||||
return .{
|
||||
.value_body = b: {
|
||||
defer extra_index += value_body_len;
|
||||
break :b zir.bodySlice(extra_index, value_body_len);
|
||||
.type_body = if (type_body_len == 0) null else b: {
|
||||
const b = zir.bodySlice(extra_index, type_body_len);
|
||||
extra_index += type_body_len;
|
||||
break :b b;
|
||||
},
|
||||
.align_body = if (align_body_len == 0) null else b: {
|
||||
defer extra_index += align_body_len;
|
||||
break :b zir.bodySlice(extra_index, align_body_len);
|
||||
const b = zir.bodySlice(extra_index, align_body_len);
|
||||
extra_index += align_body_len;
|
||||
break :b b;
|
||||
},
|
||||
.linksection_body = if (linksection_body_len == 0) null else b: {
|
||||
defer extra_index += linksection_body_len;
|
||||
break :b zir.bodySlice(extra_index, linksection_body_len);
|
||||
const b = zir.bodySlice(extra_index, linksection_body_len);
|
||||
extra_index += linksection_body_len;
|
||||
break :b b;
|
||||
},
|
||||
.addrspace_body = if (addrspace_body_len == 0) null else b: {
|
||||
defer extra_index += addrspace_body_len;
|
||||
break :b zir.bodySlice(extra_index, addrspace_body_len);
|
||||
const b = zir.bodySlice(extra_index, addrspace_body_len);
|
||||
extra_index += addrspace_body_len;
|
||||
break :b b;
|
||||
},
|
||||
.value_body = if (value_body_len == 0) null else b: {
|
||||
const b = zir.bodySlice(extra_index, value_body_len);
|
||||
extra_index += value_body_len;
|
||||
break :b b;
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -3711,18 +3962,18 @@ pub const DeclContents = struct {
|
||||
pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void {
|
||||
contents.clear();
|
||||
|
||||
const declaration, const extra_end = zir.getDeclaration(decl_inst);
|
||||
const bodies = declaration.getBodies(extra_end, zir);
|
||||
const decl = zir.getDeclaration(decl_inst);
|
||||
|
||||
// `defer` instructions duplicate the same body arbitrarily many times, but we only want to traverse
|
||||
// their contents once per defer. So, we store the extra index of the body here to deduplicate.
|
||||
var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
|
||||
defer found_defers.deinit(gpa);
|
||||
|
||||
try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
|
||||
if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (decl.type_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (decl.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (decl.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (decl.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
if (decl.value_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
|
||||
}
|
||||
|
||||
/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
|
||||
@ -3991,7 +4242,6 @@ fn findTrackableInner(
|
||||
.value_placeholder => unreachable,
|
||||
|
||||
// Once again, we start with the boring tags.
|
||||
.variable,
|
||||
.this,
|
||||
.ret_addr,
|
||||
.builtin_src,
|
||||
@ -4237,7 +4487,6 @@ fn findTrackableInner(
|
||||
const inst_data = datas[@intFromEnum(inst)].pl_node;
|
||||
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
|
||||
var extra_index: usize = extra.end;
|
||||
extra_index += @intFromBool(extra.data.bits.has_lib_name);
|
||||
|
||||
if (extra.data.bits.has_cc_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
@ -4470,8 +4719,7 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
|
||||
return zir.bodySlice(param_block.end, param_block.data.body_len);
|
||||
},
|
||||
.declaration => {
|
||||
const decl, const extra_end = zir.getDeclaration(param_block_index);
|
||||
return decl.getBodies(extra_end, zir).value_body;
|
||||
return zir.getDeclaration(param_block_index).value_body.?;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
@ -4526,7 +4774,6 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
var ret_ty_ref: Inst.Ref = .void_type;
|
||||
var ret_ty_body: []const Inst.Index = &.{};
|
||||
|
||||
extra_index += @intFromBool(extra.data.bits.has_lib_name);
|
||||
if (extra.data.bits.has_cc_body) {
|
||||
extra_index += zir.extra[extra_index] + 1;
|
||||
} else if (extra.data.bits.has_cc_ref) {
|
||||
@ -4555,17 +4802,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const param_body = switch (tags[@intFromEnum(info.param_block)]) {
|
||||
.block, .block_comptime, .block_inline => param_body: {
|
||||
const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
|
||||
break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
|
||||
},
|
||||
.declaration => param_body: {
|
||||
const decl, const extra_end = zir.getDeclaration(info.param_block);
|
||||
break :param_body decl.getBodies(extra_end, zir).value_body;
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
const param_body = zir.getParamBody(fn_inst);
|
||||
var total_params_len: u32 = 0;
|
||||
for (param_body) |inst| {
|
||||
switch (tags[@intFromEnum(inst)]) {
|
||||
@ -4585,13 +4822,74 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } {
|
||||
pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) Inst.Declaration.Unwrapped {
|
||||
assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration);
|
||||
const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].declaration;
|
||||
const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
|
||||
|
||||
const flags_vals: [2]u32 = .{ extra.data.flags_0, extra.data.flags_1 };
|
||||
const flags: Inst.Declaration.Flags = @bitCast(flags_vals);
|
||||
|
||||
var extra_index = extra.end;
|
||||
|
||||
const name: NullTerminatedString = if (flags.id.hasName()) name: {
|
||||
const name = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :name @enumFromInt(name);
|
||||
} else .empty;
|
||||
|
||||
const lib_name: NullTerminatedString = if (flags.id.hasLibName()) lib_name: {
|
||||
const lib_name = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :lib_name @enumFromInt(lib_name);
|
||||
} else .empty;
|
||||
|
||||
const type_body_len: u32 = if (flags.id.hasTypeBody()) len: {
|
||||
const len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :len len;
|
||||
} else 0;
|
||||
const align_body_len: u32, const linksection_body_len: u32, const addrspace_body_len: u32 = lens: {
|
||||
if (!flags.id.hasSpecialBodies()) break :lens .{ 0, 0, 0 };
|
||||
const lens = zir.extra[extra_index..][0..3].*;
|
||||
extra_index += 3;
|
||||
break :lens lens;
|
||||
};
|
||||
const value_body_len: u32 = if (flags.id.hasValueBody()) len: {
|
||||
const len = zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :len len;
|
||||
} else 0;
|
||||
|
||||
const type_body = zir.bodySlice(extra_index, type_body_len);
|
||||
extra_index += type_body_len;
|
||||
const align_body = zir.bodySlice(extra_index, align_body_len);
|
||||
extra_index += align_body_len;
|
||||
const linksection_body = zir.bodySlice(extra_index, linksection_body_len);
|
||||
extra_index += linksection_body_len;
|
||||
const addrspace_body = zir.bodySlice(extra_index, addrspace_body_len);
|
||||
extra_index += addrspace_body_len;
|
||||
const value_body = zir.bodySlice(extra_index, value_body_len);
|
||||
extra_index += value_body_len;
|
||||
|
||||
return .{
|
||||
extra.data,
|
||||
@intCast(extra.end),
|
||||
.src_node = pl_node.src_node,
|
||||
|
||||
.src_line = flags.src_line,
|
||||
.src_column = flags.src_column,
|
||||
|
||||
.kind = flags.id.kind(),
|
||||
.name = name,
|
||||
.is_pub = flags.id.isPub(),
|
||||
.is_threadlocal = flags.id.isThreadlocal(),
|
||||
.linkage = flags.id.linkage(),
|
||||
.lib_name = lib_name,
|
||||
|
||||
.type_body = if (type_body_len == 0) null else type_body,
|
||||
.align_body = if (align_body_len == 0) null else align_body,
|
||||
.linksection_body = if (linksection_body_len == 0) null else linksection_body,
|
||||
.addrspace_body = if (addrspace_body_len == 0) null else addrspace_body,
|
||||
.value_body = if (value_body_len == 0) null else value_body,
|
||||
};
|
||||
}
|
||||
|
||||
@ -4636,7 +4934,6 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
|
||||
}
|
||||
const bits = extra.data.bits;
|
||||
var extra_index = extra.end;
|
||||
extra_index += @intFromBool(bits.has_lib_name);
|
||||
if (bits.has_cc_body) {
|
||||
const body_len = zir.extra[extra_index];
|
||||
extra_index += 1 + body_len;
|
||||
|
||||
@ -348,12 +348,15 @@ const Job = union(enum) {
|
||||
/// Corresponds to the task in `link.Task`.
|
||||
/// Only needed for backends that haven't yet been updated to not race against Sema.
|
||||
codegen_type: InternPool.Index,
|
||||
/// The `Cau` must be semantically analyzed (and possibly export itself).
|
||||
/// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
|
||||
/// This may be its first time being analyzed, or it may be outdated.
|
||||
/// If the unit is a function, a `codegen_func` job will then be queued.
|
||||
analyze_comptime_unit: InternPool.AnalUnit,
|
||||
/// This function must be semantically analyzed.
|
||||
/// This may be its first time being analyzed, or it may be outdated.
|
||||
analyze_cau: InternPool.Cau.Index,
|
||||
/// Analyze the body of a runtime function.
|
||||
/// After analysis, a `codegen_func` job will be queued.
|
||||
/// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
|
||||
/// This job is separate from `analyze_comptime_unit` because it has a different priority.
|
||||
analyze_func: InternPool.Index,
|
||||
/// The main source file for the module needs to be analyzed.
|
||||
analyze_mod: *Package.Module,
|
||||
@ -2903,6 +2906,7 @@ const Header = extern struct {
|
||||
file_deps_len: u32,
|
||||
src_hash_deps_len: u32,
|
||||
nav_val_deps_len: u32,
|
||||
nav_ty_deps_len: u32,
|
||||
namespace_deps_len: u32,
|
||||
namespace_name_deps_len: u32,
|
||||
first_dependency_len: u32,
|
||||
@ -2946,6 +2950,7 @@ pub fn saveState(comp: *Compilation) !void {
|
||||
.file_deps_len = @intCast(ip.file_deps.count()),
|
||||
.src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
|
||||
.nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
|
||||
.nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
|
||||
.namespace_deps_len = @intCast(ip.namespace_deps.count()),
|
||||
.namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
|
||||
.first_dependency_len = @intCast(ip.first_dependency.count()),
|
||||
@ -2976,6 +2981,8 @@ pub fn saveState(comp: *Compilation) !void {
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.values()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.keys()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.nav_ty_deps.values()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.keys()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.namespace_deps.values()));
|
||||
addBuf(&bufs, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
|
||||
@ -3141,8 +3148,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
}
|
||||
|
||||
const file_index = switch (anal_unit.unwrap()) {
|
||||
.cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
|
||||
.func => |ip_index| (zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip) orelse continue).file,
|
||||
.@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
|
||||
.nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
|
||||
.type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
|
||||
.func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
|
||||
};
|
||||
|
||||
// Skip errors for AnalUnits within files that had a parse failure.
|
||||
@ -3374,11 +3383,9 @@ pub fn addModuleErrorMsg(
|
||||
const rt_file_path = try src.file_scope.fullPath(gpa);
|
||||
defer gpa.free(rt_file_path);
|
||||
const name = switch (ref.referencer.unwrap()) {
|
||||
.cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
|
||||
.nav => |nav| ip.getNav(nav).name.toSlice(ip),
|
||||
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
|
||||
.none => "comptime",
|
||||
},
|
||||
.@"comptime" => "comptime",
|
||||
.nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
|
||||
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
|
||||
.func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
|
||||
};
|
||||
try ref_traces.append(gpa, .{
|
||||
@ -3641,10 +3648,14 @@ fn performAllTheWorkInner(
|
||||
// If there's no work queued, check if there's anything outdated
|
||||
// which we need to work on, and queue it if so.
|
||||
if (try zcu.findOutdatedToAnalyze()) |outdated| {
|
||||
switch (outdated.unwrap()) {
|
||||
.cau => |cau| try comp.queueJob(.{ .analyze_cau = cau }),
|
||||
.func => |func| try comp.queueJob(.{ .analyze_func = func }),
|
||||
}
|
||||
try comp.queueJob(switch (outdated.unwrap()) {
|
||||
.func => |f| .{ .analyze_func = f },
|
||||
.@"comptime",
|
||||
.nav_ty,
|
||||
.nav_val,
|
||||
.type,
|
||||
=> .{ .analyze_comptime_unit = outdated },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -3667,13 +3678,13 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
|
||||
.codegen_nav => |nav_index| {
|
||||
const zcu = comp.zcu.?;
|
||||
const nav = zcu.intern_pool.getNav(nav_index);
|
||||
if (nav.analysis_owner.unwrap()) |cau| {
|
||||
const unit = InternPool.AnalUnit.wrap(.{ .cau = cau });
|
||||
if (nav.analysis != null) {
|
||||
const unit: InternPool.AnalUnit = .wrap(.{ .nav_val = nav_index });
|
||||
if (zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(nav.status == .resolved);
|
||||
assert(nav.status == .fully_resolved);
|
||||
comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index });
|
||||
},
|
||||
.codegen_func => |func| {
|
||||
@ -3688,36 +3699,48 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
|
||||
|
||||
const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
|
||||
defer pt.deactivate();
|
||||
pt.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
|
||||
pt.ensureFuncBodyUpToDate(func) catch |err| switch (err) {
|
||||
error.OutOfMemory => |e| return e,
|
||||
error.AnalysisFail => return,
|
||||
};
|
||||
},
|
||||
.analyze_cau => |cau_index| {
|
||||
.analyze_comptime_unit => |unit| {
|
||||
const named_frame = tracy.namedFrame("analyze_comptime_unit");
|
||||
defer named_frame.end();
|
||||
|
||||
const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
|
||||
defer pt.deactivate();
|
||||
pt.ensureCauAnalyzed(cau_index) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
|
||||
const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
|
||||
.@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
|
||||
.nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
|
||||
.nav_val => |nav| pt.ensureNavValUpToDate(nav),
|
||||
.type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,
|
||||
.func => unreachable,
|
||||
};
|
||||
maybe_err catch |err| switch (err) {
|
||||
error.OutOfMemory => |e| return e,
|
||||
error.AnalysisFail => return,
|
||||
};
|
||||
|
||||
queue_test_analysis: {
|
||||
if (!comp.config.is_test) break :queue_test_analysis;
|
||||
const nav = switch (unit.unwrap()) {
|
||||
.nav_val => |nav| nav,
|
||||
else => break :queue_test_analysis,
|
||||
};
|
||||
|
||||
// Check if this is a test function.
|
||||
const ip = &pt.zcu.intern_pool;
|
||||
const cau = ip.getCau(cau_index);
|
||||
const nav_index = switch (cau.owner.unwrap()) {
|
||||
.none, .type => break :queue_test_analysis,
|
||||
.nav => |nav| nav,
|
||||
};
|
||||
if (!pt.zcu.test_functions.contains(nav_index)) {
|
||||
if (!pt.zcu.test_functions.contains(nav)) {
|
||||
break :queue_test_analysis;
|
||||
}
|
||||
|
||||
// Tests are always emitted in test binaries. The decl_refs are created by
|
||||
// Zcu.populateTestFunctions, but this will not queue body analysis, so do
|
||||
// that now.
|
||||
try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav_index).status.resolved.val);
|
||||
try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val);
|
||||
}
|
||||
},
|
||||
.resolve_type_fully => |ty| {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
677
src/Sema.zig
677
src/Sema.zig
File diff suppressed because it is too large
Load Diff
@ -219,9 +219,8 @@ fn loadComptimePtrInner(
|
||||
|
||||
const base_val: MutableValue = switch (ptr.base_addr) {
|
||||
.nav => |nav| val: {
|
||||
try sema.declareDependency(.{ .nav_val = nav });
|
||||
try sema.ensureNavResolved(src, nav);
|
||||
const val = ip.getNav(nav).status.resolved.val;
|
||||
try sema.ensureNavResolved(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.
|
||||
|
||||
@ -3851,7 +3851,7 @@ fn resolveStructInner(
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
const struct_obj = zcu.typeToStruct(ty).?;
|
||||
const owner = InternPool.AnalUnit.wrap(.{ .cau = struct_obj.cau });
|
||||
const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
|
||||
|
||||
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
|
||||
return error.AnalysisFail;
|
||||
@ -3905,7 +3905,7 @@ fn resolveUnionInner(
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
const union_obj = zcu.typeToUnion(ty).?;
|
||||
const owner = InternPool.AnalUnit.wrap(.{ .cau = union_obj.cau });
|
||||
const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
|
||||
|
||||
if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
|
||||
return error.AnalysisFail;
|
||||
|
||||
@ -1343,7 +1343,12 @@ pub fn isLazySize(val: Value, zcu: *Zcu) bool {
|
||||
pub fn isPtrRuntimeValue(val: Value, zcu: *Zcu) bool {
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getBackingNav(val.toIntern()).unwrap() orelse return false;
|
||||
return switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) {
|
||||
const nav_val = switch (ip.getNav(nav).status) {
|
||||
.unresolved => unreachable,
|
||||
.type_resolved => |r| return r.is_threadlocal,
|
||||
.fully_resolved => |r| r.val,
|
||||
};
|
||||
return switch (ip.indexToKey(nav_val)) {
|
||||
.@"extern" => |e| e.is_threadlocal or e.is_dll_import,
|
||||
.variable => |v| v.is_threadlocal,
|
||||
else => false,
|
||||
|
||||
334
src/Zcu.zig
334
src/Zcu.zig
@ -170,6 +170,9 @@ outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
|
||||
/// it as outdated.
|
||||
retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
|
||||
|
||||
func_body_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty,
|
||||
nav_val_analysis_queued: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
|
||||
|
||||
/// These are the modules which we initially queue for analysis in `Compilation.update`.
|
||||
/// `resolveReferences` will use these as the root of its reachability traversal.
|
||||
analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
|
||||
@ -192,7 +195,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .empty,
|
||||
|
||||
test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
|
||||
|
||||
global_assembly: std.AutoArrayHashMapUnmanaged(InternPool.Cau.Index, []u8) = .empty,
|
||||
global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty,
|
||||
|
||||
/// Key is the `AnalUnit` *performing* the reference. This representation allows
|
||||
/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
|
||||
@ -282,7 +285,11 @@ pub const Exported = union(enum) {
|
||||
|
||||
pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
|
||||
return switch (exported) {
|
||||
.nav => |nav| zcu.intern_pool.getNav(nav).status.resolved.alignment,
|
||||
.nav => |nav| switch (zcu.intern_pool.getNav(nav).status) {
|
||||
.unresolved => unreachable,
|
||||
.type_resolved => |r| r.alignment,
|
||||
.fully_resolved => |r| r.alignment,
|
||||
},
|
||||
.uav => .none,
|
||||
};
|
||||
}
|
||||
@ -344,9 +351,12 @@ pub const Namespace = struct {
|
||||
pub_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
|
||||
/// All `usingnamespace` declarations in this namespace which are *not* marked `pub`.
|
||||
priv_usingnamespace: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
|
||||
/// All `comptime` and `test` declarations in this namespace. We store these purely so that
|
||||
/// incremental compilation can re-use the existing `Cau`s when a namespace changes.
|
||||
other_decls: std.ArrayListUnmanaged(InternPool.Cau.Index) = .empty,
|
||||
/// All `comptime` declarations in this namespace. We store these purely so that incremental
|
||||
/// compilation can re-use the existing `ComptimeUnit`s when a namespace changes.
|
||||
comptime_decls: std.ArrayListUnmanaged(InternPool.ComptimeUnit.Id) = .empty,
|
||||
/// All `test` declarations in this namespace. We store these purely so that incremental
|
||||
/// compilation can re-use the existing `Nav`s when a namespace changes.
|
||||
test_decls: std.ArrayListUnmanaged(InternPool.Nav.Index) = .empty,
|
||||
|
||||
pub const Index = InternPool.NamespaceIndex;
|
||||
pub const OptionalIndex = InternPool.OptionalNamespaceIndex;
|
||||
@ -2238,6 +2248,9 @@ pub fn deinit(zcu: *Zcu) void {
|
||||
zcu.outdated_ready.deinit(gpa);
|
||||
zcu.retryable_failures.deinit(gpa);
|
||||
|
||||
zcu.func_body_analysis_queued.deinit(gpa);
|
||||
zcu.nav_val_analysis_queued.deinit(gpa);
|
||||
|
||||
zcu.test_functions.deinit(gpa);
|
||||
|
||||
for (zcu.global_assembly.values()) |s| {
|
||||
@ -2436,11 +2449,10 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
|
||||
// If this is a Decl, we must recursively mark dependencies on its tyval
|
||||
// as no longer PO.
|
||||
switch (depender.unwrap()) {
|
||||
.cau => |cau| switch (zcu.intern_pool.getCau(cau).owner.unwrap()) {
|
||||
.nav => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
|
||||
.type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
|
||||
.none => {},
|
||||
},
|
||||
.@"comptime" => {},
|
||||
.nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
|
||||
.nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
|
||||
.type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
|
||||
.func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
|
||||
}
|
||||
}
|
||||
@ -2451,11 +2463,10 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
|
||||
fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
|
||||
const ip = &zcu.intern_pool;
|
||||
const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) {
|
||||
.cau => |cau| switch (ip.getCau(cau).owner.unwrap()) {
|
||||
.nav => |nav| .{ .nav_val = nav }, // TODO: also `nav_ref` deps when introduced
|
||||
.type => |ty| .{ .interned = ty },
|
||||
.none => return, // analysis of this `Cau` can't outdate any dependencies
|
||||
},
|
||||
.@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies
|
||||
.nav_val => |nav| .{ .nav_val = nav },
|
||||
.nav_ty => |nav| .{ .nav_ty = nav },
|
||||
.type => |ty| .{ .interned = ty },
|
||||
.func => |func_index| .{ .interned = func_index }, // IES
|
||||
};
|
||||
log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)});
|
||||
@ -2512,14 +2523,14 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
|
||||
}
|
||||
|
||||
// There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some
|
||||
// Cau with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
|
||||
// A or B. We should select a Cau, since a Cau is definitely responsible for the loop in the
|
||||
// dependency graph (since IES dependencies can't have loops). We should also, of course, not
|
||||
// select a Cau owned by a `comptime` declaration, since you can't depend on those!
|
||||
// AnalUnit with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
|
||||
// A or B. We should definitely not select a function, since a function can't be responsible for the
|
||||
// loop (IES dependencies can't have loops). We should also, of course, not select a `comptime`
|
||||
// declaration, since you can't depend on those!
|
||||
|
||||
// The choice of this Cau could have a big impact on how much total analysis we perform, since
|
||||
// The choice of this unit could have a big impact on how much total analysis we perform, since
|
||||
// if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit
|
||||
// may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a Decl
|
||||
// may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a unit
|
||||
// which the most things depend on - the idea is that this will resolve a lot of loops (but this
|
||||
// is only a heuristic).
|
||||
|
||||
@ -2530,33 +2541,29 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
|
||||
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
var chosen_cau: ?InternPool.Cau.Index = null;
|
||||
var chosen_cau_dependers: u32 = undefined;
|
||||
var chosen_unit: ?AnalUnit = null;
|
||||
var chosen_unit_dependers: u32 = undefined;
|
||||
|
||||
inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
|
||||
for (outdated_units) |unit| {
|
||||
const cau = switch (unit.unwrap()) {
|
||||
.cau => |cau| cau,
|
||||
.func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
|
||||
};
|
||||
const cau_owner = ip.getCau(cau).owner;
|
||||
|
||||
var n: u32 = 0;
|
||||
var it = ip.dependencyIterator(switch (cau_owner.unwrap()) {
|
||||
.none => continue, // there can be no dependencies on this `Cau` so it is a terrible choice
|
||||
var it = ip.dependencyIterator(switch (unit.unwrap()) {
|
||||
.func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
|
||||
.@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
|
||||
.type => |ty| .{ .interned = ty },
|
||||
.nav => |nav| .{ .nav_val = nav },
|
||||
.nav_val => |nav| .{ .nav_val = nav },
|
||||
.nav_ty => |nav| .{ .nav_ty = nav },
|
||||
});
|
||||
while (it.next()) |_| n += 1;
|
||||
|
||||
if (chosen_cau == null or n > chosen_cau_dependers) {
|
||||
chosen_cau = cau;
|
||||
chosen_cau_dependers = n;
|
||||
if (chosen_unit == null or n > chosen_unit_dependers) {
|
||||
chosen_unit = unit;
|
||||
chosen_unit_dependers = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chosen_cau == null) {
|
||||
if (chosen_unit == null) {
|
||||
for (zcu.outdated.keys(), zcu.outdated.values()) |o, opod| {
|
||||
const func = o.unwrap().func;
|
||||
const nav = zcu.funcInfo(func).owner_nav;
|
||||
@ -2570,11 +2577,11 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
|
||||
}
|
||||
|
||||
log.debug("findOutdatedToAnalyze: heuristic returned '{}' ({d} dependers)", .{
|
||||
zcu.fmtAnalUnit(AnalUnit.wrap(.{ .cau = chosen_cau.? })),
|
||||
chosen_cau_dependers,
|
||||
zcu.fmtAnalUnit(chosen_unit.?),
|
||||
chosen_unit_dependers,
|
||||
});
|
||||
|
||||
return AnalUnit.wrap(.{ .cau = chosen_cau.? });
|
||||
return chosen_unit.?;
|
||||
}
|
||||
|
||||
/// During an incremental update, before semantic analysis, call this to flush all values from
|
||||
@ -2679,24 +2686,14 @@ pub fn mapOldZirToNew(
|
||||
{
|
||||
var old_decl_it = old_zir.declIterator(match_item.old_inst);
|
||||
while (old_decl_it.next()) |old_decl_inst| {
|
||||
const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
|
||||
switch (old_decl.name) {
|
||||
const old_decl = old_zir.getDeclaration(old_decl_inst);
|
||||
switch (old_decl.kind) {
|
||||
.@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
|
||||
.@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
|
||||
.unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),
|
||||
_ => {
|
||||
const name_nts = old_decl.name.toString(old_zir).?;
|
||||
const name = old_zir.nullTerminatedString(name_nts);
|
||||
if (old_decl.name.isNamedTest(old_zir)) {
|
||||
if (old_decl.flags.test_is_decltest) {
|
||||
try named_decltests.put(gpa, name, old_decl_inst);
|
||||
} else {
|
||||
try named_tests.put(gpa, name, old_decl_inst);
|
||||
}
|
||||
} else {
|
||||
try named_decls.put(gpa, name, old_decl_inst);
|
||||
}
|
||||
},
|
||||
.@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
|
||||
.decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
|
||||
.@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2707,7 +2704,7 @@ pub fn mapOldZirToNew(
|
||||
|
||||
var new_decl_it = new_zir.declIterator(match_item.new_inst);
|
||||
while (new_decl_it.next()) |new_decl_inst| {
|
||||
const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
|
||||
const new_decl = new_zir.getDeclaration(new_decl_inst);
|
||||
// Attempt to match this to a declaration in the old ZIR:
|
||||
// * For named declarations (`const`/`var`/`fn`), we match based on name.
|
||||
// * For named tests (`test "foo"`) and decltests (`test foo`), we also match based on name.
|
||||
@ -2715,7 +2712,7 @@ pub fn mapOldZirToNew(
|
||||
// * For comptime blocks, we match based on order.
|
||||
// * For usingnamespace decls, we match based on order.
|
||||
// If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
|
||||
const old_decl_inst = switch (new_decl.name) {
|
||||
const old_decl_inst = switch (new_decl.kind) {
|
||||
.@"comptime" => inst: {
|
||||
if (comptime_decl_idx == comptime_decls.items.len) continue;
|
||||
defer comptime_decl_idx += 1;
|
||||
@ -2731,18 +2728,17 @@ pub fn mapOldZirToNew(
|
||||
defer unnamed_test_idx += 1;
|
||||
break :inst unnamed_tests.items[unnamed_test_idx];
|
||||
},
|
||||
_ => inst: {
|
||||
const name_nts = new_decl.name.toString(new_zir).?;
|
||||
const name = new_zir.nullTerminatedString(name_nts);
|
||||
if (new_decl.name.isNamedTest(new_zir)) {
|
||||
if (new_decl.flags.test_is_decltest) {
|
||||
break :inst named_decltests.get(name) orelse continue;
|
||||
} else {
|
||||
break :inst named_tests.get(name) orelse continue;
|
||||
}
|
||||
} else {
|
||||
break :inst named_decls.get(name) orelse continue;
|
||||
}
|
||||
.@"test" => inst: {
|
||||
const name = new_zir.nullTerminatedString(new_decl.name);
|
||||
break :inst named_tests.get(name) orelse continue;
|
||||
},
|
||||
.decltest => inst: {
|
||||
const name = new_zir.nullTerminatedString(new_decl.name);
|
||||
break :inst named_decltests.get(name) orelse continue;
|
||||
},
|
||||
.@"const", .@"var" => inst: {
|
||||
const name = new_zir.nullTerminatedString(new_decl.name);
|
||||
break :inst named_decls.get(name) orelse continue;
|
||||
},
|
||||
};
|
||||
|
||||
@ -2797,14 +2793,39 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo
|
||||
const ip = &zcu.intern_pool;
|
||||
const func = zcu.funcInfo(func_index);
|
||||
|
||||
switch (func.analysisUnordered(ip).state) {
|
||||
.unreferenced => {}, // We're the first reference!
|
||||
.queued => return, // Analysis is already queued.
|
||||
.analyzed => return, // Analysis is complete; if it's out-of-date, it'll be re-analyzed later this update.
|
||||
if (zcu.func_body_analysis_queued.contains(func_index)) return;
|
||||
|
||||
if (func.analysisUnordered(ip).is_analyzed) {
|
||||
if (!zcu.outdated.contains(.wrap(.{ .func = func_index })) and
|
||||
!zcu.potentially_outdated.contains(.wrap(.{ .func = func_index })))
|
||||
{
|
||||
// This function has been analyzed before and is definitely up-to-date.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
|
||||
try zcu.comp.queueJob(.{ .analyze_func = func_index });
|
||||
func.setAnalysisState(ip, .queued);
|
||||
zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {});
|
||||
}
|
||||
|
||||
pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void {
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
if (zcu.nav_val_analysis_queued.contains(nav_id)) return;
|
||||
|
||||
if (ip.getNav(nav_id).status == .fully_resolved) {
|
||||
if (!zcu.outdated.contains(.wrap(.{ .nav_val = nav_id })) and
|
||||
!zcu.potentially_outdated.contains(.wrap(.{ .nav_val = nav_id })))
|
||||
{
|
||||
// This `Nav` has been analyzed before and is definitely up-to-date.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
|
||||
try zcu.comp.queueJob(.{ .analyze_comptime_unit = .wrap(.{ .nav_val = nav_id }) });
|
||||
zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
|
||||
}
|
||||
|
||||
pub const ImportFileResult = struct {
|
||||
@ -3030,9 +3051,9 @@ pub fn handleUpdateExports(
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addGlobalAssembly(zcu: *Zcu, cau: InternPool.Cau.Index, source: []const u8) !void {
|
||||
pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void {
|
||||
const gpa = zcu.gpa;
|
||||
const gop = try zcu.global_assembly.getOrPut(gpa, cau);
|
||||
const gop = try zcu.global_assembly.getOrPut(gpa, unit);
|
||||
if (gop.found_existing) {
|
||||
const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
|
||||
gpa.free(gop.value_ptr.*);
|
||||
@ -3315,23 +3336,22 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||
|
||||
log.debug("handle type '{}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
|
||||
|
||||
// If this type has a `Cau` for resolution, it's automatically referenced.
|
||||
const resolution_cau: InternPool.Cau.Index.Optional = switch (ip.indexToKey(ty)) {
|
||||
.struct_type => ip.loadStructType(ty).cau.toOptional(),
|
||||
.union_type => ip.loadUnionType(ty).cau.toOptional(),
|
||||
.enum_type => ip.loadEnumType(ty).cau,
|
||||
.opaque_type => .none,
|
||||
// If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced.
|
||||
const has_resolution: bool = switch (ip.indexToKey(ty)) {
|
||||
.struct_type, .union_type => true,
|
||||
.enum_type => |k| k != .generated_tag,
|
||||
.opaque_type => false,
|
||||
else => unreachable,
|
||||
};
|
||||
if (resolution_cau.unwrap()) |cau| {
|
||||
if (has_resolution) {
|
||||
// this should only be referenced by the type
|
||||
const unit = AnalUnit.wrap(.{ .cau = cau });
|
||||
const unit: AnalUnit = .wrap(.{ .type = ty });
|
||||
assert(!result.contains(unit));
|
||||
try unit_queue.putNoClobber(gpa, unit, referencer);
|
||||
}
|
||||
|
||||
// If this is a union with a generated tag, its tag type is automatically referenced.
|
||||
// We don't add this reference for non-generated tags, as those will already be referenced via the union's `Cau`, with a better source location.
|
||||
// We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location.
|
||||
if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| {
|
||||
const tag_ty = union_obj.enum_tag_ty;
|
||||
if (tag_ty != .none) {
|
||||
@ -3346,53 +3366,61 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||
// Queue any decls within this type which would be automatically analyzed.
|
||||
// Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`.
|
||||
const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?;
|
||||
for (zcu.namespacePtr(ns).other_decls.items) |cau| {
|
||||
// These are `comptime` and `test` declarations.
|
||||
// `comptime` decls are always analyzed; `test` declarations are analyzed depending on the test filter.
|
||||
const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
|
||||
for (zcu.namespacePtr(ns).comptime_decls.items) |cu| {
|
||||
// `comptime` decls are always analyzed.
|
||||
const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
|
||||
if (!result.contains(unit)) {
|
||||
log.debug("type '{}': ref comptime %{}", .{
|
||||
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
|
||||
@intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
|
||||
});
|
||||
try unit_queue.put(gpa, unit, referencer);
|
||||
}
|
||||
}
|
||||
for (zcu.namespacePtr(ns).test_decls.items) |nav_id| {
|
||||
const nav = ip.getNav(nav_id);
|
||||
// `test` declarations are analyzed depending on the test filter.
|
||||
const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
// If the file failed AstGen, the TrackedInst refers to the old ZIR.
|
||||
const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
|
||||
const declaration = zir.getDeclaration(inst_info.inst)[0];
|
||||
const want_analysis = switch (declaration.name) {
|
||||
const decl = zir.getDeclaration(inst_info.inst);
|
||||
|
||||
if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
|
||||
|
||||
const want_analysis = switch (decl.kind) {
|
||||
.@"usingnamespace" => unreachable,
|
||||
.@"comptime" => true,
|
||||
else => a: {
|
||||
if (!comp.config.is_test) break :a false;
|
||||
if (file.mod != zcu.main_mod) break :a false;
|
||||
if (declaration.name.isNamedTest(zir)) {
|
||||
const nav = ip.getCau(cau).owner.unwrap().nav;
|
||||
const fqn_slice = ip.getNav(nav).fqn.toSlice(ip);
|
||||
for (comp.test_filters) |test_filter| {
|
||||
if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
|
||||
} else break :a false;
|
||||
}
|
||||
.@"const", .@"var" => unreachable,
|
||||
.@"comptime" => unreachable,
|
||||
.unnamed_test => true,
|
||||
.@"test", .decltest => a: {
|
||||
const fqn_slice = nav.fqn.toSlice(ip);
|
||||
for (comp.test_filters) |test_filter| {
|
||||
if (std.mem.indexOf(u8, fqn_slice, test_filter) != null) break;
|
||||
} else break :a false;
|
||||
break :a true;
|
||||
},
|
||||
};
|
||||
if (want_analysis) {
|
||||
const unit = AnalUnit.wrap(.{ .cau = cau });
|
||||
if (!result.contains(unit)) {
|
||||
log.debug("type '{}': ref cau %{}", .{
|
||||
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
|
||||
@intFromEnum(inst_info.inst),
|
||||
});
|
||||
try unit_queue.put(gpa, unit, referencer);
|
||||
}
|
||||
log.debug("type '{}': ref test %{}", .{
|
||||
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
|
||||
@intFromEnum(inst_info.inst),
|
||||
});
|
||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav_id });
|
||||
try unit_queue.put(gpa, unit, referencer);
|
||||
}
|
||||
}
|
||||
for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| {
|
||||
// These are named declarations. They are analyzed only if marked `export`.
|
||||
const cau = ip.getNav(nav).analysis_owner.unwrap().?;
|
||||
const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
|
||||
const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
// If the file failed AstGen, the TrackedInst refers to the old ZIR.
|
||||
const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
|
||||
const declaration = zir.getDeclaration(inst_info.inst)[0];
|
||||
if (declaration.flags.is_export) {
|
||||
const unit = AnalUnit.wrap(.{ .cau = cau });
|
||||
const decl = zir.getDeclaration(inst_info.inst);
|
||||
if (decl.linkage == .@"export") {
|
||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
||||
if (!result.contains(unit)) {
|
||||
log.debug("type '{}': ref cau %{}", .{
|
||||
log.debug("type '{}': ref named %{}", .{
|
||||
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
|
||||
@intFromEnum(inst_info.inst),
|
||||
});
|
||||
@ -3402,16 +3430,15 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||
}
|
||||
for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| {
|
||||
// These are named declarations. They are analyzed only if marked `export`.
|
||||
const cau = ip.getNav(nav).analysis_owner.unwrap().?;
|
||||
const inst_info = ip.getCau(cau).zir_index.resolveFull(ip) orelse continue;
|
||||
const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
// If the file failed AstGen, the TrackedInst refers to the old ZIR.
|
||||
const zir = if (file.status == .success_zir) file.zir else file.prev_zir.?.*;
|
||||
const declaration = zir.getDeclaration(inst_info.inst)[0];
|
||||
if (declaration.flags.is_export) {
|
||||
const unit = AnalUnit.wrap(.{ .cau = cau });
|
||||
const decl = zir.getDeclaration(inst_info.inst);
|
||||
if (decl.linkage == .@"export") {
|
||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
||||
if (!result.contains(unit)) {
|
||||
log.debug("type '{}': ref cau %{}", .{
|
||||
log.debug("type '{}': ref named %{}", .{
|
||||
Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
|
||||
@intFromEnum(inst_info.inst),
|
||||
});
|
||||
@ -3422,13 +3449,11 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||
// Incremental compilation does not support `usingnamespace`.
|
||||
// These are only included to keep good reference traces in non-incremental updates.
|
||||
for (zcu.namespacePtr(ns).pub_usingnamespace.items) |nav| {
|
||||
const cau = ip.getNav(nav).analysis_owner.unwrap().?;
|
||||
const unit = AnalUnit.wrap(.{ .cau = cau });
|
||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
||||
if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
|
||||
}
|
||||
for (zcu.namespacePtr(ns).priv_usingnamespace.items) |nav| {
|
||||
const cau = ip.getNav(nav).analysis_owner.unwrap().?;
|
||||
const unit = AnalUnit.wrap(.{ .cau = cau });
|
||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
||||
if (!result.contains(unit)) try unit_queue.put(gpa, unit, referencer);
|
||||
}
|
||||
continue;
|
||||
@ -3437,6 +3462,17 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
||||
const unit = kv.key;
|
||||
try result.putNoClobber(gpa, unit, kv.value);
|
||||
|
||||
// `nav_val` and `nav_ty` reference each other *implicitly* to save memory.
|
||||
queue_paired: {
|
||||
const other: AnalUnit = .wrap(switch (unit.unwrap()) {
|
||||
.nav_val => |n| .{ .nav_ty = n },
|
||||
.nav_ty => |n| .{ .nav_val = n },
|
||||
.@"comptime", .type, .func => break :queue_paired,
|
||||
});
|
||||
if (result.contains(other)) break :queue_paired;
|
||||
try unit_queue.put(gpa, other, kv.value); // same reference location
|
||||
}
|
||||
|
||||
log.debug("handle unit '{}'", .{zcu.fmtAnalUnit(unit)});
|
||||
|
||||
if (zcu.reference_table.get(unit)) |first_ref_idx| {
|
||||
@ -3522,13 +3558,11 @@ pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
|
||||
const ip = &zcu.intern_pool;
|
||||
const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?;
|
||||
const zir = zcu.fileByIndex(inst_info.file).zir;
|
||||
const inst = zir.instructions.get(@intFromEnum(inst_info.inst));
|
||||
assert(inst.tag == .declaration);
|
||||
return zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
|
||||
return zir.getDeclaration(inst_info.inst).src_line;
|
||||
}
|
||||
|
||||
pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
|
||||
return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
|
||||
return Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.fully_resolved.val);
|
||||
}
|
||||
|
||||
pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {
|
||||
@ -3540,12 +3574,6 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
|
||||
return zcu.fileByIndex(zcu.navFileScopeIndex(nav));
|
||||
}
|
||||
|
||||
pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {
|
||||
const ip = &zcu.intern_pool;
|
||||
const file_index = ip.getCau(cau).zir_index.resolveFile(ip);
|
||||
return zcu.fileByIndex(file_index);
|
||||
}
|
||||
|
||||
pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Formatter(formatAnalUnit) {
|
||||
return .{ .data = .{ .unit = unit, .zcu = zcu } };
|
||||
}
|
||||
@ -3558,19 +3586,18 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
|
||||
const zcu = data.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
switch (data.unit.unwrap()) {
|
||||
.cau => |cau_index| {
|
||||
const cau = ip.getCau(cau_index);
|
||||
switch (cau.owner.unwrap()) {
|
||||
.nav => |nav| return writer.print("cau(decl='{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
|
||||
.type => |ty| return writer.print("cau(ty='{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
|
||||
.none => if (cau.zir_index.resolveFull(ip)) |resolved| {
|
||||
const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
|
||||
return writer.print("cau(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) });
|
||||
} else {
|
||||
return writer.writeAll("cau(inst=<lost>)");
|
||||
},
|
||||
.@"comptime" => |cu_id| {
|
||||
const cu = ip.getComptimeUnit(cu_id);
|
||||
if (cu.zir_index.resolveFull(ip)) |resolved| {
|
||||
const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
|
||||
return writer.print("comptime(inst=('{s}', %{}))", .{ file_path, @intFromEnum(resolved.inst) });
|
||||
} else {
|
||||
return writer.writeAll("comptime(inst=<list>)");
|
||||
}
|
||||
},
|
||||
.nav_val => |nav| return writer.print("nav_val('{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
|
||||
.nav_ty => |nav| return writer.print("nav_ty('{}')", .{ip.getNav(nav).fqn.fmt(ip)}),
|
||||
.type => |ty| return writer.print("ty('{}')", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)}),
|
||||
.func => |func| {
|
||||
const nav = zcu.funcInfo(func).owner_nav;
|
||||
return writer.print("func('{}')", .{ip.getNav(nav).fqn.fmt(ip)});
|
||||
@ -3595,7 +3622,11 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
|
||||
},
|
||||
.nav_val => |nav| {
|
||||
const fqn = ip.getNav(nav).fqn;
|
||||
return writer.print("nav('{}')", .{fqn.fmt(ip)});
|
||||
return writer.print("nav_val('{}')", .{fqn.fmt(ip)});
|
||||
},
|
||||
.nav_ty => |nav| {
|
||||
const fqn = ip.getNav(nav).fqn;
|
||||
return writer.print("nav_ty('{}')", .{fqn.fmt(ip)});
|
||||
},
|
||||
.interned => |ip_index| switch (ip.indexToKey(ip_index)) {
|
||||
.struct_type, .union_type, .enum_type => return writer.print("type('{}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),
|
||||
@ -3772,3 +3803,12 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
|
||||
if (!backend_ok) return .{ .bad_backend = backend };
|
||||
return .ok;
|
||||
}
|
||||
|
||||
/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer.
|
||||
pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool {
|
||||
return switch (zcu.intern_pool.indexToKey(val)) {
|
||||
.variable => false,
|
||||
.@"extern" => |e| e.is_const,
|
||||
else => true,
|
||||
};
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -3218,15 +3218,7 @@ fn lowerNavRef(func: *CodeGen, nav_index: InternPool.Nav.Index, offset: u32) Inn
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
// check if decl is an alias to a function, in which case we
|
||||
// want to lower the actual decl, rather than the alias itself.
|
||||
const owner_nav = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
|
||||
.func => |function| function.owner_nav,
|
||||
.variable => |variable| variable.owner_nav,
|
||||
.@"extern" => |@"extern"| @"extern".owner_nav,
|
||||
else => nav_index,
|
||||
};
|
||||
const nav_ty = ip.getNav(owner_nav).typeOf(ip);
|
||||
const nav_ty = ip.getNav(nav_index).typeOf(ip);
|
||||
if (!ip.isFunctionType(nav_ty) and !Type.fromInterned(nav_ty).hasRuntimeBitsIgnoreComptime(zcu)) {
|
||||
return .{ .imm32 = 0xaaaaaaaa };
|
||||
}
|
||||
|
||||
@ -817,7 +817,7 @@ fn genNavRef(
|
||||
pt: Zcu.PerThread,
|
||||
src_loc: Zcu.LazySrcLoc,
|
||||
val: Value,
|
||||
ref_nav_index: InternPool.Nav.Index,
|
||||
nav_index: InternPool.Nav.Index,
|
||||
target: std.Target,
|
||||
) CodeGenError!GenResult {
|
||||
const zcu = pt.zcu;
|
||||
@ -851,14 +851,15 @@ fn genNavRef(
|
||||
}
|
||||
}
|
||||
|
||||
const nav_index, const is_extern, const lib_name, const is_threadlocal = switch (ip.indexToKey(zcu.navValue(ref_nav_index).toIntern())) {
|
||||
.func => |func| .{ func.owner_nav, false, .none, false },
|
||||
.variable => |variable| .{ variable.owner_nav, false, variable.lib_name, variable.is_threadlocal },
|
||||
.@"extern" => |@"extern"| .{ @"extern".owner_nav, true, @"extern".lib_name, @"extern".is_threadlocal },
|
||||
else => .{ ref_nav_index, false, .none, false },
|
||||
};
|
||||
const nav = ip.getNav(nav_index);
|
||||
|
||||
const is_extern, const lib_name, const is_threadlocal = if (nav.getExtern(ip)) |e|
|
||||
.{ true, e.lib_name, e.is_threadlocal }
|
||||
else
|
||||
.{ false, .none, nav.isThreadlocal(ip) };
|
||||
|
||||
const single_threaded = zcu.navFileScope(nav_index).mod.single_threaded;
|
||||
const name = ip.getNav(nav_index).name;
|
||||
const name = nav.name;
|
||||
if (lf.cast(.elf)) |elf_file| {
|
||||
const zo = elf_file.zigObjectPtr().?;
|
||||
if (is_extern) {
|
||||
|
||||
@ -770,11 +770,14 @@ pub const DeclGen = struct {
|
||||
const ctype_pool = &dg.ctype_pool;
|
||||
|
||||
// Chase function values in order to be able to reference the original function.
|
||||
const owner_nav = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
|
||||
.variable => |variable| variable.owner_nav,
|
||||
.func => |func| func.owner_nav,
|
||||
.@"extern" => |@"extern"| @"extern".owner_nav,
|
||||
else => nav_index,
|
||||
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)) {
|
||||
.func => |f| f.owner_nav,
|
||||
.@"extern" => |e| e.owner_nav,
|
||||
else => nav_index,
|
||||
},
|
||||
};
|
||||
|
||||
// Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
|
||||
@ -2237,7 +2240,7 @@ pub const DeclGen = struct {
|
||||
Type.fromInterned(nav.typeOf(ip)),
|
||||
.{ .nav = nav_index },
|
||||
CQualifiers.init(.{ .@"const" = flags.is_const }),
|
||||
nav.status.resolved.alignment,
|
||||
nav.getAlignment(),
|
||||
.complete,
|
||||
);
|
||||
try fwd.writeAll(";\n");
|
||||
@ -2246,19 +2249,19 @@ pub const DeclGen = struct {
|
||||
fn renderNavName(dg: *DeclGen, writer: anytype, nav_index: InternPool.Nav.Index) !void {
|
||||
const zcu = dg.pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
|
||||
.@"extern" => |@"extern"| try writer.print("{ }", .{
|
||||
const nav = ip.getNav(nav_index);
|
||||
if (nav.getExtern(ip)) |@"extern"| {
|
||||
try writer.print("{ }", .{
|
||||
fmtIdent(ip.getNav(@"extern".owner_nav).name.toSlice(ip)),
|
||||
}),
|
||||
else => {
|
||||
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
|
||||
// expand to 3x the length of its input, but let's cut it off at a much shorter limit.
|
||||
const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
|
||||
try writer.print("{}__{d}", .{
|
||||
fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
|
||||
@intFromEnum(nav_index),
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
|
||||
// expand to 3x the length of its input, but let's cut it off at a much shorter limit.
|
||||
const fqn_slice = ip.getNav(nav_index).fqn.toSlice(ip);
|
||||
try writer.print("{}__{d}", .{
|
||||
fmtIdent(fqn_slice[0..@min(fqn_slice.len, 100)]),
|
||||
@intFromEnum(nav_index),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -2826,7 +2829,7 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
|
||||
|
||||
const fwd = o.dg.fwdDeclWriter();
|
||||
try fwd.print("static zig_{s} ", .{@tagName(key)});
|
||||
try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).status.resolved.alignment, .forward, .{
|
||||
try o.dg.renderFunctionSignature(fwd, fn_val, ip.getNav(fn_nav_index).getAlignment(), .forward, .{
|
||||
.fmt_ctype_pool_string = fn_name,
|
||||
});
|
||||
try fwd.writeAll(";\n");
|
||||
@ -2867,13 +2870,13 @@ pub fn genFunc(f: *Function) !void {
|
||||
try o.dg.renderFunctionSignature(
|
||||
fwd,
|
||||
nav_val,
|
||||
nav.status.resolved.alignment,
|
||||
nav.status.fully_resolved.alignment,
|
||||
.forward,
|
||||
.{ .nav = nav_index },
|
||||
);
|
||||
try fwd.writeAll(";\n");
|
||||
|
||||
if (nav.status.resolved.@"linksection".toSlice(ip)) |s|
|
||||
if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |s|
|
||||
try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
|
||||
try o.dg.renderFunctionSignature(
|
||||
o.writer(),
|
||||
@ -2952,7 +2955,7 @@ pub fn genDecl(o: *Object) !void {
|
||||
const nav_ty = Type.fromInterned(nav.typeOf(ip));
|
||||
|
||||
if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
|
||||
switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
||||
.@"extern" => |@"extern"| {
|
||||
if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
|
||||
.is_extern = true,
|
||||
@ -2965,8 +2968,8 @@ pub fn genDecl(o: *Object) !void {
|
||||
try fwd.writeAll("zig_extern ");
|
||||
try o.dg.renderFunctionSignature(
|
||||
fwd,
|
||||
Value.fromInterned(nav.status.resolved.val),
|
||||
nav.status.resolved.alignment,
|
||||
Value.fromInterned(nav.status.fully_resolved.val),
|
||||
nav.status.fully_resolved.alignment,
|
||||
.forward,
|
||||
.{ .@"export" = .{
|
||||
.main_name = nav.name,
|
||||
@ -2985,14 +2988,14 @@ pub fn genDecl(o: *Object) !void {
|
||||
const w = o.writer();
|
||||
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
|
||||
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
|
||||
if (nav.status.resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
|
||||
if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
|
||||
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
|
||||
try o.dg.renderTypeAndName(
|
||||
w,
|
||||
nav_ty,
|
||||
.{ .nav = o.dg.pass.nav },
|
||||
.{},
|
||||
nav.status.resolved.alignment,
|
||||
nav.status.fully_resolved.alignment,
|
||||
.complete,
|
||||
);
|
||||
try w.writeAll(" = ");
|
||||
@ -3002,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
|
||||
},
|
||||
else => try genDeclValue(
|
||||
o,
|
||||
Value.fromInterned(nav.status.resolved.val),
|
||||
Value.fromInterned(nav.status.fully_resolved.val),
|
||||
.{ .nav = o.dg.pass.nav },
|
||||
nav.status.resolved.alignment,
|
||||
nav.status.resolved.@"linksection",
|
||||
nav.status.fully_resolved.alignment,
|
||||
nav.status.fully_resolved.@"linksection",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1476,7 +1476,7 @@ pub const Object = struct {
|
||||
} }, &o.builder);
|
||||
}
|
||||
|
||||
if (nav.status.resolved.@"linksection".toSlice(ip)) |section|
|
||||
if (nav.status.fully_resolved.@"linksection".toSlice(ip)) |section|
|
||||
function_index.setSection(try o.builder.string(section), &o.builder);
|
||||
|
||||
var deinit_wip = true;
|
||||
@ -1684,7 +1684,7 @@ pub const Object = struct {
|
||||
const file = try o.getDebugFile(file_scope);
|
||||
|
||||
const line_number = zcu.navSrcLine(func.owner_nav) + 1;
|
||||
const is_internal_linkage = ip.indexToKey(nav.status.resolved.val) != .@"extern";
|
||||
const is_internal_linkage = ip.indexToKey(nav.status.fully_resolved.val) != .@"extern";
|
||||
const debug_decl_type = try o.lowerDebugType(fn_ty);
|
||||
|
||||
const subprogram = try o.builder.debugSubprogram(
|
||||
@ -2928,9 +2928,7 @@ pub const Object = struct {
|
||||
const gpa = o.gpa;
|
||||
const nav = ip.getNav(nav_index);
|
||||
const owner_mod = zcu.navFileScope(nav_index).mod;
|
||||
const resolved = nav.status.resolved;
|
||||
const val = Value.fromInterned(resolved.val);
|
||||
const ty = val.typeOf(zcu);
|
||||
const ty: Type = .fromInterned(nav.typeOf(ip));
|
||||
const gop = try o.nav_map.getOrPut(gpa, nav_index);
|
||||
if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
|
||||
|
||||
@ -2938,15 +2936,14 @@ pub const Object = struct {
|
||||
const target = owner_mod.resolved_target.result;
|
||||
const sret = firstParamSRet(fn_info, zcu, target);
|
||||
|
||||
const is_extern, const lib_name = switch (ip.indexToKey(val.toIntern())) {
|
||||
.variable => |variable| .{ false, variable.lib_name },
|
||||
.@"extern" => |@"extern"| .{ true, @"extern".lib_name },
|
||||
else => .{ false, .none },
|
||||
};
|
||||
const is_extern, const lib_name = if (nav.getExtern(ip)) |@"extern"|
|
||||
.{ true, @"extern".lib_name }
|
||||
else
|
||||
.{ false, .none };
|
||||
const function_index = try o.builder.addFunction(
|
||||
try o.lowerType(ty),
|
||||
try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
|
||||
toLlvmAddressSpace(resolved.@"addrspace", target),
|
||||
toLlvmAddressSpace(nav.getAddrspace(), target),
|
||||
);
|
||||
gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
|
||||
|
||||
@ -3064,8 +3061,8 @@ pub const Object = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (resolved.alignment != .none)
|
||||
function_index.setAlignment(resolved.alignment.toLlvm(), &o.builder);
|
||||
if (nav.getAlignment() != .none)
|
||||
function_index.setAlignment(nav.getAlignment().toLlvm(), &o.builder);
|
||||
|
||||
// Function attributes that are independent of analysis results of the function body.
|
||||
try o.addCommonFnAttributes(
|
||||
@ -3250,17 +3247,21 @@ pub const Object = struct {
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
const resolved = nav.status.resolved;
|
||||
const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (ip.indexToKey(resolved.val)) {
|
||||
.variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
|
||||
.@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
|
||||
else => .{ false, false, false, false },
|
||||
const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
|
||||
.unresolved => unreachable,
|
||||
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
|
||||
.variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
|
||||
.@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
|
||||
else => .{ false, false, false, false },
|
||||
},
|
||||
// This means it's a source declaration which is not `extern`!
|
||||
.type_resolved => |r| .{ false, r.is_threadlocal, false, false },
|
||||
};
|
||||
|
||||
const variable_index = try o.builder.addVariable(
|
||||
try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
|
||||
try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
|
||||
toLlvmGlobalAddressSpace(resolved.@"addrspace", zcu.getTarget()),
|
||||
toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
|
||||
);
|
||||
gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
|
||||
|
||||
@ -4529,20 +4530,10 @@ pub const Object = struct {
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
// In the case of something like:
|
||||
// fn foo() void {}
|
||||
// const bar = foo;
|
||||
// ... &bar;
|
||||
// `bar` is just an alias and we actually want to lower a reference to `foo`.
|
||||
const owner_nav_index = switch (ip.indexToKey(zcu.navValue(nav_index).toIntern())) {
|
||||
.func => |func| func.owner_nav,
|
||||
.@"extern" => |@"extern"| @"extern".owner_nav,
|
||||
else => nav_index,
|
||||
};
|
||||
const owner_nav = ip.getNav(owner_nav_index);
|
||||
const nav = ip.getNav(nav_index);
|
||||
|
||||
const nav_ty = Type.fromInterned(owner_nav.typeOf(ip));
|
||||
const ptr_ty = try pt.navPtrType(owner_nav_index);
|
||||
const nav_ty = Type.fromInterned(nav.typeOf(ip));
|
||||
const ptr_ty = try pt.navPtrType(nav_index);
|
||||
|
||||
const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
|
||||
if ((!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) or
|
||||
@ -4552,13 +4543,13 @@ pub const Object = struct {
|
||||
}
|
||||
|
||||
const llvm_global = if (is_fn_body)
|
||||
(try o.resolveLlvmFunction(owner_nav_index)).ptrConst(&o.builder).global
|
||||
(try o.resolveLlvmFunction(nav_index)).ptrConst(&o.builder).global
|
||||
else
|
||||
(try o.resolveGlobalNav(owner_nav_index)).ptrConst(&o.builder).global;
|
||||
(try o.resolveGlobalNav(nav_index)).ptrConst(&o.builder).global;
|
||||
|
||||
const llvm_val = try o.builder.convConst(
|
||||
llvm_global.toConst(),
|
||||
try o.builder.ptrType(toLlvmAddressSpace(owner_nav.status.resolved.@"addrspace", zcu.getTarget())),
|
||||
try o.builder.ptrType(toLlvmAddressSpace(nav.getAddrspace(), zcu.getTarget())),
|
||||
);
|
||||
|
||||
return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty));
|
||||
@ -4800,10 +4791,10 @@ 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.resolved;
|
||||
const resolved = nav.status.fully_resolved;
|
||||
|
||||
const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
|
||||
.variable => |variable| .{ false, variable.lib_name, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
|
||||
.variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
|
||||
.@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
|
||||
else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
|
||||
};
|
||||
@ -5766,7 +5757,7 @@ pub const FuncGen = struct {
|
||||
const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?;
|
||||
const msg_nav = ip.getNav(msg_nav_index);
|
||||
const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu);
|
||||
const msg_ptr = try o.lowerValue(msg_nav.status.resolved.val);
|
||||
const msg_ptr = try o.lowerValue(msg_nav.status.fully_resolved.val);
|
||||
const null_opt_addr_global = try fg.resolveNullOptUsize();
|
||||
const target = zcu.getTarget();
|
||||
const llvm_usize = try o.lowerType(Type.usize);
|
||||
|
||||
@ -268,7 +268,7 @@ pub const Object = struct {
|
||||
// TODO: Extern fn?
|
||||
const kind: SpvModule.Decl.Kind = if (ip.isFunctionType(nav.typeOf(ip)))
|
||||
.func
|
||||
else switch (nav.status.resolved.@"addrspace") {
|
||||
else switch (nav.getAddrspace()) {
|
||||
.generic => .invocation_global,
|
||||
else => .global,
|
||||
};
|
||||
@ -1279,17 +1279,20 @@ const NavGen = struct {
|
||||
const ip = &zcu.intern_pool;
|
||||
const ty_id = try self.resolveType(ty, .direct);
|
||||
const nav = ip.getNav(nav_index);
|
||||
const nav_val = zcu.navValue(nav_index);
|
||||
const nav_ty = nav_val.typeOf(zcu);
|
||||
const nav_ty: Type = .fromInterned(nav.typeOf(ip));
|
||||
|
||||
switch (ip.indexToKey(nav_val.toIntern())) {
|
||||
.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.
|
||||
return try self.spv.constUndef(ty_id);
|
||||
switch (nav.status) {
|
||||
.unresolved => unreachable,
|
||||
.type_resolved => {}, // this is not a function or extern
|
||||
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
|
||||
.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.
|
||||
return try self.spv.constUndef(ty_id);
|
||||
},
|
||||
.@"extern" => if (ip.isFunctionType(nav_ty.toIntern())) @panic("TODO"),
|
||||
else => {},
|
||||
},
|
||||
.@"extern" => assert(!ip.isFunctionType(nav_ty.toIntern())), // TODO
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (!nav_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) {
|
||||
@ -1305,7 +1308,7 @@ const NavGen = struct {
|
||||
.global, .invocation_global => spv_decl.result_id,
|
||||
};
|
||||
|
||||
const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
|
||||
const storage_class = self.spvStorageClass(nav.getAddrspace());
|
||||
try self.addFunctionDep(spv_decl_index, storage_class);
|
||||
|
||||
const decl_ptr_ty_id = try self.ptrType(nav_ty, storage_class);
|
||||
@ -3182,7 +3185,7 @@ const NavGen = struct {
|
||||
};
|
||||
assert(maybe_init_val == null); // TODO
|
||||
|
||||
const storage_class = self.spvStorageClass(nav.status.resolved.@"addrspace");
|
||||
const storage_class = self.spvStorageClass(nav.getAddrspace());
|
||||
assert(storage_class != .Generic); // These should be instance globals
|
||||
|
||||
const ptr_ty_id = try self.ptrType(ty, storage_class);
|
||||
|
||||
@ -692,7 +692,7 @@ pub const File = struct {
|
||||
/// May be called before or after updateExports for any given Nav.
|
||||
pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
|
||||
const nav = pt.zcu.intern_pool.getNav(nav_index);
|
||||
assert(nav.status == .resolved);
|
||||
assert(nav.status == .fully_resolved);
|
||||
switch (base.tag) {
|
||||
inline else => |tag| {
|
||||
dev.check(tag.devFeature());
|
||||
|
||||
@ -217,7 +217,7 @@ pub fn updateFunc(
|
||||
.mod = zcu.navFileScope(func.owner_nav).mod,
|
||||
.error_msg = null,
|
||||
.pass = .{ .nav = func.owner_nav },
|
||||
.is_naked_fn = zcu.navValue(func.owner_nav).typeOf(zcu).fnCallingConvention(zcu) == .naked,
|
||||
.is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
|
||||
.fwd_decl = fwd_decl.toManaged(gpa),
|
||||
.ctype_pool = ctype_pool.*,
|
||||
.scratch = .{},
|
||||
@ -320,11 +320,11 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
const nav = ip.getNav(nav_index);
|
||||
const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
||||
.func => return,
|
||||
.@"extern" => .none,
|
||||
.variable => |variable| variable.init,
|
||||
else => nav.status.resolved.val,
|
||||
else => nav.status.fully_resolved.val,
|
||||
};
|
||||
if (nav_init != .none and !Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) return;
|
||||
|
||||
@ -499,7 +499,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
av_block,
|
||||
self.exported_navs.getPtr(nav),
|
||||
export_names,
|
||||
if (ip.indexToKey(zcu.navValue(nav).toIntern()) == .@"extern")
|
||||
if (ip.getNav(nav).getExtern(ip) != null)
|
||||
ip.getNav(nav).name.toOptional()
|
||||
else
|
||||
.none,
|
||||
@ -544,13 +544,11 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
},
|
||||
self.getString(av_block.code),
|
||||
);
|
||||
for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(
|
||||
if (self.exported_navs.contains(nav)) .default else switch (ip.indexToKey(zcu.navValue(nav).toIntern())) {
|
||||
.@"extern" => .zig_extern,
|
||||
else => .static,
|
||||
},
|
||||
self.getString(av_block.code),
|
||||
);
|
||||
for (self.navs.keys(), self.navs.values()) |nav, av_block| f.appendCodeAssumeCapacity(storage: {
|
||||
if (self.exported_navs.contains(nav)) break :storage .default;
|
||||
if (ip.getNav(nav).getExtern(ip) != null) break :storage .zig_extern;
|
||||
break :storage .static;
|
||||
}, self.getString(av_block.code));
|
||||
|
||||
const file = self.base.file.?;
|
||||
try file.setEndPos(f.file_size);
|
||||
|
||||
@ -1110,6 +1110,8 @@ pub fn updateFunc(coff: *Coff, pt: Zcu.PerThread, func_index: InternPool.Index,
|
||||
const atom_index = try coff.getOrCreateAtomForNav(func.owner_nav);
|
||||
coff.freeRelocations(atom_index);
|
||||
|
||||
coff.navs.getPtr(func.owner_nav).?.section = coff.text_section_index.?;
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(gpa);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
@ -1223,6 +1225,8 @@ pub fn updateNav(
|
||||
coff.freeRelocations(atom_index);
|
||||
const atom = coff.getAtom(atom_index);
|
||||
|
||||
coff.navs.getPtr(nav_index).?.section = coff.getNavOutputSection(nav_index);
|
||||
|
||||
var code_buffer = std.ArrayList(u8).init(gpa);
|
||||
defer code_buffer.deinit();
|
||||
|
||||
@ -1342,7 +1346,8 @@ pub fn getOrCreateAtomForNav(coff: *Coff, nav_index: InternPool.Nav.Index) !Atom
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{
|
||||
.atom = try coff.createAtom(),
|
||||
.section = coff.getNavOutputSection(nav_index),
|
||||
// If necessary, this will be modified by `updateNav` or `updateFunc`.
|
||||
.section = coff.rdata_section_index.?,
|
||||
.exports = .{},
|
||||
};
|
||||
}
|
||||
@ -1355,7 +1360,7 @@ fn getNavOutputSection(coff: *Coff, nav_index: InternPool.Nav.Index) u16 {
|
||||
const nav = ip.getNav(nav_index);
|
||||
const ty = Type.fromInterned(nav.typeOf(ip));
|
||||
const zig_ty = ty.zigTypeTag(zcu);
|
||||
const val = Value.fromInterned(nav.status.resolved.val);
|
||||
const val = Value.fromInterned(nav.status.fully_resolved.val);
|
||||
const index: u16 = blk: {
|
||||
if (val.isUndefDeep(zcu)) {
|
||||
// TODO in release-fast and release-small, we should put undef in .bss
|
||||
@ -2348,10 +2353,10 @@ pub fn getNavVAddr(
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
|
||||
const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
.@"extern" => |@"extern"| try coff.getGlobalSymbol(nav.name.toSlice(ip), @"extern".lib_name.toSlice(ip)),
|
||||
else => coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?,
|
||||
};
|
||||
const sym_index = if (nav.getExtern(ip)) |e|
|
||||
try coff.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip))
|
||||
else
|
||||
coff.getAtom(try coff.getOrCreateAtomForNav(nav_index)).getSymbolIndex().?;
|
||||
const atom_index = coff.getAtomIndexForSymbol(.{
|
||||
.sym_index = reloc_info.parent.atom_index,
|
||||
.file = null,
|
||||
|
||||
@ -2259,24 +2259,13 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
|
||||
switch (ip.indexToKey(nav_val.toIntern())) {
|
||||
else => {
|
||||
assert(file.zir_loaded);
|
||||
const decl = file.zir.getDeclaration(inst_info.inst)[0];
|
||||
const decl = file.zir.getDeclaration(inst_info.inst);
|
||||
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(a.namespace);
|
||||
break :parent .{
|
||||
parent_namespace_ptr.owner_type,
|
||||
switch (decl.name) {
|
||||
.@"comptime",
|
||||
.@"usingnamespace",
|
||||
.unnamed_test,
|
||||
=> DW.ACCESS.private,
|
||||
_ => if (decl.name.isNamedTest(file.zir))
|
||||
DW.ACCESS.private
|
||||
else if (decl.flags.is_pub)
|
||||
DW.ACCESS.public
|
||||
else
|
||||
DW.ACCESS.private,
|
||||
},
|
||||
if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
|
||||
};
|
||||
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
|
||||
|
||||
@ -2292,7 +2281,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
|
||||
const nav_ty = nav_val.typeOf(zcu);
|
||||
const nav_ty_reloc_index = try wip_nav.refForward();
|
||||
try wip_nav.infoExprloc(.{ .addr = .{ .sym = sym_index } });
|
||||
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
|
||||
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
||||
nav_ty.abiAlignment(zcu).toByteUnits().?);
|
||||
try diw.writeByte(@intFromBool(false));
|
||||
wip_nav.finishForward(nav_ty_reloc_index);
|
||||
@ -2301,24 +2290,13 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
|
||||
},
|
||||
.variable => |variable| {
|
||||
assert(file.zir_loaded);
|
||||
const decl = file.zir.getDeclaration(inst_info.inst)[0];
|
||||
const decl = file.zir.getDeclaration(inst_info.inst);
|
||||
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(a.namespace);
|
||||
break :parent .{
|
||||
parent_namespace_ptr.owner_type,
|
||||
switch (decl.name) {
|
||||
.@"comptime",
|
||||
.@"usingnamespace",
|
||||
.unnamed_test,
|
||||
=> DW.ACCESS.private,
|
||||
_ => if (decl.name.isNamedTest(file.zir))
|
||||
DW.ACCESS.private
|
||||
else if (decl.flags.is_pub)
|
||||
DW.ACCESS.public
|
||||
else
|
||||
DW.ACCESS.private,
|
||||
},
|
||||
if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
|
||||
};
|
||||
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
|
||||
|
||||
@ -2335,30 +2313,19 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
|
||||
try wip_nav.refType(ty);
|
||||
const addr: Loc = .{ .addr = .{ .sym = sym_index } };
|
||||
try wip_nav.infoExprloc(if (variable.is_threadlocal) .{ .form_tls_address = &addr } else addr);
|
||||
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
|
||||
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
||||
ty.abiAlignment(zcu).toByteUnits().?);
|
||||
try diw.writeByte(@intFromBool(false));
|
||||
},
|
||||
.func => |func| {
|
||||
assert(file.zir_loaded);
|
||||
const decl = file.zir.getDeclaration(inst_info.inst)[0];
|
||||
const decl = file.zir.getDeclaration(inst_info.inst);
|
||||
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(a.namespace);
|
||||
break :parent .{
|
||||
parent_namespace_ptr.owner_type,
|
||||
switch (decl.name) {
|
||||
.@"comptime",
|
||||
.@"usingnamespace",
|
||||
.unnamed_test,
|
||||
=> DW.ACCESS.private,
|
||||
_ => if (decl.name.isNamedTest(file.zir))
|
||||
DW.ACCESS.private
|
||||
else if (decl.flags.is_pub)
|
||||
DW.ACCESS.public
|
||||
else
|
||||
DW.ACCESS.private,
|
||||
},
|
||||
if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
|
||||
};
|
||||
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
|
||||
|
||||
@ -2421,7 +2388,7 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
|
||||
wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
|
||||
try diw.writeInt(u32, 0, dwarf.endian);
|
||||
const target = file.mod.resolved_target.result;
|
||||
try uleb128(diw, switch (nav.status.resolved.alignment) {
|
||||
try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
|
||||
.none => target_info.defaultFunctionAlignment(target),
|
||||
else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
|
||||
}.toByteUnits().?);
|
||||
@ -2585,23 +2552,22 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
|
||||
const inst_info = nav.srcInst(ip).resolveFull(ip).?;
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
assert(file.zir_loaded);
|
||||
const decl = file.zir.getDeclaration(inst_info.inst)[0];
|
||||
const decl = file.zir.getDeclaration(inst_info.inst);
|
||||
|
||||
const is_test = switch (decl.name) {
|
||||
.unnamed_test => true,
|
||||
.@"comptime", .@"usingnamespace" => false,
|
||||
_ => decl.name.isNamedTest(file.zir),
|
||||
const is_test = switch (decl.kind) {
|
||||
.unnamed_test, .@"test", .decltest => true,
|
||||
.@"comptime", .@"usingnamespace", .@"const", .@"var" => false,
|
||||
};
|
||||
if (is_test) {
|
||||
// This isn't actually a comptime Nav! It's a test, so it'll definitely never be referenced at comptime.
|
||||
return;
|
||||
}
|
||||
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis_owner.unwrap()) |cau| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).namespace);
|
||||
const parent_type, const accessibility: u8 = if (nav.analysis) |a| parent: {
|
||||
const parent_namespace_ptr = ip.namespacePtr(a.namespace);
|
||||
break :parent .{
|
||||
parent_namespace_ptr.owner_type,
|
||||
if (decl.flags.is_pub) DW.ACCESS.public else DW.ACCESS.private,
|
||||
if (decl.is_pub) DW.ACCESS.public else DW.ACCESS.private,
|
||||
};
|
||||
} else .{ zcu.fileRootType(inst_info.file), DW.ACCESS.private };
|
||||
|
||||
@ -2986,7 +2952,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
|
||||
const nav_ty = nav_val.typeOf(zcu);
|
||||
try wip_nav.refType(nav_ty);
|
||||
try wip_nav.blockValue(nav_src_loc, nav_val);
|
||||
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
|
||||
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
||||
nav_ty.abiAlignment(zcu).toByteUnits().?);
|
||||
try diw.writeByte(@intFromBool(false));
|
||||
},
|
||||
@ -3011,7 +2977,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
|
||||
try wip_nav.strp(nav.name.toSlice(ip));
|
||||
try wip_nav.strp(nav.fqn.toSlice(ip));
|
||||
const nav_ty_reloc_index = try wip_nav.refForward();
|
||||
try uleb128(diw, nav.status.resolved.alignment.toByteUnits() orelse
|
||||
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
||||
nav_ty.abiAlignment(zcu).toByteUnits().?);
|
||||
try diw.writeByte(@intFromBool(false));
|
||||
if (has_runtime_bits) try wip_nav.blockValue(nav_src_loc, nav_val);
|
||||
@ -4198,9 +4164,7 @@ pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.I
|
||||
assert(inst_info.inst != .main_struct_inst);
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
|
||||
const inst = file.zir.instructions.get(@intFromEnum(inst_info.inst));
|
||||
assert(inst.tag == .declaration);
|
||||
const line = file.zir.extraData(Zir.Inst.Declaration, inst.data.declaration.payload_index).data.src_line;
|
||||
const line = file.zir.getDeclaration(inst_info.inst).src_line;
|
||||
var line_buf: [4]u8 = undefined;
|
||||
std.mem.writeInt(u32, &line_buf, line, dwarf.endian);
|
||||
|
||||
|
||||
@ -925,14 +925,11 @@ pub fn getNavVAddr(
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
|
||||
const this_sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
.@"extern" => |@"extern"| try self.getGlobalSymbol(
|
||||
elf_file,
|
||||
nav.name.toSlice(ip),
|
||||
@"extern".lib_name.toSlice(ip),
|
||||
),
|
||||
else => try self.getOrCreateMetadataForNav(zcu, nav_index),
|
||||
};
|
||||
const this_sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
|
||||
elf_file,
|
||||
nav.name.toSlice(ip),
|
||||
@"extern".lib_name.toSlice(ip),
|
||||
) else try self.getOrCreateMetadataForNav(zcu, nav_index);
|
||||
const this_sym = self.symbol(this_sym_index);
|
||||
const vaddr = this_sym.address(.{}, elf_file);
|
||||
switch (reloc_info.parent) {
|
||||
@ -1107,15 +1104,13 @@ pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index
|
||||
|
||||
pub fn getOrCreateMetadataForNav(self: *ZigObject, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol.Index {
|
||||
const gpa = zcu.gpa;
|
||||
const ip = &zcu.intern_pool;
|
||||
const gop = try self.navs.getOrPut(gpa, nav_index);
|
||||
if (!gop.found_existing) {
|
||||
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
|
||||
const nav_val = Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
|
||||
const sym = self.symbol(symbol_index);
|
||||
if (nav_val.getVariable(zcu)) |variable| {
|
||||
if (variable.is_threadlocal and zcu.comp.config.any_non_single_threaded) {
|
||||
sym.flags.is_tls = true;
|
||||
}
|
||||
if (ip.getNav(nav_index).isThreadlocal(ip) and zcu.comp.config.any_non_single_threaded) {
|
||||
sym.flags.is_tls = true;
|
||||
}
|
||||
gop.value_ptr.* = .{ .symbol_index = symbol_index };
|
||||
}
|
||||
@ -1547,7 +1542,7 @@ pub fn updateNav(
|
||||
|
||||
log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
|
||||
|
||||
const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
||||
.func => .none,
|
||||
.variable => |variable| variable.init,
|
||||
.@"extern" => |@"extern"| {
|
||||
@ -1560,7 +1555,7 @@ pub fn updateNav(
|
||||
self.symbol(sym_index).flags.is_extern_ptr = true;
|
||||
return;
|
||||
},
|
||||
else => nav.status.resolved.val,
|
||||
else => nav.status.fully_resolved.val,
|
||||
};
|
||||
|
||||
if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
|
||||
|
||||
@ -608,14 +608,11 @@ pub fn getNavVAddr(
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
|
||||
const sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
.@"extern" => |@"extern"| try self.getGlobalSymbol(
|
||||
macho_file,
|
||||
nav.name.toSlice(ip),
|
||||
@"extern".lib_name.toSlice(ip),
|
||||
),
|
||||
else => try self.getOrCreateMetadataForNav(macho_file, nav_index),
|
||||
};
|
||||
const sym_index = if (nav.getExtern(ip)) |@"extern"| try self.getGlobalSymbol(
|
||||
macho_file,
|
||||
nav.name.toSlice(ip),
|
||||
@"extern".lib_name.toSlice(ip),
|
||||
) else try self.getOrCreateMetadataForNav(macho_file, nav_index);
|
||||
const sym = self.symbols.items[sym_index];
|
||||
const vaddr = sym.getAddress(.{}, macho_file);
|
||||
switch (reloc_info.parent) {
|
||||
@ -882,7 +879,7 @@ pub fn updateNav(
|
||||
const ip = &zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
|
||||
const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
const nav_init = switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
||||
.func => .none,
|
||||
.variable => |variable| variable.init,
|
||||
.@"extern" => |@"extern"| {
|
||||
@ -895,7 +892,7 @@ pub fn updateNav(
|
||||
sym.flags.is_extern_ptr = true;
|
||||
return;
|
||||
},
|
||||
else => nav.status.resolved.val,
|
||||
else => nav.status.fully_resolved.val,
|
||||
};
|
||||
|
||||
if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(zcu)) {
|
||||
@ -1561,11 +1558,7 @@ fn isThreadlocal(macho_file: *MachO, nav_index: InternPool.Nav.Index) bool {
|
||||
if (!macho_file.base.comp.config.any_non_single_threaded)
|
||||
return false;
|
||||
const ip = &macho_file.base.comp.zcu.?.intern_pool;
|
||||
return switch (ip.indexToKey(ip.getNav(nav_index).status.resolved.val)) {
|
||||
.variable => |variable| variable.is_threadlocal,
|
||||
.@"extern" => |@"extern"| @"extern".is_threadlocal,
|
||||
else => false,
|
||||
};
|
||||
return ip.getNav(nav_index).isThreadlocal(ip);
|
||||
}
|
||||
|
||||
fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
|
||||
|
||||
@ -1021,7 +1021,7 @@ pub fn seeNav(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index)
|
||||
const atom_idx = gop.value_ptr.index;
|
||||
// handle externs here because they might not get updateDecl called on them
|
||||
const nav = ip.getNav(nav_index);
|
||||
if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
|
||||
if (nav.getExtern(ip) != null) {
|
||||
// this is a "phantom atom" - it is never actually written to disk, just convenient for us to store stuff about externs
|
||||
if (nav.name.eqlSlice("etext", ip)) {
|
||||
self.etext_edata_end_atom_indices[0] = atom_idx;
|
||||
@ -1370,7 +1370,7 @@ pub fn getNavVAddr(
|
||||
const ip = &pt.zcu.intern_pool;
|
||||
const nav = ip.getNav(nav_index);
|
||||
log.debug("getDeclVAddr for {}", .{nav.name.fmt(ip)});
|
||||
if (ip.indexToKey(nav.status.resolved.val) == .@"extern") {
|
||||
if (nav.getExtern(ip) != null) {
|
||||
if (nav.name.eqlSlice("etext", ip)) {
|
||||
try self.addReloc(reloc_info.parent.atom_index, .{
|
||||
.target = undefined,
|
||||
|
||||
@ -241,7 +241,7 @@ pub fn updateNav(
|
||||
|
||||
const nav_val = zcu.navValue(nav_index);
|
||||
const is_extern, const lib_name, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
|
||||
.variable => |variable| .{ false, variable.lib_name, Value.fromInterned(variable.init) },
|
||||
.variable => |variable| .{ false, .none, Value.fromInterned(variable.init) },
|
||||
.func => return,
|
||||
.@"extern" => |@"extern"| if (ip.isFunctionType(nav.typeOf(ip)))
|
||||
return
|
||||
@ -734,15 +734,14 @@ pub fn getNavVAddr(
|
||||
const target_atom_index = try zig_object.getOrCreateAtomForNav(wasm, pt, nav_index);
|
||||
const target_atom = wasm.getAtom(target_atom_index);
|
||||
const target_symbol_index = @intFromEnum(target_atom.sym_index);
|
||||
switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
.@"extern" => |@"extern"| try zig_object.addOrUpdateImport(
|
||||
if (nav.getExtern(ip)) |@"extern"| {
|
||||
try zig_object.addOrUpdateImport(
|
||||
wasm,
|
||||
nav.name.toSlice(ip),
|
||||
target_atom.sym_index,
|
||||
@"extern".lib_name.toSlice(ip),
|
||||
null,
|
||||
),
|
||||
else => {},
|
||||
);
|
||||
}
|
||||
|
||||
std.debug.assert(reloc_info.parent.atom_index != 0);
|
||||
@ -945,8 +944,8 @@ pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.In
|
||||
segment.name = &.{}; // Ensure no accidental double free
|
||||
}
|
||||
|
||||
const nav_val = zcu.navValue(nav_index).toIntern();
|
||||
if (ip.indexToKey(nav_val) == .@"extern") {
|
||||
const nav = ip.getNav(nav_index);
|
||||
if (nav.getExtern(ip) != null) {
|
||||
std.debug.assert(zig_object.imports.remove(atom.sym_index));
|
||||
}
|
||||
std.debug.assert(wasm.symbol_atom.remove(atom.symbolLoc()));
|
||||
@ -960,7 +959,7 @@ pub fn freeNav(zig_object: *ZigObject, wasm: *Wasm, nav_index: InternPool.Nav.In
|
||||
if (sym.isGlobal()) {
|
||||
std.debug.assert(zig_object.global_syms.remove(atom.sym_index));
|
||||
}
|
||||
if (ip.isFunctionType(ip.typeOf(nav_val))) {
|
||||
if (ip.isFunctionType(nav.typeOf(ip))) {
|
||||
zig_object.functions_free_list.append(gpa, sym.index) catch {};
|
||||
std.debug.assert(zig_object.atom_types.remove(atom_index));
|
||||
} else {
|
||||
|
||||
@ -542,7 +542,6 @@ const Writer = struct {
|
||||
|
||||
.@"asm" => try self.writeAsm(stream, extended, false),
|
||||
.asm_expr => try self.writeAsm(stream, extended, true),
|
||||
.variable => try self.writeVarExtended(stream, extended),
|
||||
.alloc => try self.writeAllocExtended(stream, extended),
|
||||
|
||||
.compile_log => try self.writeNodeMultiOp(stream, extended),
|
||||
@ -2347,7 +2346,6 @@ const Writer = struct {
|
||||
inferred_error_set,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
|
||||
.none,
|
||||
&.{},
|
||||
@ -2371,13 +2369,6 @@ const Writer = struct {
|
||||
var ret_ty_ref: Zir.Inst.Ref = .none;
|
||||
var ret_ty_body: []const Zir.Inst.Index = &.{};
|
||||
|
||||
if (extra.data.bits.has_lib_name) {
|
||||
const lib_name = self.code.nullTerminatedString(@enumFromInt(self.code.extra[extra_index]));
|
||||
extra_index += 1;
|
||||
try stream.print("lib_name=\"{}\", ", .{std.zig.fmtEscapes(lib_name)});
|
||||
}
|
||||
try self.writeFlag(stream, "test, ", extra.data.bits.is_test);
|
||||
|
||||
if (extra.data.bits.has_cc_body) {
|
||||
const body_len = self.code.extra[extra_index];
|
||||
extra_index += 1;
|
||||
@ -2414,7 +2405,6 @@ const Writer = struct {
|
||||
stream,
|
||||
extra.data.bits.is_inferred_error,
|
||||
extra.data.bits.is_var_args,
|
||||
extra.data.bits.is_extern,
|
||||
extra.data.bits.is_noinline,
|
||||
cc_ref,
|
||||
cc_body,
|
||||
@ -2427,36 +2417,6 @@ const Writer = struct {
|
||||
);
|
||||
}
|
||||
|
||||
fn writeVarExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
|
||||
const extra = self.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
|
||||
const small = @as(Zir.Inst.ExtendedVar.Small, @bitCast(extended.small));
|
||||
|
||||
try self.writeInstRef(stream, extra.data.var_type);
|
||||
|
||||
var extra_index: usize = extra.end;
|
||||
if (small.has_lib_name) {
|
||||
const lib_name_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
|
||||
const lib_name = self.code.nullTerminatedString(lib_name_index);
|
||||
extra_index += 1;
|
||||
try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)});
|
||||
}
|
||||
const align_inst: Zir.Inst.Ref = if (!small.has_align) .none else blk: {
|
||||
const align_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
|
||||
extra_index += 1;
|
||||
break :blk align_inst;
|
||||
};
|
||||
const init_inst: Zir.Inst.Ref = if (!small.has_init) .none else blk: {
|
||||
const init_inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
|
||||
extra_index += 1;
|
||||
break :blk init_inst;
|
||||
};
|
||||
try self.writeFlag(stream, ", is_extern", small.is_extern);
|
||||
try self.writeFlag(stream, ", is_threadlocal", small.is_threadlocal);
|
||||
try self.writeOptionalInstRef(stream, ", align=", align_inst);
|
||||
try self.writeOptionalInstRef(stream, ", init=", init_inst);
|
||||
try stream.writeAll("))");
|
||||
}
|
||||
|
||||
fn writeAllocExtended(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
|
||||
const extra = self.code.extraData(Zir.Inst.AllocExtended, extended.operand);
|
||||
const small = @as(Zir.Inst.AllocExtended.Small, @bitCast(extended.small));
|
||||
@ -2604,7 +2564,6 @@ const Writer = struct {
|
||||
stream: anytype,
|
||||
inferred_error_set: bool,
|
||||
var_args: bool,
|
||||
is_extern: bool,
|
||||
is_noinline: bool,
|
||||
cc_ref: Zir.Inst.Ref,
|
||||
cc_body: []const Zir.Inst.Index,
|
||||
@ -2618,7 +2577,6 @@ const Writer = struct {
|
||||
try self.writeOptionalInstRefOrBody(stream, "cc=", cc_ref, cc_body);
|
||||
try self.writeOptionalInstRefOrBody(stream, "ret_ty=", ret_ty_ref, ret_ty_body);
|
||||
try self.writeFlag(stream, "vargs, ", var_args);
|
||||
try self.writeFlag(stream, "extern, ", is_extern);
|
||||
try self.writeFlag(stream, "inferror, ", inferred_error_set);
|
||||
try self.writeFlag(stream, "noinline, ", is_noinline);
|
||||
|
||||
@ -2664,56 +2622,58 @@ const Writer = struct {
|
||||
}
|
||||
|
||||
fn writeDeclaration(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].declaration;
|
||||
const extra = self.code.extraData(Zir.Inst.Declaration, inst_data.payload_index);
|
||||
const decl = self.code.getDeclaration(inst);
|
||||
|
||||
const prev_parent_decl_node = self.parent_decl_node;
|
||||
defer self.parent_decl_node = prev_parent_decl_node;
|
||||
self.parent_decl_node = inst_data.src_node;
|
||||
self.parent_decl_node = decl.src_node;
|
||||
|
||||
if (extra.data.flags.is_pub) try stream.writeAll("pub ");
|
||||
if (extra.data.flags.is_export) try stream.writeAll("export ");
|
||||
switch (extra.data.name) {
|
||||
if (decl.is_pub) try stream.writeAll("pub ");
|
||||
switch (decl.linkage) {
|
||||
.normal => {},
|
||||
.@"export" => try stream.writeAll("export "),
|
||||
.@"extern" => try stream.writeAll("extern "),
|
||||
}
|
||||
switch (decl.kind) {
|
||||
.@"comptime" => try stream.writeAll("comptime"),
|
||||
.@"usingnamespace" => try stream.writeAll("usingnamespace"),
|
||||
.unnamed_test => try stream.writeAll("test"),
|
||||
_ => {
|
||||
const name = extra.data.name.toString(self.code).?;
|
||||
const prefix = if (extra.data.name.isNamedTest(self.code)) p: {
|
||||
break :p if (extra.data.flags.test_is_decltest) "decltest " else "test ";
|
||||
} else "";
|
||||
try stream.print("{s}'{s}'", .{ prefix, self.code.nullTerminatedString(name) });
|
||||
.@"test", .decltest, .@"const", .@"var" => {
|
||||
try stream.print("{s} '{s}'", .{ @tagName(decl.kind), self.code.nullTerminatedString(decl.name) });
|
||||
},
|
||||
}
|
||||
const src_hash_arr: [4]u32 = .{
|
||||
extra.data.src_hash_0,
|
||||
extra.data.src_hash_1,
|
||||
extra.data.src_hash_2,
|
||||
extra.data.src_hash_3,
|
||||
};
|
||||
const src_hash_bytes: [16]u8 = @bitCast(src_hash_arr);
|
||||
try stream.print(" line({d}) hash({})", .{ extra.data.src_line, std.fmt.fmtSliceHexLower(&src_hash_bytes) });
|
||||
const src_hash = self.code.getAssociatedSrcHash(inst).?;
|
||||
try stream.print(" line({d}) column({d}) hash({})", .{
|
||||
decl.src_line,
|
||||
decl.src_column,
|
||||
std.fmt.fmtSliceHexLower(&src_hash),
|
||||
});
|
||||
|
||||
{
|
||||
const bodies = extra.data.getBodies(@intCast(extra.end), self.code);
|
||||
if (decl.type_body) |b| {
|
||||
try stream.writeAll(" type=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
|
||||
try stream.writeAll(" value=");
|
||||
try self.writeBracedDecl(stream, bodies.value_body);
|
||||
|
||||
if (bodies.align_body) |b| {
|
||||
if (decl.align_body) |b| {
|
||||
try stream.writeAll(" align=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
|
||||
if (bodies.linksection_body) |b| {
|
||||
if (decl.linksection_body) |b| {
|
||||
try stream.writeAll(" linksection=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
|
||||
if (bodies.addrspace_body) |b| {
|
||||
if (decl.addrspace_body) |b| {
|
||||
try stream.writeAll(" addrspace=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
|
||||
if (decl.value_body) |b| {
|
||||
try stream.writeAll(" value=");
|
||||
try self.writeBracedDecl(stream, b);
|
||||
}
|
||||
}
|
||||
|
||||
try stream.writeAll(") ");
|
||||
|
||||
@ -66,3 +66,99 @@ test "global loads can affect liveness" {
|
||||
S.f();
|
||||
try std.testing.expect(y.a == 1);
|
||||
}
|
||||
|
||||
test "global const can be self-referential" {
|
||||
const S = struct {
|
||||
self: *const @This(),
|
||||
x: u32,
|
||||
|
||||
const foo: @This() = .{ .self = &foo, .x = 123 };
|
||||
};
|
||||
|
||||
try std.testing.expect(S.foo.x == 123);
|
||||
try std.testing.expect(S.foo.self.x == 123);
|
||||
try std.testing.expect(S.foo.self.self.x == 123);
|
||||
try std.testing.expect(S.foo.self == &S.foo);
|
||||
try std.testing.expect(S.foo.self.self == &S.foo);
|
||||
}
|
||||
|
||||
test "global var can be self-referential" {
|
||||
const S = struct {
|
||||
self: *@This(),
|
||||
x: u32,
|
||||
|
||||
var foo: @This() = .{ .self = &foo, .x = undefined };
|
||||
};
|
||||
|
||||
S.foo.x = 123;
|
||||
|
||||
try std.testing.expect(S.foo.x == 123);
|
||||
try std.testing.expect(S.foo.self.x == 123);
|
||||
try std.testing.expect(S.foo.self == &S.foo);
|
||||
|
||||
S.foo.self.x = 456;
|
||||
|
||||
try std.testing.expect(S.foo.x == 456);
|
||||
try std.testing.expect(S.foo.self.x == 456);
|
||||
try std.testing.expect(S.foo.self == &S.foo);
|
||||
|
||||
S.foo.self.self.x = 789;
|
||||
|
||||
try std.testing.expect(S.foo.x == 789);
|
||||
try std.testing.expect(S.foo.self.x == 789);
|
||||
try std.testing.expect(S.foo.self == &S.foo);
|
||||
}
|
||||
|
||||
test "global const can be indirectly self-referential" {
|
||||
const S = struct {
|
||||
other: *const @This(),
|
||||
x: u32,
|
||||
|
||||
const foo: @This() = .{ .other = &bar, .x = 123 };
|
||||
const bar: @This() = .{ .other = &foo, .x = 456 };
|
||||
};
|
||||
|
||||
try std.testing.expect(S.foo.x == 123);
|
||||
try std.testing.expect(S.foo.other.x == 456);
|
||||
try std.testing.expect(S.foo.other.other.x == 123);
|
||||
try std.testing.expect(S.foo.other.other.other.x == 456);
|
||||
try std.testing.expect(S.foo.other == &S.bar);
|
||||
try std.testing.expect(S.foo.other.other == &S.foo);
|
||||
|
||||
try std.testing.expect(S.bar.x == 456);
|
||||
try std.testing.expect(S.bar.other.x == 123);
|
||||
try std.testing.expect(S.bar.other.other.x == 456);
|
||||
try std.testing.expect(S.bar.other.other.other.x == 123);
|
||||
try std.testing.expect(S.bar.other == &S.foo);
|
||||
try std.testing.expect(S.bar.other.other == &S.bar);
|
||||
}
|
||||
|
||||
test "global var can be indirectly self-referential" {
|
||||
const S = struct {
|
||||
other: *@This(),
|
||||
x: u32,
|
||||
|
||||
var foo: @This() = .{ .other = &bar, .x = undefined };
|
||||
var bar: @This() = .{ .other = &foo, .x = undefined };
|
||||
};
|
||||
|
||||
S.foo.other.x = 123; // bar.x
|
||||
S.foo.other.other.x = 456; // foo.x
|
||||
|
||||
try std.testing.expect(S.foo.x == 456);
|
||||
try std.testing.expect(S.foo.other.x == 123);
|
||||
try std.testing.expect(S.foo.other.other.x == 456);
|
||||
try std.testing.expect(S.foo.other.other.other.x == 123);
|
||||
try std.testing.expect(S.foo.other == &S.bar);
|
||||
try std.testing.expect(S.foo.other.other == &S.foo);
|
||||
|
||||
S.bar.other.x = 111; // foo.x
|
||||
S.bar.other.other.x = 222; // bar.x
|
||||
|
||||
try std.testing.expect(S.bar.x == 222);
|
||||
try std.testing.expect(S.bar.other.x == 111);
|
||||
try std.testing.expect(S.bar.other.other.x == 222);
|
||||
try std.testing.expect(S.bar.other.other.other.x == 111);
|
||||
try std.testing.expect(S.bar.other == &S.foo);
|
||||
try std.testing.expect(S.bar.other.other == &S.bar);
|
||||
}
|
||||
|
||||
@ -10,4 +10,5 @@ pub export fn entry() void {
|
||||
// target=native
|
||||
//
|
||||
// :2:36: error: unable to resolve comptime value
|
||||
// :2:36: note: container level variable initializers must be comptime-known
|
||||
// :2:36: note: global variable initializer must be comptime-known
|
||||
// :2:36: note: thread local and dll imported variables have runtime-known addresses
|
||||
|
||||
11
test/cases/compile_errors/self_reference_missing_const.zig
Normal file
11
test/cases/compile_errors/self_reference_missing_const.zig
Normal file
@ -0,0 +1,11 @@
|
||||
const S = struct { self: *S, x: u32 };
|
||||
const s: S = .{ .self = &s, .x = 123 };
|
||||
|
||||
comptime {
|
||||
_ = s;
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :2:18: error: expected type '*tmp.S', found '*const tmp.S'
|
||||
// :2:18: note: cast discards const qualifier
|
||||
@ -7,5 +7,5 @@ export fn entry() foo {
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :1:5: error: variable of type 'type' must be const or comptime
|
||||
// :1:5: note: types are not available at runtime
|
||||
// :1:11: error: variable of type 'type' must be const or comptime
|
||||
// :1:11: note: types are not available at runtime
|
||||
|
||||
@ -8,5 +8,5 @@ export fn entry() void {
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :1:5: error: variable of type 'comptime_int' must be const or comptime
|
||||
// :1:5: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
// :1:9: error: variable of type 'comptime_int' must be const or comptime
|
||||
// :1:9: note: to modify this variable at runtime, it must be given an explicit fixed-size number type
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user