authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-23 23:27:49-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-23 23:59:25-07:00
log6249a24e81b9b3df3d5ca99b57f22470b9ac486c
tree7f9ad767459ce5c1227365368d9034576b04e018
parent65c04759709a64d1ad0529623bab804b97c02cbc

stage2: integer-backed packed structs

This implements #10113 for the self-hosted compiler only. It removes the ability to override alignment of packed struct fields, and removes the ability to put pointers and arrays inside packed structs. After this commit, nearly all the behavior tests pass for the stage2 llvm backend that involve packed structs. I didn't implement the compile errors or compile error tests yet. I'm waiting until we have stage2 building itself and then I want to rework the compile error test harness with inspiration from Vexu's arocc test harness. At that point it should be a much nicer dev experience to work on compile errors.

13 files changed, 513 insertions(+), 643 deletions(-)

lib/std/builtin.zig+1
...@@ -356,6 +356,7 @@ pub const TypeInfo = union(enum) {...@@ -356,6 +356,7 @@ pub const TypeInfo = union(enum) {
356 alignment: comptime_int,356 alignment: comptime_int,
357 is_generic: bool,357 is_generic: bool,
358 is_var_args: bool,358 is_var_args: bool,
359 /// TODO change the language spec to make this not optional.
359 return_type: ?type,360 return_type: ?type,
360 args: []const Param,361 args: []const Param,
361362
lib/std/os/uefi/protocols/edid_override_protocol.zig+1-1
...@@ -23,7 +23,7 @@ pub const EdidOverrideProtocol = extern struct {...@@ -23,7 +23,7 @@ pub const EdidOverrideProtocol = extern struct {
23};23};
2424
25pub const EdidOverrideProtocolAttributes = packed struct {25pub const EdidOverrideProtocolAttributes = packed struct {
26 dont_override: bool align(4),26 dont_override: bool,
27 enable_hot_plug: bool,27 enable_hot_plug: bool,
28 _pad: u30 = 0,28 _pad: u30 = 0,
29};29};
src/AstGen.zig+3
...@@ -4002,6 +4002,9 @@ fn structDeclInner(...@@ -4002,6 +4002,9 @@ fn structDeclInner(
4002 wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused });4002 wip_members.nextField(bits_per_field, .{ have_align, have_value, is_comptime, unused });
40034003
4004 if (have_align) {4004 if (have_align) {
4005 if (layout == .Packed) {
4006 try astgen.appendErrorNode(member.ast.align_expr, "unable to override alignment of packed struct fields", .{});
4007 }
4005 const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr);4008 const align_inst = try expr(&block_scope, &namespace.base, align_rl, member.ast.align_expr);
4006 wip_members.appendToField(@enumToInt(align_inst));4009 wip_members.appendToField(@enumToInt(align_inst));
4007 }4010 }
src/Module.zig+25-9
...@@ -886,15 +886,6 @@ pub const Struct = struct {...@@ -886,15 +886,6 @@ pub const Struct = struct {
886 offset: u32,886 offset: u32,
887 is_comptime: bool,887 is_comptime: bool,
888888
889 /// Returns the field alignment, assuming the struct is packed.
890 pub fn packedAlignment(field: Field) u32 {
891 if (field.abi_align.tag() == .abi_align_default) {
892 return 0;
893 } else {
894 return @intCast(u32, field.abi_align.toUnsignedInt());
895 }
896 }
897
898 /// Returns the field alignment, assuming the struct is not packed.889 /// Returns the field alignment, assuming the struct is not packed.
899 pub fn normalAlignment(field: Field, target: Target) u32 {890 pub fn normalAlignment(field: Field, target: Target) u32 {
900 if (field.abi_align.tag() == .abi_align_default) {891 if (field.abi_align.tag() == .abi_align_default) {
...@@ -985,6 +976,31 @@ pub const Struct = struct {...@@ -985,6 +976,31 @@ pub const Struct = struct {
985 => true,976 => true,
986 };977 };
987 }978 }
979
980 pub fn packedFieldBitOffset(s: Struct, target: Target, index: usize) u16 {
981 assert(s.layout == .Packed);
982 assert(s.haveFieldTypes());
983 var bit_sum: u64 = 0;
984 for (s.fields.values()) |field, i| {
985 if (i == index) {
986 return @intCast(u16, bit_sum);
987 }
988 bit_sum += field.ty.bitSize(target);
989 }
990 return @intCast(u16, bit_sum);
991 }
992
993 pub fn packedIntegerBits(s: Struct, target: Target) u16 {
994 return s.packedFieldBitOffset(target, s.fields.count());
995 }
996
997 pub fn packedIntegerType(s: Struct, target: Target, buf: *Type.Payload.Bits) Type {
998 buf.* = .{
999 .base = .{ .tag = .int_unsigned },
1000 .data = s.packedIntegerBits(target),
1001 };
1002 return Type.initPayload(&buf.base);
1003 }
988};1004};
9891005
990/// Represents the data that an enum declaration provides, when the fields1006/// Represents the data that an enum declaration provides, when the fields
src/Sema.zig+103-94
...@@ -9701,7 +9701,8 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -9701,7 +9701,8 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
9701fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9701fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9702 const inst_data = sema.code.instructions.items(.data)[inst].un_node;9702 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
9703 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };9703 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9704 const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);9704 const unresolved_operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
9705 const operand_ty = try sema.resolveTypeFields(block, operand_src, unresolved_operand_ty);
9705 const target = sema.mod.getTarget();9706 const target = sema.mod.getTarget();
9706 const bit_size = operand_ty.bitSize(target);9707 const bit_size = operand_ty.bitSize(target);
9707 return sema.addIntUnsigned(Type.initTag(.comptime_int), bit_size);9708 return sema.addIntUnsigned(Type.initTag(.comptime_int), bit_size);
...@@ -9891,6 +9892,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9891,6 +9892,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9891 .Fn => {9892 .Fn => {
9892 // TODO: look into memoizing this result.9893 // TODO: look into memoizing this result.
9893 const info = ty.fnInfo();9894 const info = ty.fnInfo();
9895
9894 var params_anon_decl = try block.startAnonDecl(src);9896 var params_anon_decl = try block.startAnonDecl(src);
9895 defer params_anon_decl.deinit();9897 defer params_anon_decl.deinit();
98969898
...@@ -9948,19 +9950,24 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9948,19 +9950,24 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9948 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);9950 break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
9949 };9951 };
99509952
9951 const field_values = try sema.arena.alloc(Value, 6);9953 const field_values = try sema.arena.create([6]Value);
9952 // calling_convention: CallingConvention,9954 field_values.* = .{
9953 field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc));9955 // calling_convention: CallingConvention,
9954 // alignment: comptime_int,9956 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)),
9955 field_values[1] = try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target));9957 // alignment: comptime_int,
9956 // is_generic: bool,9958 try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)),
9957 field_values[2] = Value.makeBool(info.is_generic);9959 // is_generic: bool,
9958 // is_var_args: bool,9960 Value.makeBool(info.is_generic),
9959 field_values[3] = Value.makeBool(info.is_var_args);9961 // is_var_args: bool,
9960 // return_type: ?type,9962 Value.makeBool(info.is_var_args),
9961 field_values[4] = try Value.Tag.ty.create(sema.arena, info.return_type);9963 // return_type: ?type,
9962 // args: []const Fn.Param,9964 try Value.Tag.opt_payload.create(
9963 field_values[5] = args_val;9965 sema.arena,
9966 try Value.Tag.ty.create(sema.arena, info.return_type),
9967 ),
9968 // args: []const Fn.Param,
9969 args_val,
9970 };
99649971
9965 return sema.addConstant(9972 return sema.addConstant(
9966 type_info_ty,9973 type_info_ty,
...@@ -10007,25 +10014,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -10007,25 +10014,27 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
10007 const alignment = if (info.@"align" != 0)10014 const alignment = if (info.@"align" != 0)
10008 info.@"align"10015 info.@"align"
10009 else10016 else
10010 info.pointee_type.abiAlignment(target);10017 try sema.typeAbiAlignment(block, src, info.pointee_type);
1001110018
10012 const field_values = try sema.arena.alloc(Value, 8);10019 const field_values = try sema.arena.create([8]Value);
10013 // size: Size,10020 field_values.* = .{
10014 field_values[0] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size));10021 // size: Size,
10015 // is_const: bool,10022 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size)),
10016 field_values[1] = Value.makeBool(!info.mutable);10023 // is_const: bool,
10017 // is_volatile: bool,10024 Value.makeBool(!info.mutable),
10018 field_values[2] = Value.makeBool(info.@"volatile");10025 // is_volatile: bool,
10019 // alignment: comptime_int,10026 Value.makeBool(info.@"volatile"),
10020 field_values[3] = try Value.Tag.int_u64.create(sema.arena, alignment);10027 // alignment: comptime_int,
10021 // address_space: AddressSpace10028 try Value.Tag.int_u64.create(sema.arena, alignment),
10022 field_values[4] = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace"));10029 // address_space: AddressSpace
10023 // child: type,10030 try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace")),
10024 field_values[5] = try Value.Tag.ty.create(sema.arena, info.pointee_type);10031 // child: type,
10025 // is_allowzero: bool,10032 try Value.Tag.ty.create(sema.arena, info.pointee_type),
10026 field_values[6] = Value.makeBool(info.@"allowzero");10033 // is_allowzero: bool,
10027 // sentinel: ?*const anyopaque,10034 Value.makeBool(info.@"allowzero"),
10028 field_values[7] = try sema.optRefValue(block, src, info.pointee_type, info.sentinel);10035 // sentinel: ?*const anyopaque,
10036 try sema.optRefValue(block, src, info.pointee_type, info.sentinel),
10037 };
1002910038
10030 return sema.addConstant(10039 return sema.addConstant(
10031 type_info_ty,10040 type_info_ty,
...@@ -10377,7 +10386,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -10377,7 +10386,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
10377 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);10386 const default_val_ptr = try sema.optRefValue(block, src, field.ty, opt_default_val);
10378 const alignment = switch (layout) {10387 const alignment = switch (layout) {
10379 .Auto, .Extern => field.normalAlignment(target),10388 .Auto, .Extern => field.normalAlignment(target),
10380 .Packed => field.packedAlignment(),10389 .Packed => 0,
10381 };10390 };
1038210391
10383 struct_field_fields.* = .{10392 struct_field_fields.* = .{
...@@ -12120,6 +12129,7 @@ fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -12120,6 +12129,7 @@ fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
1212012129
12121fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {12130fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
12122 const offset = try bitOffsetOf(sema, block, inst);12131 const offset = try bitOffsetOf(sema, block, inst);
12132 // TODO reminder to make this a compile error for packed structs
12123 return sema.addIntUnsigned(Type.comptime_int, offset / 8);12133 return sema.addIntUnsigned(Type.comptime_int, offset / 8);
12124}12134}
1212512135
...@@ -12143,7 +12153,8 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6...@@ -12143,7 +12153,8 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
12143 );12153 );
12144 }12154 }
1214512155
12146 const index = ty.structFields().getIndex(field_name) orelse {12156 const fields = ty.structFields();
12157 const index = fields.getIndex(field_name) orelse {
12147 return sema.fail(12158 return sema.fail(
12148 block,12159 block,
12149 rhs_src,12160 rhs_src,
...@@ -12153,24 +12164,25 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6...@@ -12153,24 +12164,25 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
12153 };12164 };
1215412165
12155 const target = sema.mod.getTarget();12166 const target = sema.mod.getTarget();
12156 const layout = ty.containerLayout();12167 switch (ty.containerLayout()) {
12157 if (layout == .Packed) {12168 .Packed => {
12158 var it = ty.iteratePackedStructOffsets(target);12169 var bit_sum: u64 = 0;
12159 while (it.next()) |field_offset| {12170 for (fields.values()) |field, i| {
12160 if (field_offset.field == index) {12171 if (i == index) {
12161 return (field_offset.offset * 8) + field_offset.running_bits;12172 return bit_sum;
12162 }12173 }
12163 }12174 bit_sum += field.ty.bitSize(target);
12164 } else {12175 } else unreachable;
12165 var it = ty.iterateStructOffsets(target);12176 },
12166 while (it.next()) |field_offset| {12177 else => {
12167 if (field_offset.field == index) {12178 var it = ty.iterateStructOffsets(target);
12168 return field_offset.offset * 8;12179 while (it.next()) |field_offset| {
12169 }12180 if (field_offset.field == index) {
12170 }12181 return field_offset.offset * 8;
12182 }
12183 } else unreachable;
12184 },
12171 }12185 }
12172
12173 unreachable;
12174}12186}
1217512187
12176/// Returns `true` if the type was a comptime_int.12188/// Returns `true` if the type was a comptime_int.
...@@ -14199,61 +14211,44 @@ fn structFieldPtrByIndex(...@@ -14199,61 +14211,44 @@ fn structFieldPtrByIndex(
14199 field_src: LazySrcLoc,14211 field_src: LazySrcLoc,
14200) CompileError!Air.Inst.Ref {14212) CompileError!Air.Inst.Ref {
14201 const field = struct_obj.fields.values()[field_index];14213 const field = struct_obj.fields.values()[field_index];
14202
14203 const struct_ptr_ty = sema.typeOf(struct_ptr);14214 const struct_ptr_ty = sema.typeOf(struct_ptr);
14215 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;
14216
14204 var ptr_ty_data: Type.Payload.Pointer.Data = .{14217 var ptr_ty_data: Type.Payload.Pointer.Data = .{
14205 .pointee_type = field.ty,14218 .pointee_type = field.ty,
14206 .mutable = struct_ptr_ty.ptrIsMutable(),14219 .mutable = struct_ptr_ty_info.mutable,
14207 .@"addrspace" = struct_ptr_ty.ptrAddressSpace(),14220 .@"addrspace" = struct_ptr_ty_info.@"addrspace",
14208 };14221 };
14222
14209 // TODO handle when the struct pointer is overaligned, we should return a potentially14223 // TODO handle when the struct pointer is overaligned, we should return a potentially
14210 // over-aligned field pointer too.14224 // over-aligned field pointer too.
14211 if (struct_obj.layout == .Packed) p: {14225 if (struct_obj.layout == .Packed) {
14212 const target = sema.mod.getTarget();14226 const target = sema.mod.getTarget();
14213 comptime assert(Type.packed_struct_layout_version == 1);14227 comptime assert(Type.packed_struct_layout_version == 2);
1421414228
14215 var offset: u64 = 0;
14216 var running_bits: u16 = 0;14229 var running_bits: u16 = 0;
14217 for (struct_obj.fields.values()) |f, i| {14230 for (struct_obj.fields.values()) |f, i| {
14218 if (!(try sema.typeHasRuntimeBits(block, field_src, f.ty))) continue;14231 if (!(try sema.typeHasRuntimeBits(block, field_src, f.ty))) continue;
1421914232
14220 const field_align = f.packedAlignment();14233 if (i == field_index) {
14221 if (field_align == 0) {14234 ptr_ty_data.bit_offset = running_bits;
14222 if (i == field_index) {
14223 ptr_ty_data.bit_offset = running_bits;
14224 }
14225 running_bits += @intCast(u16, f.ty.bitSize(target));
14226 } else {
14227 if (running_bits != 0) {
14228 var int_payload: Type.Payload.Bits = .{
14229 .base = .{ .tag = .int_unsigned },
14230 .data = running_bits,
14231 };
14232 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
14233 if (i > field_index) {
14234 ptr_ty_data.host_size = @intCast(u16, int_ty.abiSize(target));
14235 break :p;
14236 }
14237 const int_align = int_ty.abiAlignment(target);
14238 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
14239 offset += int_ty.abiSize(target);
14240 running_bits = 0;
14241 }
14242 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
14243 if (i == field_index) {
14244 break :p;
14245 }
14246 offset += f.ty.abiSize(target);
14247 }14235 }
14236 running_bits += @intCast(u16, f.ty.bitSize(target));
14237 }
14238 ptr_ty_data.host_size = (running_bits + 7) / 8;
14239
14240 // If this is a packed struct embedded in another one, we need to offset
14241 // the bits against each other.
14242 if (struct_ptr_ty_info.host_size != 0) {
14243 ptr_ty_data.host_size = struct_ptr_ty_info.host_size;
14244 ptr_ty_data.bit_offset += struct_ptr_ty_info.bit_offset;
14245 }
14246 } else {
14247 if (field.abi_align.tag() != .abi_align_default) {
14248 ptr_ty_data.@"align" = @intCast(u32, field.abi_align.toUnsignedInt());
14248 }14249 }
14249 assert(running_bits != 0);
14250 var int_payload: Type.Payload.Bits = .{
14251 .base = .{ .tag = .int_unsigned },
14252 .data = running_bits,
14253 };
14254 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
14255 ptr_ty_data.host_size = @intCast(u16, int_ty.abiSize(target));
14256 }14250 }
14251
14257 const ptr_field_ty = try Type.ptr(sema.arena, ptr_ty_data);14252 const ptr_field_ty = try Type.ptr(sema.arena, ptr_ty_data);
1425814253
14259 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {14254 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
...@@ -15849,13 +15844,18 @@ fn beginComptimePtrLoad(...@@ -15849,13 +15844,18 @@ fn beginComptimePtrLoad(
15849fn bitCast(15844fn bitCast(
15850 sema: *Sema,15845 sema: *Sema,
15851 block: *Block,15846 block: *Block,
15852 dest_ty: Type,15847 dest_ty_unresolved: Type,
15853 inst: Air.Inst.Ref,15848 inst: Air.Inst.Ref,
15854 inst_src: LazySrcLoc,15849 inst_src: LazySrcLoc,
15855) CompileError!Air.Inst.Ref {15850) CompileError!Air.Inst.Ref {
15851 const dest_ty = try sema.resolveTypeFields(block, inst_src, dest_ty_unresolved);
15852 try sema.resolveTypeLayout(block, inst_src, dest_ty);
15853
15854 const old_ty = try sema.resolveTypeFields(block, inst_src, sema.typeOf(inst));
15855 try sema.resolveTypeLayout(block, inst_src, old_ty);
15856
15856 // TODO validate the type size and other compile errors15857 // TODO validate the type size and other compile errors
15857 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {15858 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |val| {
15858 const old_ty = sema.typeOf(inst);
15859 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty);15859 const result_val = try sema.bitCastVal(block, inst_src, val, old_ty, dest_ty);
15860 return sema.addConstant(dest_ty, result_val);15860 return sema.addConstant(dest_ty, result_val);
15861 }15861 }
...@@ -17506,6 +17506,9 @@ fn semaStructFields(...@@ -17506,6 +17506,9 @@ fn semaStructFields(
17506 // But only resolve the source location if we need to emit a compile error.17506 // But only resolve the source location if we need to emit a compile error.
17507 try sema.resolveType(&block_scope, src, field_type_ref);17507 try sema.resolveType(&block_scope, src, field_type_ref);
1750817508
17509 // TODO emit compile errors for invalid field types
17510 // such as arrays and pointers inside packed structs.
17511
17509 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);17512 const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
17510 assert(!gop.found_existing);17513 assert(!gop.found_existing);
17511 gop.value_ptr.* = .{17514 gop.value_ptr.* = .{
...@@ -18690,6 +18693,12 @@ pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)...@@ -18690,6 +18693,12 @@ pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type)
18690 return true;18693 return true;
18691}18694}
1869218695
18696fn typeAbiAlignment(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u32 {
18697 try sema.resolveTypeLayout(block, src, ty);
18698 const target = sema.mod.getTarget();
18699 return ty.abiAlignment(target);
18700}
18701
18693/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.18702/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
18694pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {18703pub fn fnHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
18695 const fn_info = ty.fnInfo();18704 const fn_info = ty.fnInfo();
src/codegen/llvm.zig+120-282
...@@ -865,8 +865,12 @@ pub const DeclGen = struct {...@@ -865,8 +865,12 @@ pub const DeclGen = struct {
865 };865 };
866 return dg.context.structType(&fields, fields.len, .False);866 return dg.context.structType(&fields, fields.len, .False);
867 }867 }
868 const llvm_addrspace = dg.llvmAddressSpace(t.ptrAddressSpace());868 const ptr_info = t.ptrInfo().data;
869 const elem_ty = t.childType();869 const llvm_addrspace = dg.llvmAddressSpace(ptr_info.@"addrspace");
870 if (ptr_info.host_size != 0) {
871 return dg.context.intType(ptr_info.host_size * 8).pointerType(llvm_addrspace);
872 }
873 const elem_ty = ptr_info.pointee_type;
870 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {874 const lower_elem_ty = switch (elem_ty.zigTypeTag()) {
871 .Opaque, .Fn => true,875 .Opaque, .Fn => true,
872 .Array => elem_ty.childType().hasRuntimeBits(),876 .Array => elem_ty.childType().hasRuntimeBits(),
...@@ -977,6 +981,14 @@ pub const DeclGen = struct {...@@ -977,6 +981,14 @@ pub const DeclGen = struct {
977981
978 const struct_obj = t.castTag(.@"struct").?.data;982 const struct_obj = t.castTag(.@"struct").?.data;
979983
984 if (struct_obj.layout == .Packed) {
985 var buf: Type.Payload.Bits = undefined;
986 const int_ty = struct_obj.packedIntegerType(target, &buf);
987 const int_llvm_ty = try dg.llvmType(int_ty);
988 gop.value_ptr.* = int_llvm_ty;
989 return int_llvm_ty;
990 }
991
980 const name = try struct_obj.getFullyQualifiedName(gpa);992 const name = try struct_obj.getFullyQualifiedName(gpa);
981 defer gpa.free(name);993 defer gpa.free(name);
982994
...@@ -988,83 +1000,9 @@ pub const DeclGen = struct {...@@ -988,83 +1000,9 @@ pub const DeclGen = struct {
988 var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, struct_obj.fields.count());1000 var llvm_field_types = try std.ArrayListUnmanaged(*const llvm.Type).initCapacity(gpa, struct_obj.fields.count());
989 defer llvm_field_types.deinit(gpa);1001 defer llvm_field_types.deinit(gpa);
9901002
991 if (struct_obj.layout == .Packed) {1003 for (struct_obj.fields.values()) |field| {
992 try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count() * 2);1004 if (!field.ty.hasRuntimeBits()) continue;
993 comptime assert(Type.packed_struct_layout_version == 1);1005 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
994 var offset: u64 = 0;
995 var big_align: u32 = 0;
996 var running_bits: u16 = 0;
997 for (struct_obj.fields.values()) |field| {
998 if (!field.ty.hasRuntimeBits()) continue;
999
1000 const field_align = field.packedAlignment();
1001 if (field_align == 0) {
1002 running_bits += @intCast(u16, field.ty.bitSize(target));
1003 } else {
1004 if (running_bits != 0) {
1005 var int_payload: Type.Payload.Bits = .{
1006 .base = .{ .tag = .int_unsigned },
1007 .data = running_bits,
1008 };
1009 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1010 const int_align = int_ty.abiAlignment(target);
1011 big_align = @maximum(big_align, int_align);
1012 const llvm_int_ty = try dg.llvmType(int_ty);
1013 const prev_offset = offset;
1014 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
1015 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1016 if (padding_bytes != 0) {
1017 const padding = dg.context.intType(8).arrayType(padding_bytes);
1018 llvm_field_types.appendAssumeCapacity(padding);
1019 }
1020 llvm_field_types.appendAssumeCapacity(llvm_int_ty);
1021 offset += int_ty.abiSize(target);
1022 running_bits = 0;
1023 }
1024 big_align = @maximum(big_align, field_align);
1025 const prev_offset = offset;
1026 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
1027 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1028 if (padding_bytes != 0) {
1029 const padding = dg.context.intType(8).arrayType(padding_bytes);
1030 llvm_field_types.appendAssumeCapacity(padding);
1031 }
1032 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
1033 offset += field.ty.abiSize(target);
1034 }
1035 }
1036
1037 if (running_bits != 0) {
1038 var int_payload: Type.Payload.Bits = .{
1039 .base = .{ .tag = .int_unsigned },
1040 .data = running_bits,
1041 };
1042 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1043 const int_align = int_ty.abiAlignment(target);
1044 big_align = @maximum(big_align, int_align);
1045 const prev_offset = offset;
1046 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
1047 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1048 if (padding_bytes != 0) {
1049 const padding = dg.context.intType(8).arrayType(padding_bytes);
1050 llvm_field_types.appendAssumeCapacity(padding);
1051 }
1052 const llvm_int_ty = try dg.llvmType(int_ty);
1053 llvm_field_types.appendAssumeCapacity(llvm_int_ty);
1054 }
1055
1056 const prev_offset = offset;
1057 offset = std.mem.alignForwardGeneric(u64, offset, big_align);
1058 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1059 if (padding_bytes != 0) {
1060 const padding = dg.context.intType(8).arrayType(padding_bytes);
1061 llvm_field_types.appendAssumeCapacity(padding);
1062 }
1063 } else {
1064 for (struct_obj.fields.values()) |field| {
1065 if (!field.ty.hasRuntimeBits()) continue;
1066 llvm_field_types.appendAssumeCapacity(try dg.llvmType(field.ty));
1067 }
1068 }1006 }
10691007
1070 llvm_struct_ty.structSetBody(1008 llvm_struct_ty.structSetBody(
...@@ -1521,116 +1459,54 @@ pub const DeclGen = struct {...@@ -1521,116 +1459,54 @@ pub const DeclGen = struct {
1521 const llvm_struct_ty = try dg.llvmType(tv.ty);1459 const llvm_struct_ty = try dg.llvmType(tv.ty);
1522 const field_vals = tv.val.castTag(.@"struct").?.data;1460 const field_vals = tv.val.castTag(.@"struct").?.data;
1523 const gpa = dg.gpa;1461 const gpa = dg.gpa;
1524 const llvm_field_count = llvm_struct_ty.countStructElementTypes();
1525
1526 var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count);
1527 defer llvm_fields.deinit(gpa);
1528
1529 var need_unnamed = false;
1530 const struct_obj = tv.ty.castTag(.@"struct").?.data;1462 const struct_obj = tv.ty.castTag(.@"struct").?.data;
1463
1531 if (struct_obj.layout == .Packed) {1464 if (struct_obj.layout == .Packed) {
1532 const target = dg.module.getTarget();1465 const target = dg.module.getTarget();
1466 var int_ty_buf: Type.Payload.Bits = undefined;
1467 const int_ty = struct_obj.packedIntegerType(target, &int_ty_buf);
1468 const int_llvm_ty = try dg.llvmType(int_ty);
1533 const fields = struct_obj.fields.values();1469 const fields = struct_obj.fields.values();
1534 comptime assert(Type.packed_struct_layout_version == 1);1470 comptime assert(Type.packed_struct_layout_version == 2);
1535 var offset: u64 = 0;1471 var running_int: *const llvm.Value = int_llvm_ty.constNull();
1536 var big_align: u32 = 0;
1537 var running_bits: u16 = 0;1472 var running_bits: u16 = 0;
1538 var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
1539 for (field_vals) |field_val, i| {1473 for (field_vals) |field_val, i| {
1540 const field = fields[i];1474 const field = fields[i];
1541 if (!field.ty.hasRuntimeBits()) continue;1475 if (!field.ty.hasRuntimeBits()) continue;
15421476
1543 const field_align = field.packedAlignment();1477 const non_int_val = try dg.genTypedValue(.{
1544 if (field_align == 0) {1478 .ty = field.ty,
1545 const non_int_val = try dg.genTypedValue(.{1479 .val = field_val,
1546 .ty = field.ty,1480 });
1547 .val = field_val,1481 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));
1548 });1482 const small_int_ty = dg.context.intType(ty_bit_size);
1549 const ty_bit_size = @intCast(u16, field.ty.bitSize(target));1483 const small_int_val = non_int_val.constBitCast(small_int_ty);
1550 const small_int_ty = dg.context.intType(ty_bit_size);1484 const shift_rhs = int_llvm_ty.constInt(running_bits, .False);
1551 const small_int_val = non_int_val.constBitCast(small_int_ty);1485 const extended_int_val = small_int_val.constZExt(int_llvm_ty);
1552 const big_int_ty = running_int.typeOf();1486 const shifted = extended_int_val.constShl(shift_rhs);
1553 const shift_rhs = big_int_ty.constInt(running_bits, .False);1487 running_int = running_int.constOr(shifted);
1554 const extended_int_val = small_int_val.constZExt(big_int_ty);1488 running_bits += ty_bit_size;
1555 const shifted = extended_int_val.constShl(shift_rhs);
1556 running_int = running_int.constOr(shifted);
1557 running_bits += ty_bit_size;
1558 } else {
1559 big_align = @maximum(big_align, field_align);
1560 if (running_bits != 0) {
1561 var int_payload: Type.Payload.Bits = .{
1562 .base = .{ .tag = .int_unsigned },
1563 .data = running_bits,
1564 };
1565 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1566 const int_align = int_ty.abiAlignment(target);
1567 big_align = @maximum(big_align, int_align);
1568 const prev_offset = offset;
1569 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
1570 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1571 if (padding_bytes != 0) {
1572 const padding = dg.context.intType(8).arrayType(padding_bytes);
1573 llvm_fields.appendAssumeCapacity(padding.getUndef());
1574 }
1575 llvm_fields.appendAssumeCapacity(running_int);
1576 running_int = llvm_struct_ty.structGetTypeAtIndex(@intCast(c_uint, llvm_fields.items.len)).constNull();
1577 offset += int_ty.abiSize(target);
1578 running_bits = 0;
1579 }
1580 const prev_offset = offset;
1581 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
1582 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1583 if (padding_bytes != 0) {
1584 const padding = dg.context.intType(8).arrayType(padding_bytes);
1585 llvm_fields.appendAssumeCapacity(padding.getUndef());
1586 }
1587 llvm_fields.appendAssumeCapacity(try dg.genTypedValue(.{
1588 .ty = field.ty,
1589 .val = field_val,
1590 }));
1591 offset += field.ty.abiSize(target);
1592 }
1593 }
1594 if (running_bits != 0) {
1595 var int_payload: Type.Payload.Bits = .{
1596 .base = .{ .tag = .int_unsigned },
1597 .data = running_bits,
1598 };
1599 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1600 const int_align = int_ty.abiAlignment(target);
1601 big_align = @maximum(big_align, int_align);
1602 const prev_offset = offset;
1603 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
1604 const padding_bytes = @intCast(c_uint, offset - prev_offset);
1605 if (padding_bytes != 0) {
1606 const padding = dg.context.intType(8).arrayType(padding_bytes);
1607 llvm_fields.appendAssumeCapacity(padding.getUndef());
1608 }
1609 llvm_fields.appendAssumeCapacity(running_int);
1610 offset += int_ty.abiSize(target);
1611 }1489 }
1490 return running_int;
1491 }
16121492
1613 const prev_offset = offset;1493 const llvm_field_count = llvm_struct_ty.countStructElementTypes();
1614 offset = std.mem.alignForwardGeneric(u64, offset, big_align);1494 var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count);
1615 const padding_bytes = @intCast(c_uint, offset - prev_offset);1495 defer llvm_fields.deinit(gpa);
1616 if (padding_bytes != 0) {
1617 const padding = dg.context.intType(8).arrayType(padding_bytes);
1618 llvm_fields.appendAssumeCapacity(padding.getUndef());
1619 }
1620 } else {
1621 for (field_vals) |field_val, i| {
1622 const field_ty = tv.ty.structFieldType(i);
1623 if (!field_ty.hasRuntimeBits()) continue;
16241496
1625 const field_llvm_val = try dg.genTypedValue(.{1497 var need_unnamed = false;
1626 .ty = field_ty,1498 for (field_vals) |field_val, i| {
1627 .val = field_val,1499 const field_ty = tv.ty.structFieldType(i);
1628 });1500 if (!field_ty.hasRuntimeBits()) continue;
16291501
1630 need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val);1502 const field_llvm_val = try dg.genTypedValue(.{
1503 .ty = field_ty,
1504 .val = field_val,
1505 });
16311506
1632 llvm_fields.appendAssumeCapacity(field_llvm_val);1507 need_unnamed = need_unnamed or dg.isUnnamedType(field_ty, field_llvm_val);
1633 }1508
1509 llvm_fields.appendAssumeCapacity(field_llvm_val);
1634 }1510 }
16351511
1636 if (need_unnamed) {1512 if (need_unnamed) {
...@@ -2923,10 +2799,27 @@ pub const FuncGen = struct {...@@ -2923,10 +2799,27 @@ pub const FuncGen = struct {
2923 if (!isByRef(struct_ty)) {2799 if (!isByRef(struct_ty)) {
2924 assert(!isByRef(field_ty));2800 assert(!isByRef(field_ty));
2925 switch (struct_ty.zigTypeTag()) {2801 switch (struct_ty.zigTypeTag()) {
2926 .Struct => {2802 .Struct => switch (struct_ty.containerLayout()) {
2927 var ptr_ty_buf: Type.Payload.Pointer = undefined;2803 .Packed => {
2928 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;2804 const struct_obj = struct_ty.castTag(.@"struct").?.data;
2929 return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");2805 const bit_offset = struct_obj.packedFieldBitOffset(target, field_index);
2806 const containing_int = struct_llvm_val;
2807 const shift_amt = containing_int.typeOf().constInt(bit_offset, .False);
2808 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
2809 const elem_llvm_ty = try self.dg.llvmType(field_ty);
2810 if (field_ty.zigTypeTag() == .Float) {
2811 const elem_bits = @intCast(c_uint, field_ty.bitSize(target));
2812 const same_size_int = self.context.intType(elem_bits);
2813 const truncated_int = self.builder.buildTrunc(shifted_value, same_size_int, "");
2814 return self.builder.buildBitCast(truncated_int, elem_llvm_ty, "");
2815 }
2816 return self.builder.buildTrunc(shifted_value, elem_llvm_ty, "");
2817 },
2818 else => {
2819 var ptr_ty_buf: Type.Payload.Pointer = undefined;
2820 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
2821 return self.builder.buildExtractValue(struct_llvm_val, llvm_field_index, "");
2822 },
2930 },2823 },
2931 .Union => {2824 .Union => {
2932 return self.todo("airStructFieldVal byval union", .{});2825 return self.todo("airStructFieldVal byval union", .{});
...@@ -2937,6 +2830,7 @@ pub const FuncGen = struct {...@@ -2937,6 +2830,7 @@ pub const FuncGen = struct {
29372830
2938 switch (struct_ty.zigTypeTag()) {2831 switch (struct_ty.zigTypeTag()) {
2939 .Struct => {2832 .Struct => {
2833 assert(struct_ty.containerLayout() != .Packed);
2940 var ptr_ty_buf: Type.Payload.Pointer = undefined;2834 var ptr_ty_buf: Type.Payload.Pointer = undefined;
2941 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;2835 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
2942 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");2836 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
...@@ -4928,21 +4822,35 @@ pub const FuncGen = struct {...@@ -4928,21 +4822,35 @@ pub const FuncGen = struct {
4928 ) !?*const llvm.Value {4822 ) !?*const llvm.Value {
4929 const struct_ty = struct_ptr_ty.childType();4823 const struct_ty = struct_ptr_ty.childType();
4930 switch (struct_ty.zigTypeTag()) {4824 switch (struct_ty.zigTypeTag()) {
4931 .Struct => {4825 .Struct => switch (struct_ty.containerLayout()) {
4932 const target = self.dg.module.getTarget();4826 .Packed => {
4933 var ty_buf: Type.Payload.Pointer = undefined;4827 // From LLVM's perspective, a pointer to a packed struct and a pointer
4934 if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {4828 // to a field of a packed struct are the same. The difference is in the
4935 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");4829 // Zig pointer type which provides information for how to mask and shift
4936 } else {4830 // out the relevant bits when accessing the pointee.
4937 // If we found no index then this means this is a zero sized field at the4831 // Here we perform a bitcast because we want to use the host_size
4938 // end of the struct. Treat our struct pointer as an array of two and get4832 // as the llvm pointer element type.
4939 // the index to the element at index `1` to get a pointer to the end of4833 const result_llvm_ty = try self.dg.llvmType(self.air.typeOfIndex(inst));
4940 // the struct.4834 // TODO this can be removed if we change host_size to be bits instead
4941 const llvm_usize = try self.dg.llvmType(Type.usize);4835 // of bytes.
4942 const llvm_index = llvm_usize.constInt(1, .False);4836 return self.builder.buildBitCast(struct_ptr, result_llvm_ty, "");
4943 const indices: [1]*const llvm.Value = .{llvm_index};4837 },
4944 return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");4838 else => {
4945 }4839 const target = self.dg.module.getTarget();
4840 var ty_buf: Type.Payload.Pointer = undefined;
4841 if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {
4842 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
4843 } else {
4844 // If we found no index then this means this is a zero sized field at the
4845 // end of the struct. Treat our struct pointer as an array of two and get
4846 // the index to the element at index `1` to get a pointer to the end of
4847 // the struct.
4848 const llvm_usize = try self.dg.llvmType(Type.usize);
4849 const llvm_index = llvm_usize.constInt(1, .False);
4850 const indices: [1]*const llvm.Value = .{llvm_index};
4851 return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
4852 }
4853 },
4946 },4854 },
4947 .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),4855 .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
4948 else => unreachable,4856 else => unreachable,
...@@ -5373,102 +5281,29 @@ fn llvmFieldIndex(...@@ -5373,102 +5281,29 @@ fn llvmFieldIndex(
5373 return null;5281 return null;
5374 }5282 }
5375 const struct_obj = ty.castTag(.@"struct").?.data;5283 const struct_obj = ty.castTag(.@"struct").?.data;
5376 if (struct_obj.layout != .Packed) {5284 assert(struct_obj.layout != .Packed);
5377 var llvm_field_index: c_uint = 0;
5378 for (struct_obj.fields.values()) |field, i| {
5379 if (!field.ty.hasRuntimeBits())
5380 continue;
5381 if (field_index > i) {
5382 llvm_field_index += 1;
5383 continue;
5384 }
53855285
5386 ptr_pl_buf.* = .{
5387 .data = .{
5388 .pointee_type = field.ty,
5389 .@"align" = field.normalAlignment(target),
5390 .@"addrspace" = .generic,
5391 },
5392 };
5393 return llvm_field_index;
5394 } else {
5395 // We did not find an llvm field that corresponds to this zig field.
5396 return null;
5397 }
5398 }
5399
5400 // Our job here is to return the host integer field index.
5401 comptime assert(Type.packed_struct_layout_version == 1);
5402 var offset: u64 = 0;
5403 var running_bits: u16 = 0;
5404 var llvm_field_index: c_uint = 0;5286 var llvm_field_index: c_uint = 0;
5405 for (struct_obj.fields.values()) |field, i| {5287 for (struct_obj.fields.values()) |field, i| {
5406 if (!field.ty.hasRuntimeBits())5288 if (!field.ty.hasRuntimeBits())
5407 continue;5289 continue;
54085290 if (field_index > i) {
5409 const field_align = field.packedAlignment();
5410 if (field_align == 0) {
5411 if (i == field_index) {
5412 ptr_pl_buf.* = .{
5413 .data = .{
5414 .pointee_type = field.ty,
5415 .bit_offset = running_bits,
5416 .@"addrspace" = .generic,
5417 },
5418 };
5419 }
5420 running_bits += @intCast(u16, field.ty.bitSize(target));
5421 } else {
5422 if (running_bits != 0) {
5423 var int_payload: Type.Payload.Bits = .{
5424 .base = .{ .tag = .int_unsigned },
5425 .data = running_bits,
5426 };
5427 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
5428 if (i > field_index) {
5429 ptr_pl_buf.data.host_size = @intCast(u16, int_ty.abiSize(target));
5430 return llvm_field_index;
5431 }
5432
5433 const int_align = int_ty.abiAlignment(target);
5434 const prev_offset = offset;
5435 offset = std.mem.alignForwardGeneric(u64, offset, int_align);
5436 const padding_bytes = @intCast(c_uint, offset - prev_offset);
5437 if (padding_bytes != 0) {
5438 llvm_field_index += 1;
5439 }
5440 llvm_field_index += 1;
5441 offset += int_ty.abiSize(target);
5442 running_bits = 0;
5443 }
5444 const prev_offset = offset;
5445 offset = std.mem.alignForwardGeneric(u64, offset, field_align);
5446 const padding_bytes = @intCast(c_uint, offset - prev_offset);
5447 if (padding_bytes != 0) {
5448 llvm_field_index += 1;
5449 }
5450 if (i == field_index) {
5451 ptr_pl_buf.* = .{
5452 .data = .{
5453 .pointee_type = field.ty,
5454 .@"align" = field_align,
5455 .@"addrspace" = .generic,
5456 },
5457 };
5458 return llvm_field_index;
5459 }
5460 llvm_field_index += 1;5291 llvm_field_index += 1;
5461 offset += field.ty.abiSize(target);5292 continue;
5462 }5293 }
5294
5295 ptr_pl_buf.* = .{
5296 .data = .{
5297 .pointee_type = field.ty,
5298 .@"align" = field.normalAlignment(target),
5299 .@"addrspace" = .generic,
5300 },
5301 };
5302 return llvm_field_index;
5303 } else {
5304 // We did not find an llvm field that corresponds to this zig field.
5305 return null;
5463 }5306 }
5464 assert(running_bits != 0);
5465 var int_payload: Type.Payload.Bits = .{
5466 .base = .{ .tag = .int_unsigned },
5467 .data = running_bits,
5468 };
5469 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
5470 ptr_pl_buf.data.host_size = @intCast(u16, int_ty.abiSize(target));
5471 return llvm_field_index;
5472}5307}
54735308
5474fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {5309fn firstParamSRet(fn_info: Type.Payload.Function.Data, target: std.Target) bool {
...@@ -5518,6 +5353,9 @@ fn isByRef(ty: Type) bool {...@@ -5518,6 +5353,9 @@ fn isByRef(ty: Type) bool {
55185353
5519 .Array, .Frame => return ty.hasRuntimeBits(),5354 .Array, .Frame => return ty.hasRuntimeBits(),
5520 .Struct => {5355 .Struct => {
5356 // Packed structs are represented to LLVM as integers.
5357 if (ty.containerLayout() == .Packed) return false;
5358
5521 if (!ty.hasRuntimeBits()) return false;5359 if (!ty.hasRuntimeBits()) return false;
5522 if (ty.castTag(.tuple)) |tuple| {5360 if (ty.castTag(.tuple)) |tuple| {
5523 var count: usize = 0;5361 var count: usize = 0;
src/type.zig+40-153
...@@ -1952,57 +1952,22 @@ pub const Type = extern union {...@@ -1952,57 +1952,22 @@ pub const Type = extern union {
19521952
1953 .@"struct" => {1953 .@"struct" => {
1954 const fields = self.structFields();1954 const fields = self.structFields();
1955 const is_packed = if (self.castTag(.@"struct")) |payload| p: {1955 if (self.castTag(.@"struct")) |payload| {
1956 const struct_obj = payload.data;1956 const struct_obj = payload.data;
1957 assert(struct_obj.haveLayout());1957 assert(struct_obj.haveLayout());
1958 break :p struct_obj.layout == .Packed;1958 if (struct_obj.layout == .Packed) {
1959 } else false;1959 var buf: Type.Payload.Bits = undefined;
19601960 const int_ty = struct_obj.packedIntegerType(target, &buf);
1961 if (!is_packed) {1961 return int_ty.abiAlignment(target);
1962 var big_align: u32 = 0;
1963 for (fields.values()) |field| {
1964 if (!field.ty.hasRuntimeBits()) continue;
1965
1966 const field_align = field.normalAlignment(target);
1967 big_align = @maximum(big_align, field_align);
1968 }1962 }
1969 return big_align;
1970 }1963 }
19711964
1972 // For packed structs, we take the maximum alignment of the backing integers.
1973 comptime assert(Type.packed_struct_layout_version == 1);
1974 var big_align: u32 = 0;1965 var big_align: u32 = 0;
1975 var running_bits: u16 = 0;
1976
1977 for (fields.values()) |field| {1966 for (fields.values()) |field| {
1978 if (!field.ty.hasRuntimeBits()) continue;1967 if (!field.ty.hasRuntimeBits()) continue;
19791968
1980 const field_align = field.packedAlignment();1969 const field_align = field.normalAlignment(target);
1981 if (field_align == 0) {1970 big_align = @maximum(big_align, field_align);
1982 running_bits += @intCast(u16, field.ty.bitSize(target));
1983 } else {
1984 if (running_bits != 0) {
1985 var int_payload: Payload.Bits = .{
1986 .base = .{ .tag = .int_unsigned },
1987 .data = running_bits,
1988 };
1989 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
1990 const int_align = int_ty.abiAlignment(target);
1991 big_align = @maximum(big_align, int_align);
1992 running_bits = 0;
1993 }
1994 big_align = @maximum(big_align, field_align);
1995 }
1996 }
1997
1998 if (running_bits != 0) {
1999 var int_payload: Payload.Bits = .{
2000 .base = .{ .tag = .int_unsigned },
2001 .data = running_bits,
2002 };
2003 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
2004 const int_align = int_ty.abiAlignment(target);
2005 big_align = @maximum(big_align, int_align);
2006 }1971 }
2007 return big_align;1972 return big_align;
2008 },1973 },
...@@ -2090,12 +2055,20 @@ pub const Type = extern union {...@@ -2090,12 +2055,20 @@ pub const Type = extern union {
2090 .void,2055 .void,
2091 => 0,2056 => 0,
20922057
2093 .@"struct", .tuple => {2058 .@"struct", .tuple => switch (self.containerLayout()) {
2094 const field_count = self.structFieldCount();2059 .Packed => {
2095 if (field_count == 0) {2060 const struct_obj = self.castTag(.@"struct").?.data;
2096 return 0;2061 var buf: Type.Payload.Bits = undefined;
2097 }2062 const int_ty = struct_obj.packedIntegerType(target, &buf);
2098 return self.structFieldOffset(field_count, target);2063 return int_ty.abiSize(target);
2064 },
2065 else => {
2066 const field_count = self.structFieldCount();
2067 if (field_count == 0) {
2068 return 0;
2069 }
2070 return self.structFieldOffset(field_count, target);
2071 },
2099 },2072 },
21002073
2101 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {2074 .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => {
...@@ -2264,7 +2237,6 @@ pub const Type = extern union {...@@ -2264,7 +2237,6 @@ pub const Type = extern union {
2264 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer2237 .fn_ccc_void_no_args => unreachable, // represents machine code; not a pointer
2265 .function => unreachable, // represents machine code; not a pointer2238 .function => unreachable, // represents machine code; not a pointer
2266 .anyopaque => unreachable,2239 .anyopaque => unreachable,
2267 .void => unreachable,
2268 .type => unreachable,2240 .type => unreachable,
2269 .comptime_int => unreachable,2241 .comptime_int => unreachable,
2270 .comptime_float => unreachable,2242 .comptime_float => unreachable,
...@@ -2282,18 +2254,25 @@ pub const Type = extern union {...@@ -2282,18 +2254,25 @@ pub const Type = extern union {
2282 .generic_poison => unreachable,2254 .generic_poison => unreachable,
2283 .bound_fn => unreachable,2255 .bound_fn => unreachable,
22842256
2257 .void => 0,
2258
2285 .@"struct" => {2259 .@"struct" => {
2286 const field_count = ty.structFieldCount();2260 const field_count = ty.structFieldCount();
2287 if (field_count == 0) return 0;2261 if (field_count == 0) return 0;
22882262
2289 const struct_obj = ty.castTag(.@"struct").?.data;2263 const struct_obj = ty.castTag(.@"struct").?.data;
2290 assert(struct_obj.haveLayout());2264 assert(struct_obj.haveFieldTypes());
22912265
2292 var total: u64 = 0;2266 switch (struct_obj.layout) {
2293 for (struct_obj.fields.values()) |field| {2267 .Auto, .Extern => {
2294 total += field.ty.bitSize(target);2268 var total: u64 = 0;
2269 for (struct_obj.fields.values()) |field| {
2270 total += field.ty.bitSize(target);
2271 }
2272 return total;
2273 },
2274 .Packed => return struct_obj.packedIntegerBits(target),
2295 }2275 }
2296 return total;
2297 },2276 },
22982277
2299 .tuple => {2278 .tuple => {
...@@ -4039,78 +4018,6 @@ pub const Type = extern union {...@@ -4039,78 +4018,6 @@ pub const Type = extern union {
4039 }4018 }
4040 }4019 }
40414020
4042 pub const PackedFieldOffset = struct {
4043 field: usize,
4044 offset: u64,
4045 running_bits: u16,
4046 };
4047
4048 pub const PackedStructOffsetIterator = struct {
4049 field: usize = 0,
4050 offset: u64 = 0,
4051 big_align: u32 = 0,
4052 running_bits: u16 = 0,
4053 struct_obj: *Module.Struct,
4054 target: Target,
4055
4056 pub fn next(it: *PackedStructOffsetIterator) ?PackedFieldOffset {
4057 comptime assert(Type.packed_struct_layout_version == 1);
4058 if (it.struct_obj.fields.count() <= it.field)
4059 return null;
4060
4061 const field = it.struct_obj.fields.values()[it.field];
4062 defer it.field += 1;
4063 if (!field.ty.hasRuntimeBits()) {
4064 return PackedFieldOffset{
4065 .field = it.field,
4066 .offset = it.offset,
4067 .running_bits = it.running_bits,
4068 };
4069 }
4070
4071 const field_align = field.packedAlignment();
4072 if (field_align == 0) {
4073 defer it.running_bits += @intCast(u16, field.ty.bitSize(it.target));
4074 return PackedFieldOffset{
4075 .field = it.field,
4076 .offset = it.offset,
4077 .running_bits = it.running_bits,
4078 };
4079 } else {
4080 it.big_align = @maximum(it.big_align, field_align);
4081
4082 if (it.running_bits != 0) {
4083 var int_payload: Payload.Bits = .{
4084 .base = .{ .tag = .int_unsigned },
4085 .data = it.running_bits,
4086 };
4087 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
4088 const int_align = int_ty.abiAlignment(it.target);
4089 it.big_align = @maximum(it.big_align, int_align);
4090 it.offset = std.mem.alignForwardGeneric(u64, it.offset, int_align);
4091 it.offset += int_ty.abiSize(it.target);
4092 it.running_bits = 0;
4093 }
4094 it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
4095 defer it.offset += field.ty.abiSize(it.target);
4096 return PackedFieldOffset{
4097 .field = it.field,
4098 .offset = it.offset,
4099 .running_bits = it.running_bits,
4100 };
4101 }
4102 }
4103 };
4104
4105 /// Get an iterator that iterates over all the struct field, returning the field and
4106 /// offset of that field. Asserts that the type is a none packed struct.
4107 pub fn iteratePackedStructOffsets(ty: Type, target: Target) PackedStructOffsetIterator {
4108 const struct_obj = ty.castTag(.@"struct").?.data;
4109 assert(struct_obj.haveLayout());
4110 assert(struct_obj.layout == .Packed);
4111 return .{ .struct_obj = struct_obj, .target = target };
4112 }
4113
4114 pub const FieldOffset = struct {4021 pub const FieldOffset = struct {
4115 field: usize,4022 field: usize,
4116 offset: u64,4023 offset: u64,
...@@ -4150,42 +4057,19 @@ pub const Type = extern union {...@@ -4150,42 +4057,19 @@ pub const Type = extern union {
4150 }4057 }
41514058
4152 /// Supports structs and unions.4059 /// Supports structs and unions.
4153 /// For packed structs, it returns the byte offset of the containing integer.
4154 pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 {4060 pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 {
4155 switch (ty.tag()) {4061 switch (ty.tag()) {
4156 .@"struct" => {4062 .@"struct" => {
4157 const struct_obj = ty.castTag(.@"struct").?.data;4063 const struct_obj = ty.castTag(.@"struct").?.data;
4158 assert(struct_obj.haveLayout());4064 assert(struct_obj.haveLayout());
4159 const is_packed = struct_obj.layout == .Packed;4065 assert(struct_obj.layout != .Packed);
4160 if (!is_packed) {4066 var it = ty.iterateStructOffsets(target);
4161 var it = ty.iterateStructOffsets(target);
4162 while (it.next()) |field_offset| {
4163 if (index == field_offset.field)
4164 return field_offset.offset;
4165 }
4166
4167 return std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
4168 }
4169
4170 var it = ty.iteratePackedStructOffsets(target);
4171 while (it.next()) |field_offset| {4067 while (it.next()) |field_offset| {
4172 if (index == field_offset.field)4068 if (index == field_offset.field)
4173 return field_offset.offset;4069 return field_offset.offset;
4174 }4070 }
41754071
4176 if (it.running_bits != 0) {4072 return std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
4177 var int_payload: Payload.Bits = .{
4178 .base = .{ .tag = .int_unsigned },
4179 .data = it.running_bits,
4180 };
4181 const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
4182 const int_align = int_ty.abiAlignment(target);
4183 it.big_align = @maximum(it.big_align, int_align);
4184 it.offset = std.mem.alignForwardGeneric(u64, it.offset, int_align);
4185 it.offset += int_ty.abiSize(target);
4186 }
4187 it.offset = std.mem.alignForwardGeneric(u64, it.offset, it.big_align);
4188 return it.offset;
4189 },4073 },
41904074
4191 .tuple => {4075 .tuple => {
...@@ -4734,6 +4618,9 @@ pub const Type = extern union {...@@ -4734,6 +4618,9 @@ pub const Type = extern union {
4734 /// an appropriate value for this field.4618 /// an appropriate value for this field.
4735 @"addrspace": std.builtin.AddressSpace,4619 @"addrspace": std.builtin.AddressSpace,
4736 bit_offset: u16 = 0,4620 bit_offset: u16 = 0,
4621 /// If this is non-zero it means the pointer points to a sub-byte
4622 /// range of data, which is backed by a "host integer" with this
4623 /// number of bytes.
4737 host_size: u16 = 0,4624 host_size: u16 = 0,
4738 @"allowzero": bool = false,4625 @"allowzero": bool = false,
4739 mutable: bool = true, // TODO rename this to const, not mutable4626 mutable: bool = true, // TODO rename this to const, not mutable
...@@ -4953,7 +4840,7 @@ pub const Type = extern union {...@@ -4953,7 +4840,7 @@ pub const Type = extern union {
49534840
4954 /// This is only used for comptime asserts. Bump this number when you make a change4841 /// This is only used for comptime asserts. Bump this number when you make a change
4955 /// to packed struct layout to find out all the places in the codebase you need to edit!4842 /// to packed struct layout to find out all the places in the codebase you need to edit!
4956 pub const packed_struct_layout_version = 1;4843 pub const packed_struct_layout_version = 2;
4957};4844};
49584845
4959pub const CType = enum {4846pub const CType = enum {
src/value.zig+141-7
...@@ -1078,18 +1078,72 @@ pub const Value = extern union {...@@ -1078,18 +1078,72 @@ pub const Value = extern union {
1078 buf_off += elem_size;1078 buf_off += elem_size;
1079 }1079 }
1080 },1080 },
1081 .Struct => {1081 .Struct => switch (ty.containerLayout()) {
1082 const fields = ty.structFields().values();1082 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
1083 const field_vals = val.castTag(.@"struct").?.data;1083 .Extern => {
1084 for (fields) |field, i| {1084 const fields = ty.structFields().values();
1085 const off = @intCast(usize, ty.structFieldOffset(i, target));1085 const field_vals = val.castTag(.@"struct").?.data;
1086 writeToMemory(field_vals[i], field.ty, target, buffer[off..]);1086 for (fields) |field, i| {
1087 }1087 const off = @intCast(usize, ty.structFieldOffset(i, target));
1088 writeToMemory(field_vals[i], field.ty, target, buffer[off..]);
1089 }
1090 },
1091 .Packed => {
1092 // TODO allocate enough heap space instead of using this buffer
1093 // on the stack.
1094 var buf: [16]std.math.big.Limb = undefined;
1095 const host_int = packedStructToInt(val, ty, target, &buf);
1096 const abi_size = @intCast(usize, ty.abiSize(target));
1097 const bit_size = @intCast(usize, ty.bitSize(target));
1098 host_int.writeTwosComplement(buffer, bit_size, abi_size, target.cpu.arch.endian());
1099 },
1088 },1100 },
1089 else => @panic("TODO implement writeToMemory for more types"),1101 else => @panic("TODO implement writeToMemory for more types"),
1090 }1102 }
1091 }1103 }
10921104
1105 fn packedStructToInt(val: Value, ty: Type, target: Target, buf: []std.math.big.Limb) BigIntConst {
1106 var bigint = BigIntMutable.init(buf, 0);
1107 const fields = ty.structFields().values();
1108 const field_vals = val.castTag(.@"struct").?.data;
1109 var bits: u16 = 0;
1110 // TODO allocate enough heap space instead of using this buffer
1111 // on the stack.
1112 var field_buf: [16]std.math.big.Limb = undefined;
1113 var field_space: BigIntSpace = undefined;
1114 var field_buf2: [16]std.math.big.Limb = undefined;
1115 for (fields) |field, i| {
1116 const field_val = field_vals[i];
1117 const field_bigint_const = switch (field.ty.zigTypeTag()) {
1118 .Float => switch (field.ty.floatBits(target)) {
1119 16 => bitcastFloatToBigInt(f16, val.toFloat(f16), &field_buf),
1120 32 => bitcastFloatToBigInt(f32, val.toFloat(f32), &field_buf),
1121 64 => bitcastFloatToBigInt(f64, val.toFloat(f64), &field_buf),
1122 80 => bitcastFloatToBigInt(f80, val.toFloat(f80), &field_buf),
1123 128 => bitcastFloatToBigInt(f128, val.toFloat(f128), &field_buf),
1124 else => unreachable,
1125 },
1126 .Int, .Bool => field_val.toBigInt(&field_space),
1127 .Struct => packedStructToInt(field_val, field.ty, target, &field_buf),
1128 else => unreachable,
1129 };
1130 var field_bigint = BigIntMutable.init(&field_buf2, 0);
1131 field_bigint.shiftLeft(field_bigint_const, bits);
1132 bits += @intCast(u16, field.ty.bitSize(target));
1133 bigint.bitOr(bigint.toConst(), field_bigint.toConst());
1134 }
1135 return bigint.toConst();
1136 }
1137
1138 fn bitcastFloatToBigInt(comptime F: type, f: F, buf: []std.math.big.Limb) BigIntConst {
1139 const Int = @Type(.{ .Int = .{
1140 .signedness = .unsigned,
1141 .bits = @typeInfo(F).Float.bits,
1142 } });
1143 const int = @bitCast(Int, f);
1144 return BigIntMutable.init(buf, int).toConst();
1145 }
1146
1093 pub fn readFromMemory(1147 pub fn readFromMemory(
1094 ty: Type,1148 ty: Type,
1095 target: Target,1149 target: Target,
...@@ -1127,10 +1181,90 @@ pub const Value = extern union {...@@ -1127,10 +1181,90 @@ pub const Value = extern union {
1127 }1181 }
1128 return Tag.array.create(arena, elems);1182 return Tag.array.create(arena, elems);
1129 },1183 },
1184 .Struct => switch (ty.containerLayout()) {
1185 .Auto => unreachable, // Sema is supposed to have emitted a compile error already
1186 .Extern => {
1187 const fields = ty.structFields().values();
1188 const field_vals = try arena.alloc(Value, fields.len);
1189 for (fields) |field, i| {
1190 const off = @intCast(usize, ty.structFieldOffset(i, target));
1191 field_vals[i] = try readFromMemory(field.ty, target, buffer[off..], arena);
1192 }
1193 return Tag.@"struct".create(arena, field_vals);
1194 },
1195 .Packed => {
1196 const endian = target.cpu.arch.endian();
1197 const Limb = std.math.big.Limb;
1198 const abi_size = @intCast(usize, ty.abiSize(target));
1199 const bit_size = @intCast(usize, ty.bitSize(target));
1200 const limb_count = (buffer.len + @sizeOf(Limb) - 1) / @sizeOf(Limb);
1201 const limbs_buffer = try arena.alloc(Limb, limb_count);
1202 var bigint = BigIntMutable.init(limbs_buffer, 0);
1203 bigint.readTwosComplement(buffer, bit_size, abi_size, endian, .unsigned);
1204 return intToPackedStruct(ty, target, bigint.toConst(), arena);
1205 },
1206 },
1130 else => @panic("TODO implement readFromMemory for more types"),1207 else => @panic("TODO implement readFromMemory for more types"),
1131 }1208 }
1132 }1209 }
11331210
1211 fn intToPackedStruct(
1212 ty: Type,
1213 target: Target,
1214 bigint: BigIntConst,
1215 arena: Allocator,
1216 ) Allocator.Error!Value {
1217 const limbs_buffer = try arena.alloc(std.math.big.Limb, bigint.limbs.len);
1218 var bigint_mut = bigint.toMutable(limbs_buffer);
1219 const fields = ty.structFields().values();
1220 const field_vals = try arena.alloc(Value, fields.len);
1221 var bits: u16 = 0;
1222 for (fields) |field, i| {
1223 const field_bits = @intCast(u16, field.ty.bitSize(target));
1224 bigint_mut.shiftRight(bigint, bits);
1225 bigint_mut.truncate(bigint_mut.toConst(), .unsigned, field_bits);
1226 bits += field_bits;
1227 const field_bigint = bigint_mut.toConst();
1228
1229 field_vals[i] = switch (field.ty.zigTypeTag()) {
1230 .Float => switch (field.ty.floatBits(target)) {
1231 16 => try bitCastBigIntToFloat(f16, .float_16, field_bigint, arena),
1232 32 => try bitCastBigIntToFloat(f32, .float_32, field_bigint, arena),
1233 64 => try bitCastBigIntToFloat(f64, .float_64, field_bigint, arena),
1234 80 => try bitCastBigIntToFloat(f80, .float_80, field_bigint, arena),
1235 128 => try bitCastBigIntToFloat(f128, .float_128, field_bigint, arena),
1236 else => unreachable,
1237 },
1238 .Bool => makeBool(!field_bigint.eqZero()),
1239 .Int => try Tag.int_big_positive.create(
1240 arena,
1241 try arena.dupe(std.math.big.Limb, field_bigint.limbs),
1242 ),
1243 .Struct => try intToPackedStruct(field.ty, target, field_bigint, arena),
1244 else => unreachable,
1245 };
1246 }
1247 return Tag.@"struct".create(arena, field_vals);
1248 }
1249
1250 fn bitCastBigIntToFloat(
1251 comptime F: type,
1252 comptime float_tag: Tag,
1253 bigint: BigIntConst,
1254 arena: Allocator,
1255 ) !Value {
1256 const Int = @Type(.{ .Int = .{
1257 .signedness = .unsigned,
1258 .bits = @typeInfo(F).Float.bits,
1259 } });
1260 const int = bigint.to(Int) catch |err| switch (err) {
1261 error.NegativeIntoUnsigned => unreachable,
1262 error.TargetTooSmall => unreachable,
1263 };
1264 const f = @bitCast(F, int);
1265 return float_tag.create(arena, f);
1266 }
1267
1134 fn floatWriteToMemory(comptime F: type, f: F, target: Target, buffer: []u8) void {1268 fn floatWriteToMemory(comptime F: type, f: F, target: Target, buffer: []u8) void {
1135 if (F == f80) {1269 if (F == f80) {
1136 switch (target.cpu.arch) {1270 switch (target.cpu.arch) {
test/behavior/array.zig+5-5
...@@ -473,8 +473,8 @@ test "type deduction for array subscript expression" {...@@ -473,8 +473,8 @@ test "type deduction for array subscript expression" {
473}473}
474474
475test "sentinel element count towards the ABI size calculation" {475test "sentinel element count towards the ABI size calculation" {
476 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
477 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO476 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
477 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
478 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO478 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
479 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO479 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
480 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO480 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -482,7 +482,7 @@ test "sentinel element count towards the ABI size calculation" {...@@ -482,7 +482,7 @@ test "sentinel element count towards the ABI size calculation" {
482482
483 const S = struct {483 const S = struct {
484 fn doTheTest() !void {484 fn doTheTest() !void {
485 const T = packed struct {485 const T = extern struct {
486 fill_pre: u8 = 0x55,486 fill_pre: u8 = 0x55,
487 data: [0:0]u8 = undefined,487 data: [0:0]u8 = undefined,
488 fill_post: u8 = 0xAA,488 fill_post: u8 = 0xAA,
...@@ -500,7 +500,7 @@ test "sentinel element count towards the ABI size calculation" {...@@ -500,7 +500,7 @@ test "sentinel element count towards the ABI size calculation" {
500}500}
501501
502test "zero-sized array with recursive type definition" {502test "zero-sized array with recursive type definition" {
503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;503 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
504 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO504 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
505 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO505 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
506 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO506 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
...@@ -525,7 +525,7 @@ test "zero-sized array with recursive type definition" {...@@ -525,7 +525,7 @@ test "zero-sized array with recursive type definition" {
525}525}
526526
527test "type coercion of anon struct literal to array" {527test "type coercion of anon struct literal to array" {
528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;528 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
529 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO529 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
530 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO530 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
531 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO531 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
...@@ -561,8 +561,8 @@ test "type coercion of anon struct literal to array" {...@@ -561,8 +561,8 @@ test "type coercion of anon struct literal to array" {
561}561}
562562
563test "type coercion of pointer to anon struct literal to pointer to array" {563test "type coercion of pointer to anon struct literal to pointer to array" {
564 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
565 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO564 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
565 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO566 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
567 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO567 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
568 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO568 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/bitcast.zig-5
...@@ -132,7 +132,6 @@ test "bitcast generates a temporary value" {...@@ -132,7 +132,6 @@ test "bitcast generates a temporary value" {
132}132}
133133
134test "@bitCast packed structs at runtime and comptime" {134test "@bitCast packed structs at runtime and comptime" {
135 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
136 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;135 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;136 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
138 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;137 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -170,7 +169,6 @@ test "@bitCast packed structs at runtime and comptime" {...@@ -170,7 +169,6 @@ test "@bitCast packed structs at runtime and comptime" {
170}169}
171170
172test "@bitCast extern structs at runtime and comptime" {171test "@bitCast extern structs at runtime and comptime" {
173 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
174 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;172 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
175 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;173 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
176 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;174 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -205,7 +203,6 @@ test "@bitCast extern structs at runtime and comptime" {...@@ -205,7 +203,6 @@ test "@bitCast extern structs at runtime and comptime" {
205}203}
206204
207test "bitcast packed struct to integer and back" {205test "bitcast packed struct to integer and back" {
208 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
209 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;206 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
210 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;207 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
211 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;208 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -246,7 +243,6 @@ test "implicit cast to error union by returning" {...@@ -246,7 +243,6 @@ test "implicit cast to error union by returning" {
246}243}
247244
248test "bitcast packed struct literal to byte" {245test "bitcast packed struct literal to byte" {
249 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
250 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;246 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
251 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;247 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
252 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;248 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
...@@ -261,7 +257,6 @@ test "bitcast packed struct literal to byte" {...@@ -261,7 +257,6 @@ test "bitcast packed struct literal to byte" {
261}257}
262258
263test "comptime bitcast used in expression has the correct type" {259test "comptime bitcast used in expression has the correct type" {
264 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
265 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;260 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
266 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;261 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
267 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;262 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
test/behavior/sizeof_and_typeof.zig+2-2
...@@ -210,13 +210,13 @@ test "branching logic inside @TypeOf" {...@@ -210,13 +210,13 @@ test "branching logic inside @TypeOf" {
210}210}
211211
212test "@bitSizeOf" {212test "@bitSizeOf" {
213 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO213 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
214214
215 try expect(@bitSizeOf(u2) == 2);215 try expect(@bitSizeOf(u2) == 2);
216 try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8);216 try expect(@bitSizeOf(u8) == @sizeOf(u8) * 8);
217 try expect(@bitSizeOf(struct {217 try expect(@bitSizeOf(struct {
218 a: u2,218 a: u2,
219 }) == 8);219 }) == 2);
220 try expect(@bitSizeOf(packed struct {220 try expect(@bitSizeOf(packed struct {
221 a: u2,221 a: u2,
222 }) == 2);222 }) == 2);
test/behavior/struct.zig+65-79
...@@ -268,25 +268,6 @@ test "struct field init with catch" {...@@ -268,25 +268,6 @@ test "struct field init with catch" {
268 comptime try S.doTheTest();268 comptime try S.doTheTest();
269}269}
270270
271test "packed struct field alignment" {
272 if (builtin.object_format == .c) return error.SkipZigTest;
273
274 const Stage1 = struct {
275 var baz: packed struct {
276 a: u32,
277 b: u32,
278 } = undefined;
279 };
280 const Stage2 = struct {
281 var baz: packed struct {
282 a: u32,
283 b: u32 align(1),
284 } = undefined;
285 };
286 const S = if (builtin.zig_backend != .stage1) Stage2 else Stage1;
287 try expect(@TypeOf(&S.baz.b) == *align(1) u32);
288}
289
290const blah: packed struct {271const blah: packed struct {
291 a: u3,272 a: u3,
292 b: u3,273 b: u3,
...@@ -687,48 +668,52 @@ test "default struct initialization fields" {...@@ -687,48 +668,52 @@ test "default struct initialization fields" {
687 try expect(1239 == x.a + x.b);668 try expect(1239 == x.a + x.b);
688}669}
689670
690// TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512
691test "packed array 24bits" {671test "packed array 24bits" {
692 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO672 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
673 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
674 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
675 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
676 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
677 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
693678
694 comptime {679 comptime {
695 try expect(@sizeOf([9]Foo32Bits) == 9 * 4);680 try expect(@sizeOf([9]Foo32Bits) == 9 * 4);
696 try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2);681 try expect(@sizeOf(FooArray24Bits) == @sizeOf(u96));
697 }682 }
698683
699 var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1);684 var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1);
700 bytes[bytes.len - 1] = 0xaa;685 bytes[bytes.len - 1] = 0xbb;
701 const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];686 const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
702 try expect(ptr.a == 0);687 try expect(ptr.a == 0);
703 try expect(ptr.b[0].field == 0);688 try expect(ptr.b0.field == 0);
704 try expect(ptr.b[1].field == 0);689 try expect(ptr.b1.field == 0);
705 try expect(ptr.c == 0);690 try expect(ptr.c == 0);
706691
707 ptr.a = maxInt(u16);692 ptr.a = maxInt(u16);
708 try expect(ptr.a == maxInt(u16));693 try expect(ptr.a == maxInt(u16));
709 try expect(ptr.b[0].field == 0);694 try expect(ptr.b0.field == 0);
710 try expect(ptr.b[1].field == 0);695 try expect(ptr.b1.field == 0);
711 try expect(ptr.c == 0);696 try expect(ptr.c == 0);
712697
713 ptr.b[0].field = maxInt(u24);698 ptr.b0.field = maxInt(u24);
714 try expect(ptr.a == maxInt(u16));699 try expect(ptr.a == maxInt(u16));
715 try expect(ptr.b[0].field == maxInt(u24));700 try expect(ptr.b0.field == maxInt(u24));
716 try expect(ptr.b[1].field == 0);701 try expect(ptr.b1.field == 0);
717 try expect(ptr.c == 0);702 try expect(ptr.c == 0);
718703
719 ptr.b[1].field = maxInt(u24);704 ptr.b1.field = maxInt(u24);
720 try expect(ptr.a == maxInt(u16));705 try expect(ptr.a == maxInt(u16));
721 try expect(ptr.b[0].field == maxInt(u24));706 try expect(ptr.b0.field == maxInt(u24));
722 try expect(ptr.b[1].field == maxInt(u24));707 try expect(ptr.b1.field == maxInt(u24));
723 try expect(ptr.c == 0);708 try expect(ptr.c == 0);
724709
725 ptr.c = maxInt(u16);710 ptr.c = maxInt(u16);
726 try expect(ptr.a == maxInt(u16));711 try expect(ptr.a == maxInt(u16));
727 try expect(ptr.b[0].field == maxInt(u24));712 try expect(ptr.b0.field == maxInt(u24));
728 try expect(ptr.b[1].field == maxInt(u24));713 try expect(ptr.b1.field == maxInt(u24));
729 try expect(ptr.c == maxInt(u16));714 try expect(ptr.c == maxInt(u16));
730715
731 try expect(bytes[bytes.len - 1] == 0xaa);716 try expect(bytes[bytes.len - 1] == 0xbb);
732}717}
733718
734const Foo32Bits = packed struct {719const Foo32Bits = packed struct {
...@@ -738,12 +723,16 @@ const Foo32Bits = packed struct {...@@ -738,12 +723,16 @@ const Foo32Bits = packed struct {
738723
739const FooArray24Bits = packed struct {724const FooArray24Bits = packed struct {
740 a: u16,725 a: u16,
741 b: [2]Foo32Bits,726 b0: Foo32Bits,
727 b1: Foo32Bits,
742 c: u16,728 c: u16,
743};729};
744730
745test "aligned array of packed struct" {731test "aligned array of packed struct" {
746 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO732 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
733 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
735 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
747736
748 comptime {737 comptime {
749 try expect(@sizeOf(FooStructAligned) == 2);738 try expect(@sizeOf(FooStructAligned) == 2);
...@@ -769,7 +758,10 @@ const FooArrayOfAligned = packed struct {...@@ -769,7 +758,10 @@ const FooArrayOfAligned = packed struct {
769};758};
770759
771test "pointer to packed struct member in a stack variable" {760test "pointer to packed struct member in a stack variable" {
772 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO761 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
762 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
763 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
764 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
773765
774 const S = packed struct {766 const S = packed struct {
775 a: u2,767 a: u2,
...@@ -783,32 +775,12 @@ test "pointer to packed struct member in a stack variable" {...@@ -783,32 +775,12 @@ test "pointer to packed struct member in a stack variable" {
783 try expect(s.b == 2);775 try expect(s.b == 2);
784}776}
785777
786test "non-byte-aligned array inside packed struct" {
787 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
788
789 const Foo = packed struct {
790 a: bool,
791 b: [0x16]u8,
792 };
793 const S = struct {
794 fn bar(slice: []const u8) !void {
795 try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu");
796 }
797 fn doTheTest() !void {
798 var foo = Foo{
799 .a = true,
800 .b = "abcdefghijklmnopqurstu".*,
801 };
802 const value = foo.b;
803 try bar(&value);
804 }
805 };
806 try S.doTheTest();
807 comptime try S.doTheTest();
808}
809
810test "packed struct with u0 field access" {778test "packed struct with u0 field access" {
811 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO779 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
780 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
781 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
782 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
783 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
812784
813 const S = packed struct {785 const S = packed struct {
814 f0: u0,786 f0: u0,
...@@ -818,7 +790,11 @@ test "packed struct with u0 field access" {...@@ -818,7 +790,11 @@ test "packed struct with u0 field access" {
818}790}
819791
820test "access to global struct fields" {792test "access to global struct fields" {
821 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO793 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
794 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
795 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
796 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
797 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
822798
823 g_foo.bar.value = 42;799 g_foo.bar.value = 42;
824 try expect(g_foo.bar.value == 42);800 try expect(g_foo.bar.value == 42);
...@@ -839,26 +815,32 @@ const S0 = struct {...@@ -839,26 +815,32 @@ const S0 = struct {
839var g_foo: S0 = S0.init();815var g_foo: S0 = S0.init();
840816
841test "packed struct with fp fields" {817test "packed struct with fp fields" {
842 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO818 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
819 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
820 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
821 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
822 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
843823
844 const S = packed struct {824 const S = packed struct {
845 data: [3]f32,825 data0: f32,
826 data1: f32,
827 data2: f32,
846828
847 pub fn frob(self: *@This()) void {829 pub fn frob(self: *@This()) void {
848 self.data[0] += self.data[1] + self.data[2];830 self.data0 += self.data1 + self.data2;
849 self.data[1] += self.data[0] + self.data[2];831 self.data1 += self.data0 + self.data2;
850 self.data[2] += self.data[0] + self.data[1];832 self.data2 += self.data0 + self.data1;
851 }833 }
852 };834 };
853835
854 var s: S = undefined;836 var s: S = undefined;
855 s.data[0] = 1.0;837 s.data0 = 1.0;
856 s.data[1] = 2.0;838 s.data1 = 2.0;
857 s.data[2] = 3.0;839 s.data2 = 3.0;
858 s.frob();840 s.frob();
859 try expectEqual(@as(f32, 6.0), s.data[0]);841 try expect(@as(f32, 6.0) == s.data0);
860 try expectEqual(@as(f32, 11.0), s.data[1]);842 try expect(@as(f32, 11.0) == s.data1);
861 try expectEqual(@as(f32, 20.0), s.data[2]);843 try expect(@as(f32, 20.0) == s.data2);
862}844}
863845
864test "fn with C calling convention returns struct by value" {846test "fn with C calling convention returns struct by value" {
...@@ -906,7 +888,11 @@ test "non-packed struct with u128 entry in union" {...@@ -906,7 +888,11 @@ test "non-packed struct with u128 entry in union" {
906}888}
907889
908test "packed struct field passed to generic function" {890test "packed struct field passed to generic function" {
909 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO891 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
892 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
893 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
894 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
895 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
910896
911 const S = struct {897 const S = struct {
912 const P = packed struct {898 const P = packed struct {
...@@ -1046,8 +1032,8 @@ test "struct with union field" {...@@ -1046,8 +1032,8 @@ test "struct with union field" {
1046 var True = Value{1032 var True = Value{
1047 .kind = .{ .Bool = true },1033 .kind = .{ .Bool = true },
1048 };1034 };
1049 try expectEqual(@as(u32, 2), True.ref);1035 try expect(@as(u32, 2) == True.ref);
1050 try expectEqual(true, True.kind.Bool);1036 try expect(True.kind.Bool);
1051}1037}
10521038
1053test "type coercion of anon struct literal to struct" {1039test "type coercion of anon struct literal to struct" {
test/behavior/type_info.zig+7-6
...@@ -274,7 +274,7 @@ const TestStruct = struct {...@@ -274,7 +274,7 @@ const TestStruct = struct {
274};274};
275275
276test "type info: packed struct info" {276test "type info: packed struct info" {
277 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO277 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
278278
279 try testPackedStruct();279 try testPackedStruct();
280 comptime try testPackedStruct();280 comptime try testPackedStruct();
...@@ -286,19 +286,19 @@ fn testPackedStruct() !void {...@@ -286,19 +286,19 @@ fn testPackedStruct() !void {
286 try expect(struct_info.Struct.is_tuple == false);286 try expect(struct_info.Struct.is_tuple == false);
287 try expect(struct_info.Struct.layout == .Packed);287 try expect(struct_info.Struct.layout == .Packed);
288 try expect(struct_info.Struct.fields.len == 4);288 try expect(struct_info.Struct.fields.len == 4);
289 try expect(struct_info.Struct.fields[0].alignment == 2 * @alignOf(usize));289 try expect(struct_info.Struct.fields[0].alignment == 0);
290 try expect(struct_info.Struct.fields[2].field_type == *TestPackedStruct);290 try expect(struct_info.Struct.fields[2].field_type == f32);
291 try expect(struct_info.Struct.fields[2].default_value == null);291 try expect(struct_info.Struct.fields[2].default_value == null);
292 try expect(@ptrCast(*const u32, struct_info.Struct.fields[3].default_value.?).* == 4);292 try expect(@ptrCast(*const u32, struct_info.Struct.fields[3].default_value.?).* == 4);
293 try expect(struct_info.Struct.fields[3].alignment == 1);293 try expect(struct_info.Struct.fields[3].alignment == 0);
294 try expect(struct_info.Struct.decls.len == 2);294 try expect(struct_info.Struct.decls.len == 2);
295 try expect(struct_info.Struct.decls[0].is_pub);295 try expect(struct_info.Struct.decls[0].is_pub);
296}296}
297297
298const TestPackedStruct = packed struct {298const TestPackedStruct = packed struct {
299 fieldA: usize align(2 * @alignOf(usize)),299 fieldA: usize,
300 fieldB: void,300 fieldB: void,
301 fieldC: *Self,301 fieldC: f32,
302 fieldD: u32 = 4,302 fieldD: u32 = 4,
303303
304 pub fn foo(self: *const Self) void {304 pub fn foo(self: *const Self) void {
...@@ -329,6 +329,7 @@ test "type info: function type info" {...@@ -329,6 +329,7 @@ test "type info: function type info" {
329329
330 // wasm doesn't support align attributes on functions330 // wasm doesn't support align attributes on functions
331 if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;331 if (builtin.target.cpu.arch == .wasm32 or builtin.target.cpu.arch == .wasm64) return error.SkipZigTest;
332
332 try testFunction();333 try testFunction();
333 comptime try testFunction();334 comptime try testFunction();
334}335}