stage2: implement structs in the frontend

New ZIR instructions:
 * struct_decl_packed
 * struct_decl_extern

New TZIR instruction: struct_field_ptr

Introduce `Module.Struct`. It uses `Value` to store default values and
abi alignments.

Implemented Sema.analyzeStructFieldPtr and zirStructDecl.

Some stuff I changed from `@panic("TODO")` to `log.warn("TODO")`.
It's becoming more clear that we need the lazy value mechanism soon;
Type is becoming unruly, and some of these functions have too much logic
given that they don't have any context for memory management or error
reporting.
This commit is contained in:
Andrew Kelley
2021-04-01 22:34:40 -07:00
parent c66b48194f
commit 8ebfdc14f6
8 changed files with 304 additions and 16 deletions

View File

@@ -1322,6 +1322,8 @@ fn blockExprStmts(
.switch_capture_else_ref,
.struct_init_empty,
.struct_decl,
.struct_decl_packed,
.struct_decl_extern,
.union_decl,
.enum_decl,
.opaque_decl,
@@ -1789,8 +1791,13 @@ fn containerDecl(
switch (token_tags[container_decl.ast.main_token]) {
.keyword_struct => {
const tag = if (container_decl.layout_token) |t| switch (token_tags[t]) {
.keyword_packed => zir.Inst.Tag.struct_decl_packed,
.keyword_extern => zir.Inst.Tag.struct_decl_extern,
else => unreachable,
} else zir.Inst.Tag.struct_decl;
if (container_decl.ast.members.len == 0) {
const result = try gz.addPlNode(.struct_decl, node, zir.Inst.StructDecl{
const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
.fields_len = 0,
});
return rvalue(gz, scope, rl, result, node);
@@ -1856,7 +1863,7 @@ fn containerDecl(
const empty_slot_count = 16 - ((member_index - 1) % 16);
cur_bit_bag >>= @intCast(u5, empty_slot_count * 2);
const result = try gz.addPlNode(.struct_decl, node, zir.Inst.StructDecl{
const result = try gz.addPlNode(tag, node, zir.Inst.StructDecl{
.fields_len = @intCast(u32, container_decl.ast.members.len),
});
try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +

View File

@@ -356,6 +356,25 @@ pub const ErrorSet = struct {
names_ptr: [*]const []const u8,
};
/// Represents the data that a struct declaration provides.
pub const Struct = struct {
owner_decl: *Decl,
/// Set of field names in declaration order.
fields: std.StringArrayHashMapUnmanaged(Field),
/// Represents the declarations inside this struct.
container: Scope.Container,
/// Offset from Decl node index, points to the struct AST node.
node_offset: i32,
pub const Field = struct {
ty: Type,
abi_align: Value,
/// Uses `unreachable_value` to indicate no default.
default_val: Value,
};
};
/// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
/// Extern functions do not have this data structure; they are represented by
/// the `Decl` only, with a `Value` tag of `extern_fn`.
@@ -822,6 +841,7 @@ pub const Scope = struct {
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addBr(
scope_block: *Scope.Block,
src: LazySrcLoc,
@@ -920,6 +940,27 @@ pub const Scope = struct {
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
pub fn addStructFieldPtr(
block: *Scope.Block,
src: LazySrcLoc,
ty: Type,
struct_ptr: *ir.Inst,
field_index: u32,
) !*ir.Inst {
const inst = try block.sema.arena.create(ir.Inst.StructFieldPtr);
inst.* = .{
.base = .{
.tag = .struct_field_ptr,
.ty = ty,
.src = src,
},
.struct_ptr = struct_ptr,
.field_index = field_index,
};
try block.instructions.append(block.sema.gpa, &inst.base);
return &inst.base;
}
};
/// This is a temporary structure; references to it are valid only

View File

@@ -261,7 +261,9 @@ pub fn analyzeBody(
.xor => try sema.zirBitwise(block, inst, .xor),
.struct_init_empty => try sema.zirStructInitEmpty(block, inst),
.struct_decl => try sema.zirStructDecl(block, inst),
.struct_decl => try sema.zirStructDecl(block, inst, .Auto),
.struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
.struct_decl_extern => try sema.zirStructDecl(block, inst, .Extern),
.enum_decl => try sema.zirEnumDecl(block, inst),
.union_decl => try sema.zirUnionDecl(block, inst),
.opaque_decl => try sema.zirOpaqueDecl(block, inst),
@@ -520,21 +522,98 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
return sema.mod.fail(&block.base, sema.src, "TODO implement zirCoerceResultPtr", .{});
}
fn zirStructDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
fn zirStructDecl(
sema: *Sema,
block: *Scope.Block,
inst: zir.Inst.Index,
layout: std.builtin.TypeInfo.ContainerLayout,
) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
const gpa = sema.gpa;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
const extra = sema.code.extraData(zir.Inst.StructDecl, inst_data.payload_index);
const fields_len = extra.data.fields_len;
const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable;
return sema.mod.fail(&block.base, sema.src, "TODO implement zirStructDecl", .{});
var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
errdefer new_decl_arena.deinit();
//const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
// .ty = decl_ty,
// .val = decl_val,
//});
//return sema.analyzeDeclVal(block, src, new_decl);
var fields_map: std.StringArrayHashMapUnmanaged(Module.Struct.Field) = .{};
try fields_map.ensureCapacity(&new_decl_arena.allocator, fields_len);
{
var field_index: usize = extra.end + bit_bags_count;
var bit_bag_index: usize = extra.end;
var cur_bit_bag: u32 = undefined;
var field_i: u32 = 0;
while (field_i < fields_len) : (field_i += 1) {
if (field_i % 16 == 0) {
cur_bit_bag = sema.code.extra[bit_bag_index];
bit_bag_index += 1;
}
const has_align = @truncate(u1, cur_bit_bag) != 0;
cur_bit_bag >>= 1;
const has_default = @truncate(u1, cur_bit_bag) != 0;
cur_bit_bag >>= 1;
const field_name_zir = sema.code.nullTerminatedString(sema.code.extra[field_index]);
field_index += 1;
const field_type_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]);
field_index += 1;
// This string needs to outlive the ZIR code.
const field_name = try new_decl_arena.allocator.dupe(u8, field_name_zir);
// TODO: if we need to report an error here, use a source location
// that points to this type expression rather than the struct.
// But only resolve the source location if we need to emit a compile error.
const field_ty = try sema.resolveType(block, src, field_type_ref);
const gop = fields_map.getOrPutAssumeCapacity(field_name);
assert(!gop.found_existing);
gop.entry.value = .{
.ty = field_ty,
.abi_align = Value.initTag(.abi_align_default),
.default_val = Value.initTag(.unreachable_value),
};
if (has_align) {
const align_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]);
field_index += 1;
// TODO: if we need to report an error here, use a source location
// that points to this alignment expression rather than the struct.
// But only resolve the source location if we need to emit a compile error.
gop.entry.value.abi_align = (try sema.resolveInstConst(block, src, align_ref)).val;
}
if (has_default) {
const default_ref = @intToEnum(zir.Inst.Ref, sema.code.extra[field_index]);
field_index += 1;
// TODO: if we need to report an error here, use a source location
// that points to this default value expression rather than the struct.
// But only resolve the source location if we need to emit a compile error.
gop.entry.value.default_val = (try sema.resolveInstConst(block, src, default_ref)).val;
}
}
}
const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
struct_obj.* = .{
.owner_decl = sema.owner_decl,
.fields = fields_map,
.node_offset = inst_data.src_node,
.container = .{
.ty = struct_ty,
.file_scope = block.getFileScope(),
},
};
const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
.ty = Type.initTag(.type),
.val = try Value.Tag.ty.create(gpa, struct_ty),
});
return sema.analyzeDeclVal(block, src, new_decl);
}
fn zirEnumDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
@@ -763,7 +842,7 @@ fn zirValidateStructInitPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Ind
const extra = sema.code.extraData(zir.Inst.Block, inst_data.payload_index);
const instrs = sema.code.extra[extra.end..][0..extra.data.body_len];
return sema.mod.fail(&block.base, src, "TODO implement zirValidateStructInitPtr", .{});
log.warn("TODO implement zirValidateStructInitPtr (compile errors for missing/dupe fields)", .{});
}
fn zirStoreToBlockPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
@@ -4141,11 +4220,40 @@ fn namedFieldPtr(
else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
}
},
.Struct => return sema.analyzeStructFieldPtr(block, src, object_ptr, field_name, field_name_src, elem_ty),
else => {},
}
return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
}
fn analyzeStructFieldPtr(
sema: *Sema,
block: *Scope.Block,
src: LazySrcLoc,
struct_ptr: *Inst,
field_name: []const u8,
field_name_src: LazySrcLoc,
elem_ty: Type,
) InnerError!*Inst {
const mod = sema.mod;
const arena = sema.arena;
assert(elem_ty.zigTypeTag() == .Struct);
const struct_obj = elem_ty.castTag(.@"struct").?.data;
const field_index = struct_obj.fields.getIndex(field_name) orelse {
// TODO note: struct S declared here
return mod.fail(&block.base, field_name_src, "no field named '{s}' in struct '{}'", .{
field_name, elem_ty,
});
};
const field = struct_obj.fields.entries.items[field_index].value;
const ptr_field_ty = try mod.simplePtrType(arena, field.ty, true, .One);
// TODO comptime field access
try sema.requireRuntimeBlock(block, src);
return block.addStructFieldPtr(src, ptr_field_ty, struct_ptr, @intCast(u32, field_index));
}
fn elemPtr(
sema: *Sema,
block: *Scope.Block,

View File

@@ -910,6 +910,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
.ret => return self.genRet(inst.castTag(.ret).?),
.retvoid => return self.genRetVoid(inst.castTag(.retvoid).?),
.store => return self.genStore(inst.castTag(.store).?),
.struct_field_ptr => return self.genStructFieldPtr(inst.castTag(.struct_field_ptr).?),
.sub => return self.genSub(inst.castTag(.sub).?),
.subwrap => return self.genSubWrap(inst.castTag(.subwrap).?),
.switchbr => return self.genSwitch(inst.castTag(.switchbr).?),
@@ -1403,6 +1404,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
return .none;
}
fn genStructFieldPtr(self: *Self, inst: *ir.Inst.StructFieldPtr) !MCValue {
return self.fail(inst.base.src, "TODO implement codegen struct_field_ptr", .{});
}
fn genSub(self: *Self, inst: *ir.Inst.BinOp) !MCValue {
// No side effects, so if it's unreferenced, do nothing.
if (inst.base.isUnused())

View File

@@ -137,6 +137,8 @@ pub const Inst = struct {
wrap_errunion_err,
xor,
switchbr,
/// Given a pointer to a struct and a field index, returns a pointer to the field.
struct_field_ptr,
pub fn Type(tag: Tag) type {
return switch (tag) {
@@ -204,6 +206,7 @@ pub const Inst = struct {
.constant => Constant,
.loop => Loop,
.varptr => VarPtr,
.struct_field_ptr => StructFieldPtr,
.switchbr => SwitchBr,
.dbg_stmt => DbgStmt,
};
@@ -552,6 +555,27 @@ pub const Inst = struct {
}
};
pub const StructFieldPtr = struct {
pub const base_tag = Tag.struct_field_ptr;
base: Inst,
struct_ptr: *Inst,
field_index: usize,
pub fn operandCount(self: *const StructFieldPtr) usize {
return 1;
}
pub fn getOperand(self: *const StructFieldPtr, index: usize) ?*Inst {
var i = index;
if (i < 1)
return self.struct_ptr;
i -= 1;
return null;
}
};
pub const SwitchBr = struct {
pub const base_tag = Tag.switchbr;
@@ -794,6 +818,10 @@ const DumpTzir = struct {
try dtz.findConst(arg);
}
},
.struct_field_ptr => {
const struct_field_ptr = inst.castTag(.struct_field_ptr).?;
try dtz.findConst(struct_field_ptr.struct_ptr);
},
// TODO fill out this debug printing
.assembly,
@@ -1067,6 +1095,18 @@ const DumpTzir = struct {
}
},
.struct_field_ptr => {
const struct_field_ptr = inst.castTag(.struct_field_ptr).?;
const kinky = try dtz.writeInst(writer, struct_field_ptr.struct_ptr);
if (kinky != null) {
try writer.print("{d}) // Instruction does not dominate all uses!\n", .{
struct_field_ptr.field_index,
});
} else {
try writer.print("{d})\n", .{struct_field_ptr.field_index});
}
},
// TODO fill out this debug printing
.assembly,
.constant,

View File

@@ -4,6 +4,7 @@ const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const Target = std.Target;
const Module = @import("Module.zig");
const log = std.log.scoped(.Type);
/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
/// It's important for this type to be small.
@@ -94,6 +95,7 @@ pub const Type = extern union {
.empty_struct => return .Struct,
.empty_struct_literal => return .Struct,
.@"struct" => return .Struct,
.var_args_param => unreachable, // can be any type
}
@@ -611,7 +613,7 @@ pub const Type = extern union {
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
.error_set_single => return self.copyPayloadShallow(allocator, Payload.Name),
.empty_struct => return self.copyPayloadShallow(allocator, Payload.ContainerScope),
.@"struct" => return self.copyPayloadShallow(allocator, Payload.Struct),
.@"opaque" => return self.copyPayloadShallow(allocator, Payload.Opaque),
}
}
@@ -675,6 +677,7 @@ pub const Type = extern union {
.@"undefined" => return out_stream.writeAll("@Type(.Undefined)"),
.empty_struct, .empty_struct_literal => return out_stream.writeAll("struct {}"),
.@"struct" => return out_stream.writeAll("(struct)"),
.anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
.fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
@@ -940,6 +943,18 @@ pub const Type = extern union {
.error_set,
.error_set_single,
=> true,
.@"struct" => {
// TODO introduce lazy value mechanism
const struct_obj = self.castTag(.@"struct").?.data;
for (struct_obj.fields.entries.items) |entry| {
if (entry.value.ty.hasCodeGenBits())
return true;
} else {
return false;
}
},
// TODO lazy types
.array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
.array_u8 => self.arrayLen() != 0,
@@ -1100,6 +1115,10 @@ pub const Type = extern union {
@panic("TODO abiAlignment error union");
},
.@"struct" => {
@panic("TODO abiAlignment struct");
},
.c_void,
.void,
.type,
@@ -1144,6 +1163,10 @@ pub const Type = extern union {
.@"opaque" => unreachable,
.var_args_param => unreachable,
.@"struct" => {
@panic("TODO abiSize struct");
},
.u8,
.i8,
.bool,
@@ -1316,6 +1339,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.@"opaque",
@@ -1393,6 +1417,7 @@ pub const Type = extern union {
.empty_struct,
.empty_struct_literal,
.@"opaque",
.@"struct",
.var_args_param,
=> unreachable,
@@ -1487,6 +1512,7 @@ pub const Type = extern union {
.empty_struct_literal,
.inferred_alloc_const,
.inferred_alloc_mut,
.@"struct",
.@"opaque",
.var_args_param,
=> false,
@@ -1564,6 +1590,7 @@ pub const Type = extern union {
.empty_struct_literal,
.inferred_alloc_const,
.inferred_alloc_mut,
.@"struct",
.@"opaque",
.var_args_param,
=> false,
@@ -1650,6 +1677,7 @@ pub const Type = extern union {
.empty_struct_literal,
.inferred_alloc_const,
.inferred_alloc_mut,
.@"struct",
.@"opaque",
.var_args_param,
=> false,
@@ -1731,6 +1759,7 @@ pub const Type = extern union {
.empty_struct_literal,
.inferred_alloc_const,
.inferred_alloc_mut,
.@"struct",
.@"opaque",
.var_args_param,
=> false,
@@ -1792,7 +1821,11 @@ pub const Type = extern union {
.ErrorUnion => ty = ty.errorUnionChild(),
.Fn => @panic("TODO fn isValidVarType"),
.Struct => @panic("TODO struct isValidVarType"),
.Struct => {
// TODO this is not always correct; introduce lazy value mechanism
// and here we need to force a resolve of "type requires comptime".
return true;
},
.Union => @panic("TODO union isValidVarType"),
};
}
@@ -1850,6 +1883,7 @@ pub const Type = extern union {
.anyerror_void_error_union => unreachable,
.error_set => unreachable,
.error_set_single => unreachable,
.@"struct" => unreachable,
.empty_struct => unreachable,
.empty_struct_literal => unreachable,
.inferred_alloc_const => unreachable,
@@ -1999,6 +2033,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2070,6 +2105,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2156,6 +2192,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2238,6 +2275,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2306,6 +2344,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2402,6 +2441,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2519,6 +2559,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2602,6 +2643,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2684,6 +2726,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2766,6 +2809,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2845,6 +2889,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -2924,6 +2969,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -3003,6 +3049,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -3070,6 +3117,11 @@ pub const Type = extern union {
.var_args_param,
=> return null,
.@"struct" => {
log.warn("TODO implement Type.onePossibleValue for structs", .{});
return null;
},
.empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
.void => return Value.initTag(.void_value),
.noreturn => return Value.initTag(.unreachable_value),
@@ -3172,6 +3224,7 @@ pub const Type = extern union {
.anyerror_void_error_union,
.error_set,
.error_set_single,
.@"struct",
.empty_struct,
.empty_struct_literal,
.inferred_alloc_const,
@@ -3269,6 +3322,7 @@ pub const Type = extern union {
.empty_struct_literal,
=> unreachable,
.@"struct" => &self.castTag(.@"struct").?.data.container,
.empty_struct => self.castTag(.empty_struct).?.data,
.@"opaque" => &self.castTag(.@"opaque").?.data,
};
@@ -3421,6 +3475,7 @@ pub const Type = extern union {
error_set_single,
empty_struct,
@"opaque",
@"struct",
pub const last_no_payload_tag = Tag.inferred_alloc_const;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -3506,6 +3561,7 @@ pub const Type = extern union {
.error_union => Payload.ErrorUnion,
.error_set_single => Payload.Name,
.@"opaque" => Payload.Opaque,
.@"struct" => Payload.Struct,
.empty_struct => Payload.ContainerScope,
};
}
@@ -3638,6 +3694,11 @@ pub const Type = extern union {
base: Payload = .{ .tag = .@"opaque" },
data: Module.Scope.Container,
};
pub const Struct = struct {
base: Payload = .{ .tag = .@"struct" },
data: *Module.Struct,
};
};
};

View File

@@ -74,6 +74,7 @@ pub const Value = extern union {
bool_true,
bool_false,
abi_align_default,
empty_struct_value,
empty_array, // See last_no_payload_tag below.
// After this, the tag requires a payload.
@@ -165,6 +166,7 @@ pub const Value = extern union {
.null_value,
.bool_true,
.bool_false,
.abi_align_default,
=> @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
.int_big_positive,
@@ -320,6 +322,7 @@ pub const Value = extern union {
.bool_true,
.bool_false,
.empty_struct_value,
.abi_align_default,
=> unreachable,
.ty => {
@@ -464,8 +467,8 @@ pub const Value = extern union {
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
.enum_literal_type => return out_stream.writeAll("@Type(.EnumLiteral)"),
.abi_align_default => return out_stream.writeAll("(default ABI alignment)"),
// TODO this should print `NAME{}`
.empty_struct_value => return out_stream.writeAll("struct {}{}"),
.null_value => return out_stream.writeAll("null"),
.undef => return out_stream.writeAll("undefined"),
@@ -627,6 +630,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
};
}
@@ -699,6 +703,7 @@ pub const Value = extern union {
.@"error",
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.undef => unreachable,
@@ -786,6 +791,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.undef => unreachable,
@@ -873,6 +879,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.undef => unreachable,
@@ -988,6 +995,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.zero,
@@ -1079,6 +1087,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.zero,
@@ -1239,6 +1248,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.zero,
@@ -1317,6 +1327,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.zero,
@@ -1452,6 +1463,7 @@ pub const Value = extern union {
.const_slice_u8_type,
.enum_literal_type,
.ty,
.abi_align_default,
=> {
// Directly return Type.hash, toType can only fail for .int_type.
var allocator = std.heap.FixedBufferAllocator.init(&[_]u8{});
@@ -1632,6 +1644,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.ref_val => self.castTag(.ref_val).?.data,
@@ -1719,6 +1732,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.inferred_alloc,
.abi_align_default,
=> unreachable,
.empty_array => unreachable, // out of bounds array index
@@ -1822,6 +1836,7 @@ pub const Value = extern union {
.@"error",
.error_union,
.empty_struct_value,
.abi_align_default,
=> false,
.undef => unreachable,
@@ -1903,6 +1918,7 @@ pub const Value = extern union {
.void_value,
.enum_literal,
.empty_struct_value,
.abi_align_default,
=> null,
.error_union => {
@@ -2009,6 +2025,7 @@ pub const Value = extern union {
.error_union,
.empty_struct_value,
.null_value,
.abi_align_default,
=> false,
.undef => unreachable,

View File

@@ -274,6 +274,10 @@ pub const Inst = struct {
/// the field types, defaults, and alignments.
/// Uses the `pl_node` union field. Payload is `StructDecl`.
struct_decl,
/// Same as `struct_decl`, except has the `packed` layout.
struct_decl_packed,
/// Same as `struct_decl`, except has the `extern` layout.
struct_decl_extern,
/// A union type definition. Contains references to ZIR instructions for
/// the field types and optional type tag expression.
/// Uses the `pl_node` union field. Payload is `UnionDecl`.
@@ -707,6 +711,8 @@ pub const Inst = struct {
.coerce_result_ptr,
.@"const",
.struct_decl,
.struct_decl_packed,
.struct_decl_extern,
.union_decl,
.enum_decl,
.opaque_decl,
@@ -1655,7 +1661,10 @@ const Writer = struct {
.condbr_inline,
=> try self.writePlNodeCondBr(stream, inst),
.struct_decl => try self.writeStructDecl(stream, inst),
.struct_decl,
.struct_decl_packed,
.struct_decl_extern,
=> try self.writeStructDecl(stream, inst),
.switch_block => try self.writePlNodeSwitchBr(stream, inst, .none),
.switch_block_else => try self.writePlNodeSwitchBr(stream, inst, .@"else"),