Zir: refactor declaration instruction representation

The new representation is often more compact. It is also more
straightforward to understand: for instance, `extern` is represented on
the `declaration` instruction itself rather than using a special
instruction. The same applies to `var`, making both of these far more
compact.

This commit also separates the type and value bodies of a `declaration`
instruction. This is a prerequisite for #131.

In general, `declaration` now directly encodes details of the syntax
form used, and the embedded ZIR bodies are for actual expressions. The
only exception to this is functions, where ZIR is effectively designed
as if we had #1717. `extern fn` declarations are modeled as
`extern const` with a function type, and normal `fn` definitions are
modeled as `const` with a `func{,_fancy,_inferred}` instruction. This
may change in the future, but improving on this was out of scope for
this commit.
This commit is contained in:
mlugg 2024-12-17 00:41:01 +00:00
parent af5e731729
commit 18362ebe13
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
14 changed files with 1251 additions and 1122 deletions

File diff suppressed because it is too large Load diff

View file

@ -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,
// These fields should be concatenated and reinterpreted as a `Flags`.
flags_0: u32,
flags_1: u32,
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,
flags: Flags,
pub const Flags = packed struct(u32) {
value_body_len: u28,
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;

View file

@ -2018,7 +2018,6 @@ pub const Key = union(enum) {
ty: Index,
init: Index,
owner_nav: Nav.Index,
lib_name: OptionalNullTerminatedString,
is_threadlocal: bool,
is_weak_linkage: bool,
};
@ -2741,7 +2740,6 @@ pub const Key = union(enum) {
return a_info.owner_nav == b_info.owner_nav and
a_info.ty == b_info.ty and
a_info.init == b_info.init and
a_info.lib_name == b_info.lib_name and
a_info.is_threadlocal == b_info.is_threadlocal and
a_info.is_weak_linkage == b_info.is_weak_linkage;
},
@ -5573,9 +5571,6 @@ pub const Tag = enum(u8) {
/// May be `none`.
init: Index,
owner_nav: Nav.Index,
/// Library name if specified.
/// For example `extern "c" var stderrp = ...` would have 'c' as library name.
lib_name: OptionalNullTerminatedString,
flags: Flags,
pub const Flags = packed struct(u32) {
@ -6928,7 +6923,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
.ty = extra.ty,
.init = extra.init,
.owner_nav = extra.owner_nav,
.lib_name = extra.lib_name,
.is_threadlocal = extra.flags.is_threadlocal,
.is_weak_linkage = extra.flags.is_weak_linkage,
} };
@ -7575,7 +7569,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
.ty = variable.ty,
.init = variable.init,
.owner_nav = variable.owner_nav,
.lib_name = variable.lib_name,
.flags = .{
.is_const = false,
.is_threadlocal = variable.is_threadlocal,

View file

@ -1284,7 +1284,6 @@ fn analyzeBodyInner(
const extended = datas[@intFromEnum(inst)].extended;
break :ext switch (extended.opcode) {
// zig fmt: off
.variable => try sema.zirVarExtended( block, extended),
.struct_decl => try sema.zirStructDecl( block, extended, inst),
.enum_decl => try sema.zirEnumDecl( block, extended, inst),
.union_decl => try sema.zirUnionDecl( block, extended, inst),
@ -2114,13 +2113,33 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
}
/// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value.
/// InternPool key `variable` is considered a runtime value.
/// Generic poison causes `error.GenericPoison` to be returned.
fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
const val = (try sema.resolveValueAllowVariables(inst)) orelse return null;
const zcu = sema.pt.zcu;
assert(inst != .none);
if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
return opv;
}
if (inst.toInterned()) |ip_index| {
const val: Value = .fromInterned(ip_index);
assert(val.getVariable(zcu) == null);
if (val.isPtrRuntimeValue(zcu)) return null;
if (val.isGenericPoison()) return error.GenericPoison;
if (sema.pt.zcu.intern_pool.isVariable(val.toIntern())) return null;
return val;
} else {
// Runtime-known value.
const air_tags = sema.air_instructions.items(.tag);
switch (air_tags[@intFromEnum(inst.toIndex().?)]) {
.inferred_alloc => unreachable, // assertion failure
.inferred_alloc_comptime => unreachable, // assertion failure
else => {},
}
return null;
}
}
/// Like `resolveValue`, but emits an error if the value is not comptime-known.
@ -2183,35 +2202,6 @@ fn resolveValueIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
return try sema.resolveLazyValue(val);
}
/// Returns all InternPool keys representing values, including `variable`, `undef`, and `generic_poison`.
fn resolveValueAllowVariables(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
const pt = sema.pt;
assert(inst != .none);
// First section of indexes correspond to a set number of constant values.
if (@intFromEnum(inst) < InternPool.static_len) {
return Value.fromInterned(@as(InternPool.Index, @enumFromInt(@intFromEnum(inst))));
}
const air_tags = sema.air_instructions.items(.tag);
if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
if (inst.toInterned()) |ip_index| {
const val = Value.fromInterned(ip_index);
if (val.getVariable(pt.zcu) != null) return val;
}
return opv;
}
const ip_index = inst.toInterned() orelse {
switch (air_tags[@intFromEnum(inst.toIndex().?)]) {
.inferred_alloc => unreachable,
.inferred_alloc_comptime => unreachable,
else => return null,
}
};
const val = Value.fromInterned(ip_index);
if (val.isPtrRuntimeValue(pt.zcu)) return null;
return val;
}
/// Value Tag may be `undef` or `variable`.
pub fn resolveFinalDeclValue(
sema: *Sema,
@ -2221,8 +2211,13 @@ pub fn resolveFinalDeclValue(
) CompileError!Value {
const zcu = sema.pt.zcu;
const val = try sema.resolveValueAllowVariables(air_ref) orelse {
const value_comptime_reason: ?[]const u8 = if (air_ref.toInterned()) |_|
const val = try sema.resolveValue(air_ref) orelse {
const is_runtime_ptr = rt_ptr: {
const ip_index = air_ref.toInterned() orelse break :rt_ptr false;
const val: Value = .fromInterned(ip_index);
break :rt_ptr val.isPtrRuntimeValue(zcu);
};
const value_comptime_reason: ?[]const u8 = if (is_runtime_ptr)
"thread local and dll imported variables have runtime-known addresses"
else
null;
@ -2232,10 +2227,8 @@ pub fn resolveFinalDeclValue(
.value_comptime_reason = value_comptime_reason,
});
};
if (val.isGenericPoison()) return error.GenericPoison;
const init_val: Value = if (val.getVariable(zcu)) |v| .fromInterned(v.init) else val;
if (init_val.canMutateComptimeVarState(zcu)) {
if (val.canMutateComptimeVarState(zcu)) {
return sema.fail(block, src, "global variable contains reference to comptime var", .{});
}
@ -9525,8 +9518,8 @@ fn zirFunc(
} else sema.owner.unwrap().cau;
const fn_is_exported = exported: {
const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip) orelse return error.AnalysisFail;
const zir_decl = sema.code.getDeclaration(decl_inst)[0];
break :exported zir_decl.flags.is_export;
const zir_decl = sema.code.getDeclaration(decl_inst);
break :exported zir_decl.linkage == .@"export";
};
if (fn_is_exported) {
break :cc target.cCallingConvention() orelse {
@ -9557,10 +9550,8 @@ fn zirFunc(
ret_ty,
false,
inferred_error_set,
false,
has_body,
src_locs,
null,
0,
false,
);
@ -9619,7 +9610,7 @@ fn resolveGenericBody(
/// respective `Decl` (either `ExternFn` or `Var`).
/// The liveness of the duped library name is tied to liveness of `Zcu`.
/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
fn handleExternLibName(
pub fn handleExternLibName(
sema: *Sema,
block: *Block,
src_loc: LazySrcLoc,
@ -9843,10 +9834,8 @@ fn funcCommon(
bare_return_type: Type,
var_args: bool,
inferred_error_set: bool,
is_extern: bool,
has_body: bool,
src_locs: Zir.Inst.Func.SrcLocs,
opt_lib_name: ?[]const u8,
noalias_bits: u32,
is_noinline: bool,
) CompileError!Air.Inst.Ref {
@ -9998,7 +9987,6 @@ fn funcCommon(
}
if (inferred_error_set) {
assert(!is_extern);
assert(has_body);
if (!ret_poison)
try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
@ -10050,32 +10038,6 @@ fn funcCommon(
.is_noinline = is_noinline,
});
if (is_extern) {
assert(comptime_bits == 0);
assert(!is_generic);
if (opt_lib_name) |lib_name| try sema.handleExternLibName(block, block.src(.{
.node_offset_lib_name = src_node_offset,
}), lib_name);
const extern_func_index = try sema.resolveExternDecl(block, .fromInterned(func_ty), opt_lib_name, true, false);
return finishFunc(
sema,
block,
extern_func_index,
func_ty,
ret_poison,
bare_return_type,
ret_ty_src,
cc,
is_source_decl,
ret_ty_requires_comptime,
func_inst,
cc_src,
is_noinline,
is_generic,
final_is_generic,
);
}
if (has_body) {
const func_index = try ip.getFuncDecl(gpa, pt.tid, .{
.owner_nav = sema.getOwnerCauNav(),
@ -26711,135 +26673,6 @@ fn zirAwaitNosuspend(
return sema.failWithUseOfAsync(block, src);
}
fn zirVarExtended(
sema: *Sema,
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
const small: Zir.Inst.ExtendedVar.Small = @bitCast(extended.small);
var extra_index: usize = extra.end;
const lib_name = if (small.has_lib_name) lib_name: {
const lib_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
const lib_name = sema.code.nullTerminatedString(lib_name_index);
extra_index += 1;
try sema.handleExternLibName(block, ty_src, lib_name);
break :lib_name lib_name;
} else null;
// ZIR supports encoding this information but it is not used; the information
// is encoded via the Decl entry.
assert(!small.has_align);
const uncasted_init: Air.Inst.Ref = if (small.has_init) blk: {
const init_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
extra_index += 1;
break :blk try sema.resolveInst(init_ref);
} else .none;
const have_ty = extra.data.var_type != .none;
const var_ty = if (have_ty)
try sema.resolveType(block, ty_src, extra.data.var_type)
else
sema.typeOf(uncasted_init);
const init_val = if (uncasted_init != .none) blk: {
const init = if (have_ty)
try sema.coerce(block, var_ty, uncasted_init, init_src)
else
uncasted_init;
break :blk ((try sema.resolveValue(init)) orelse {
return sema.failWithNeededComptime(block, init_src, .{
.needed_comptime_reason = "container level variable initializers must be comptime-known",
});
}).toIntern();
} else .none;
try sema.validateVarType(block, ty_src, var_ty, small.is_extern);
if (small.is_extern) {
const extern_val = try sema.resolveExternDecl(block, var_ty, lib_name, small.is_const, small.is_threadlocal);
return Air.internedToRef(extern_val);
}
assert(!small.is_const); // non-const non-extern variable is not legal
return Air.internedToRef(try pt.intern(.{ .variable = .{
.ty = var_ty.toIntern(),
.init = init_val,
.owner_nav = sema.getOwnerCauNav(),
.lib_name = try ip.getOrPutStringOpt(sema.gpa, pt.tid, lib_name, .no_embedded_nulls),
.is_threadlocal = small.is_threadlocal,
.is_weak_linkage = false,
} }));
}
fn resolveExternDecl(
sema: *Sema,
block: *Block,
ty: Type,
opt_lib_name: ?[]const u8,
is_const: bool,
is_threadlocal: bool,
) CompileError!InternPool.Index {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
// We need to resolve the alignment and addrspace early.
// Keep in sync with logic in `Zcu.PerThread.semaCau`.
const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
const decl_inst, const decl_bodies = decl: {
const decl_inst = sema.getOwnerCauDeclInst().resolve(ip) orelse return error.AnalysisFail;
const zir_decl, const extra_end = sema.code.getDeclaration(decl_inst);
break :decl .{ decl_inst, zir_decl.getBodies(extra_end, sema.code) };
};
const alignment: InternPool.Alignment = a: {
const align_body = decl_bodies.align_body orelse break :a .none;
const align_ref = try sema.resolveInlineBody(block, align_body, decl_inst);
break :a try sema.analyzeAsAlign(block, align_src, align_ref);
};
const @"addrspace": std.builtin.AddressSpace = as: {
const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(ty.toIntern())) {
.func_type => .function,
else => .variable,
};
const target = zcu.getTarget();
const addrspace_body = decl_bodies.addrspace_body orelse break :as switch (addrspace_ctx) {
.function => target_util.defaultAddressSpace(target, .function),
.variable => target_util.defaultAddressSpace(target, .global_mutable),
.constant => target_util.defaultAddressSpace(target, .global_constant),
else => unreachable,
};
const addrspace_ref = try sema.resolveInlineBody(block, addrspace_body, decl_inst);
break :as try sema.analyzeAsAddressSpace(block, addrspace_src, addrspace_ref, addrspace_ctx);
};
return pt.getExtern(.{
.name = sema.getOwnerCauNavName(),
.ty = ty.toIntern(),
.lib_name = try ip.getOrPutStringOpt(sema.gpa, pt.tid, opt_lib_name, .no_embedded_nulls),
.is_const = is_const,
.is_threadlocal = is_threadlocal,
.is_weak_linkage = false,
.is_dll_import = false,
.alignment = alignment,
.@"addrspace" = @"addrspace",
.zir_index = sema.getOwnerCauDeclInst(), // `declaration` instruction
.owner_nav = undefined, // ignored by `getExtern`
});
}
fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@ -26857,13 +26690,6 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
var extra_index: usize = extra.end;
const lib_name: ?[]const u8 = if (extra.data.bits.has_lib_name) blk: {
const lib_name_index: Zir.NullTerminatedString = @enumFromInt(sema.code.extra[extra_index]);
const lib_name = sema.code.nullTerminatedString(lib_name_index);
extra_index += 1;
break :blk lib_name;
} else null;
const cc: std.builtin.CallingConvention = if (extra.data.bits.has_cc_body) blk: {
const body_len = sema.code.extra[extra_index];
extra_index += 1;
@ -26895,8 +26721,8 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
break :decl_inst cau.zir_index;
} else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau
const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&zcu.intern_pool) orelse return error.AnalysisFail)[0];
if (zir_decl.flags.is_export) {
const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&zcu.intern_pool) orelse return error.AnalysisFail);
if (zir_decl.linkage == .@"export") {
break :cc target.cCallingConvention() orelse {
// This target has no default C calling convention. We sometimes trigger a similar
// error by trying to evaluate `std.builtin.CallingConvention.c`, so for consistency,
@ -26958,7 +26784,6 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const is_var_args = extra.data.bits.is_var_args;
const is_inferred_error = extra.data.bits.is_inferred_error;
const is_extern = extra.data.bits.is_extern;
const is_noinline = extra.data.bits.is_noinline;
return sema.funcCommon(
@ -26969,10 +26794,8 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
ret_ty,
is_var_args,
is_inferred_error,
is_extern,
has_body,
src_locs,
lib_name,
noalias_bits,
is_noinline,
);
@ -27467,7 +27290,7 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
}
/// Emit a compile error if type cannot be used for a runtime variable.
fn validateVarType(
pub fn validateVarType(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
@ -29881,7 +29704,7 @@ fn elemPtrSlice(
return block.addSliceElemPtr(slice, elem_index, elem_ptr_ty);
}
fn coerce(
pub fn coerce(
sema: *Sema,
block: *Block,
dest_ty_unresolved: Type,
@ -38843,13 +38666,6 @@ fn getOwnerCauNav(sema: *Sema) InternPool.Nav.Index {
return sema.pt.zcu.intern_pool.getCau(cau).owner.unwrap().nav;
}
/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
/// the declaration name from its corresponding `Nav`.
fn getOwnerCauNavName(sema: *Sema) InternPool.NullTerminatedString {
const nav = sema.getOwnerCauNav();
return sema.pt.zcu.intern_pool.getNav(nav).name;
}
/// Given that this `Sema` is owned by the `Cau` of a `declaration`, fetches
/// the `TrackedInst` corresponding to this `declaration` instruction.
fn getOwnerCauDeclInst(sema: *Sema) InternPool.TrackedInst.Index {

View file

@ -2679,24 +2679,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 +2697,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 +2705,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 +2721,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 {
.@"test" => inst: {
const name = new_zir.nullTerminatedString(new_decl.name);
break :inst named_tests.get(name) orelse continue;
}
} else {
},
.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;
}
},
};
@ -3353,20 +3342,20 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
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);
const want_analysis = switch (decl.kind) {
.@"usingnamespace" => unreachable,
.@"const", .@"var" => unreachable,
.@"comptime" => true,
else => a: {
.unnamed_test => comp.config.is_test and file.mod == zcu.main_mod,
.@"test", .decltest => 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;
}
break :a true;
},
};
@ -3388,8 +3377,8 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
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 decl = zir.getDeclaration(inst_info.inst);
if (decl.linkage == .@"export") {
const unit = AnalUnit.wrap(.{ .cau = cau });
if (!result.contains(unit)) {
log.debug("type '{}': ref cau %{}", .{
@ -3407,8 +3396,8 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
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 decl = zir.getDeclaration(inst_info.inst);
if (decl.linkage == .@"export") {
const unit = AnalUnit.wrap(.{ .cau = cau });
if (!result.contains(unit)) {
log.debug("type '{}': ref cau %{}", .{
@ -3522,9 +3511,7 @@ 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 {

View file

@ -469,12 +469,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
{
var it = old_zir.declIterator(old_inst);
while (it.next()) |decl_inst| {
const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
switch (decl_name) {
.@"comptime", .@"usingnamespace", .unnamed_test => continue,
_ => if (decl_name.isNamedTest(old_zir)) continue,
}
const name_zir = decl_name.toString(old_zir).?;
const name_zir = old_zir.getDeclaration(decl_inst).name;
if (name_zir == .empty) continue;
const name_ip = try zcu.intern_pool.getOrPutString(
zcu.gpa,
pt.tid,
@ -488,12 +484,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
{
var it = new_zir.declIterator(new_inst);
while (it.next()) |decl_inst| {
const decl_name = new_zir.getDeclaration(decl_inst)[0].name;
switch (decl_name) {
.@"comptime", .@"usingnamespace", .unnamed_test => continue,
_ => if (decl_name.isNamedTest(new_zir)) continue,
}
const name_zir = decl_name.toString(new_zir).?;
const name_zir = new_zir.getDeclaration(decl_inst).name;
if (name_zir == .empty) continue;
const name_ip = try zcu.intern_pool.getOrPutString(
zcu.gpa,
pt.tid,
@ -1252,10 +1244,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
};
defer block.instructions.deinit(gpa);
const zir_decl: Zir.Inst.Declaration, const decl_bodies: Zir.Inst.Declaration.Bodies = decl: {
const decl, const extra_end = zir.getDeclaration(inst_info.inst);
break :decl .{ decl, decl.getBodies(extra_end, zir) };
};
const zir_decl = zir.getDeclaration(inst_info.inst);
// We have to fetch this state before resolving the body because of the `nav_already_populated`
// case below. We might change the language in future so that align/linksection/etc for functions
@ -1265,7 +1254,134 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
.nav => |nav| ip.getNav(nav),
};
const result_ref = try sema.resolveInlineBody(&block, decl_bodies.value_body, inst_info.inst);
const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
// First, we must resolve the declaration's type. To do this, we analyze the type body if available,
// or otherwise, we analyze the value body, populating `early_val` in the process.
const decl_ty: Type, const early_val: ?Value = if (zir_decl.type_body) |type_body| ty: {
// We evaluate only the type now; no need for the value yet.
const uncoerced_type_ref = try sema.resolveInlineBody(&block, type_body, inst_info.inst);
const type_ref = try sema.coerce(&block, .type, uncoerced_type_ref, ty_src);
break :ty .{ .fromInterned(type_ref.toInterned().?), null };
} else ty: {
// We don't have a type body, so we need to evaluate the value immediately.
const value_body = zir_decl.value_body.?;
const result_ref = try sema.resolveInlineBody(&block, value_body, inst_info.inst);
const val = try sema.resolveFinalDeclValue(&block, init_src, result_ref);
break :ty .{ val.typeOf(zcu), val };
};
switch (zir_decl.kind) {
.unnamed_test, .@"test", .decltest => assert(decl_ty.zigTypeTag(zcu) == .@"fn"),
.@"comptime" => assert(decl_ty.toIntern() == .void_type),
.@"usingnamespace" => {},
.@"const" => {},
.@"var" => try sema.validateVarType(
&block,
if (zir_decl.type_body != null) ty_src else init_src,
decl_ty,
zir_decl.linkage == .@"extern",
),
}
// Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
// the full pointer type of this declaration.
const alignment: InternPool.Alignment = a: {
const align_body = zir_decl.align_body orelse break :a .none;
const align_ref = try sema.resolveInlineBody(&block, align_body, inst_info.inst);
break :a try sema.analyzeAsAlign(&block, align_src, align_ref);
};
const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
const linksection_body = zir_decl.linksection_body orelse break :ls .none;
const linksection_ref = try sema.resolveInlineBody(&block, linksection_body, inst_info.inst);
const bytes = try sema.toConstString(&block, section_src, linksection_ref, .{
.needed_comptime_reason = "linksection must be comptime-known",
});
if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
return sema.fail(&block, section_src, "linksection cannot contain null bytes", .{});
} else if (bytes.len == 0) {
return sema.fail(&block, section_src, "linksection cannot be empty", .{});
}
break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
};
const @"addrspace": std.builtin.AddressSpace = as: {
const addrspace_ctx: Sema.AddressSpaceContext = switch (zir_decl.kind) {
.@"var" => .variable,
else => switch (decl_ty.zigTypeTag(zcu)) {
.@"fn" => .function,
else => .constant,
},
};
const target = zcu.getTarget();
const addrspace_body = zir_decl.addrspace_body orelse break :as switch (addrspace_ctx) {
.function => target_util.defaultAddressSpace(target, .function),
.variable => target_util.defaultAddressSpace(target, .global_mutable),
.constant => target_util.defaultAddressSpace(target, .global_constant),
else => unreachable,
};
const addrspace_ref = try sema.resolveInlineBody(&block, addrspace_body, inst_info.inst);
break :as try sema.analyzeAsAddressSpace(&block, addrspace_src, addrspace_ref, addrspace_ctx);
};
// Lastly, we must evaluate the value if we have not already done so. Note, however, that extern declarations
// don't have an associated value body.
const final_val: ?Value = early_val orelse if (zir_decl.value_body) |value_body| val: {
// Put the resolved type into `inst_map` to be used as the result type of the init.
try sema.inst_map.ensureSpaceForInstructions(gpa, &.{inst_info.inst});
sema.inst_map.putAssumeCapacity(inst_info.inst, Air.internedToRef(decl_ty.toIntern()));
const uncoerced_result_ref = try sema.resolveInlineBody(&block, value_body, inst_info.inst);
assert(sema.inst_map.remove(inst_info.inst));
const result_ref = try sema.coerce(&block, decl_ty, uncoerced_result_ref, init_src);
break :val try sema.resolveFinalDeclValue(&block, init_src, result_ref);
} else null;
// TODO: missing validation?
const decl_val: Value = switch (zir_decl.linkage) {
.normal, .@"export" => switch (zir_decl.kind) {
.@"var" => .fromInterned(try pt.intern(.{ .variable = .{
.ty = decl_ty.toIntern(),
.init = final_val.?.toIntern(),
.owner_nav = cau.owner.unwrap().nav,
.is_threadlocal = zir_decl.is_threadlocal,
.is_weak_linkage = false,
} })),
else => final_val.?,
},
.@"extern" => val: {
assert(final_val == null); // extern decls do not have a value body
const lib_name: ?[]const u8 = if (zir_decl.lib_name != .empty) l: {
break :l zir.nullTerminatedString(zir_decl.lib_name);
} else null;
if (lib_name) |l| {
const lib_name_src = block.src(.{ .node_offset_lib_name = 0 });
try sema.handleExternLibName(&block, lib_name_src, l);
}
break :val .fromInterned(try pt.getExtern(.{
.name = old_nav_info.name,
.ty = decl_ty.toIntern(),
.lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
.is_const = zir_decl.kind == .@"const",
.is_threadlocal = zir_decl.is_threadlocal,
.is_weak_linkage = false,
.is_dll_import = false,
.alignment = alignment,
.@"addrspace" = @"addrspace",
.zir_index = cau.zir_index, // `declaration` instruction
.owner_nav = undefined, // ignored by `getExtern`
}));
},
};
const nav_index = switch (cau.owner.unwrap()) {
.none => {
@ -1282,15 +1398,6 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
.type => unreachable, // Handled at top of function.
};
const align_src = block.src(.{ .node_offset_var_decl_align = 0 });
const section_src = block.src(.{ .node_offset_var_decl_section = 0 });
const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
const ty_src = block.src(.{ .node_offset_var_decl_ty = 0 });
const init_src = block.src(.{ .node_offset_var_decl_init = 0 });
const decl_val = try sema.resolveFinalDeclValue(&block, init_src, result_ref);
const decl_ty = decl_val.typeOf(zcu);
switch (decl_val.toIntern()) {
.generic_poison => unreachable, // assertion failure
.unreachable_value => unreachable, // assertion failure
@ -1331,50 +1438,10 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
};
// Keep in sync with logic in `Sema.zirVarExtended`.
const alignment: InternPool.Alignment = a: {
const align_body = decl_bodies.align_body orelse break :a .none;
const align_ref = try sema.resolveInlineBody(&block, align_body, inst_info.inst);
break :a try sema.analyzeAsAlign(&block, align_src, align_ref);
};
const @"linksection": InternPool.OptionalNullTerminatedString = ls: {
const linksection_body = decl_bodies.linksection_body orelse break :ls .none;
const linksection_ref = try sema.resolveInlineBody(&block, linksection_body, inst_info.inst);
const bytes = try sema.toConstString(&block, section_src, linksection_ref, .{
.needed_comptime_reason = "linksection must be comptime-known",
});
if (std.mem.indexOfScalar(u8, bytes, 0) != null) {
return sema.fail(&block, section_src, "linksection cannot contain null bytes", .{});
} else if (bytes.len == 0) {
return sema.fail(&block, section_src, "linksection cannot be empty", .{});
}
break :ls try ip.getOrPutStringOpt(gpa, pt.tid, bytes, .no_embedded_nulls);
};
const @"addrspace": std.builtin.AddressSpace = as: {
const addrspace_ctx: Sema.AddressSpaceContext = switch (ip.indexToKey(decl_val.toIntern())) {
.func => .function,
.variable => .variable,
.@"extern" => |e| if (ip.indexToKey(e.ty) == .func_type)
.function
else
.variable,
else => .constant,
};
const target = zcu.getTarget();
const addrspace_body = decl_bodies.addrspace_body orelse break :as switch (addrspace_ctx) {
.function => target_util.defaultAddressSpace(target, .function),
.variable => target_util.defaultAddressSpace(target, .global_mutable),
.constant => target_util.defaultAddressSpace(target, .global_constant),
else => unreachable,
};
const addrspace_ref = try sema.resolveInlineBody(&block, addrspace_body, inst_info.inst);
break :as try sema.analyzeAsAddressSpace(&block, addrspace_src, addrspace_ref, addrspace_ctx);
};
if (is_owned_fn) {
// linksection etc are legal, except some targets do not support function alignment.
if (decl_bodies.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
return sema.fail(&block, align_src, "target does not support function alignment", .{});
}
} else if (try decl_ty.comptimeOnlySema(pt)) {
@ -1383,13 +1450,13 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
.func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
else => "comptime-only type",
};
if (decl_bodies.align_body != null) {
if (zir_decl.align_body != null) {
return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});
}
if (decl_bodies.linksection_body != null) {
if (zir_decl.linksection_body != null) {
return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});
}
if (decl_bodies.addrspace_body != null) {
if (zir_decl.addrspace_body != null) {
return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});
}
}
@ -1404,9 +1471,9 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
// Mark the `Cau` as completed before evaluating the export!
assert(zcu.analysis_in_progress.swapRemove(anal_unit));
if (zir_decl.flags.is_export) {
const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.flags.is_pub) });
const name_slice = zir.nullTerminatedString(zir_decl.name.toString(zir).?);
if (zir_decl.linkage == .@"export") {
const export_src = block.src(.{ .token_offset = @intFromBool(zir_decl.is_pub) });
const name_slice = zir.nullTerminatedString(zir_decl.name);
const name_ip = try ip.getOrPutString(gpa, pt.tid, name_slice, .no_embedded_nulls);
try sema.analyzeExport(&block, export_src, .{ .name = name_ip }, nav_index);
}
@ -1919,13 +1986,11 @@ const ScanDeclIter = struct {
const zir = file.zir;
const ip = &zcu.intern_pool;
const inst_data = zir.instructions.items(.data)[@intFromEnum(decl_inst)].declaration;
const extra = zir.extraData(Zir.Inst.Declaration, inst_data.payload_index);
const declaration = extra.data;
const decl = zir.getDeclaration(decl_inst);
const Kind = enum { @"comptime", @"usingnamespace", @"test", named };
const maybe_name: InternPool.OptionalNullTerminatedString, const kind: Kind, const is_named_test: bool = switch (declaration.name) {
const maybe_name: InternPool.OptionalNullTerminatedString, const kind: Kind, const is_named_test: bool = switch (decl.kind) {
.@"comptime" => info: {
if (iter.pass != .unnamed) return;
break :info .{
@ -1954,21 +2019,22 @@ const ScanDeclIter = struct {
false,
};
},
_ => if (declaration.name.isNamedTest(zir)) info: {
.@"test", .decltest => |kind| info: {
// We consider these to be unnamed since the decl name can be adjusted to avoid conflicts if necessary.
if (iter.pass != .unnamed) return;
const prefix = if (declaration.flags.test_is_decltest) "decltest" else "test";
const prefix = @tagName(kind);
break :info .{
(try iter.avoidNameConflict("{s}.{s}", .{ prefix, zir.nullTerminatedString(declaration.name.toString(zir).?) })).toOptional(),
(try iter.avoidNameConflict("{s}.{s}", .{ prefix, zir.nullTerminatedString(decl.name) })).toOptional(),
.@"test",
true,
};
} else info: {
},
.@"const", .@"var" => info: {
if (iter.pass != .named) return;
const name = try ip.getOrPutString(
gpa,
pt.tid,
zir.nullTerminatedString(declaration.name.toString(zir).?),
zir.nullTerminatedString(decl.name),
.no_embedded_nulls,
);
try iter.seen_decls.putNoClobber(gpa, name, {});
@ -2030,7 +2096,7 @@ const ScanDeclIter = struct {
if (comp.incremental) {
@panic("'usingnamespace' is not supported by incremental compilation");
}
if (declaration.flags.is_pub) {
if (decl.is_pub) {
try namespace.pub_usingnamespace.append(gpa, nav);
} else {
try namespace.priv_usingnamespace.append(gpa, nav);
@ -2056,7 +2122,7 @@ const ScanDeclIter = struct {
break :a true;
},
.named => a: {
if (declaration.flags.is_pub) {
if (decl.is_pub) {
try namespace.pub_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
} else {
try namespace.priv_decls.putContext(gpa, nav, {}, .{ .zcu = zcu });
@ -2068,7 +2134,7 @@ const ScanDeclIter = struct {
},
};
if (existing_cau == null and (want_analysis or declaration.flags.is_export)) {
if (existing_cau == null and (want_analysis or decl.linkage == .@"export")) {
log.debug(
"scanDecl queue analyze_cau file='{s}' cau_index={d}",
.{ namespace.fileScope(zcu).sub_file_path, cau },

View file

@ -853,7 +853,7 @@ 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 },
.variable => |variable| .{ variable.owner_nav, false, .none, variable.is_threadlocal },
.@"extern" => |@"extern"| .{ @"extern".owner_nav, true, @"extern".lib_name, @"extern".is_threadlocal },
else => .{ ref_nav_index, false, .none, false },
};

View file

@ -2939,7 +2939,6 @@ pub const Object = struct {
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 },
};
@ -4803,7 +4802,7 @@ pub const NavGen = struct {
const resolved = nav.status.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 },
};

View file

@ -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);
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 };
@ -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);
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 };
@ -2341,24 +2319,13 @@ pub fn initWipNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.In
},
.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);
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 };
@ -2585,12 +2552,11 @@ 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.
@ -2601,7 +2567,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool
const parent_namespace_ptr = ip.namespacePtr(ip.getCau(cau).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 };
@ -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);

View file

@ -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

View file

@ -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(") ");

View file

@ -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

View file

@ -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

View file

@ -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