diff --git a/src/AstGen.zig b/src/AstGen.zig index 24c06aff64..9b4e6c7c1a 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -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 + diff --git a/src/Module.zig b/src/Module.zig index ebb4b2dc1d..52a53d034a 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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 diff --git a/src/Sema.zig b/src/Sema.zig index 18146cb301..06ff3e445b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -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, diff --git a/src/codegen.zig b/src/codegen.zig index d27122efc9..35ddd000fb 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -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()) diff --git a/src/ir.zig b/src/ir.zig index c09af2507e..ab6fb29e03 100644 --- a/src/ir.zig +++ b/src/ir.zig @@ -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, diff --git a/src/type.zig b/src/type.zig index 05d4a950c9..2086567b8a 100644 --- a/src/type.zig +++ b/src/type.zig @@ -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, + }; }; }; diff --git a/src/value.zig b/src/value.zig index 269cceafa4..4170b005bf 100644 --- a/src/value.zig +++ b/src/value.zig @@ -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, diff --git a/src/zir.zig b/src/zir.zig index 4f2bb6a24d..5b1ad5ce18 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -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"),