| author | |
| committer | |
| log | c1eb6c30e84b0b161b634f7410088f44c80caa90 |
| tree | 915141c29947e320175cd2c5ed73afaa88ddf259 |
| parent | 9b05474d797ea4600dbae36ae95d9eb042040bb2 |
| parent | 6bf529dc381cb2f5a83c5f9e303ffdab7779ac4d |
| signature |
stage2: fix handling of aggregates with mixed comptime-only fields6 files changed, 153 insertions(+), 119 deletions(-)
src/Sema.zig+4-6| ... | ... | @@ -11747,11 +11747,11 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 11747 | 11747 | |
| 11748 | 11748 | fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 11749 | 11749 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 11750 | const src = inst_data.src(); | |
| 11750 | 11751 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 11751 | const unresolved_operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); | |
| 11752 | const operand_ty = try sema.resolveTypeFields(block, operand_src, unresolved_operand_ty); | |
| 11752 | const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand); | |
| 11753 | 11753 | const target = sema.mod.getTarget(); |
| 11754 | const bit_size = operand_ty.bitSize(target); | |
| 11754 | const bit_size = try operand_ty.bitSizeAdvanced(target, sema.kit(block, src)); | |
| 11755 | 11755 | return sema.addIntUnsigned(Type.comptime_int, bit_size); |
| 11756 | 11756 | } |
| 11757 | 11757 | |
| ... | ... | @@ -25047,9 +25047,7 @@ pub fn typeRequiresComptime(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ |
| 25047 | 25047 | } |
| 25048 | 25048 | |
| 25049 | 25049 | pub fn typeHasRuntimeBits(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool { |
| 25050 | if ((try sema.typeHasOnePossibleValue(block, src, ty)) != null) return false; | |
| 25051 | if (try sema.typeRequiresComptime(block, src, ty)) return false; | |
| 25052 | return true; | |
| 25050 | return ty.hasRuntimeBitsAdvanced(false, sema.kit(block, src)); | |
| 25053 | 25051 | } |
| 25054 | 25052 | |
| 25055 | 25053 | fn typeAbiSize(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !u64 { |
src/codegen/llvm.zig+3-3| ... | ... | @@ -9185,7 +9185,7 @@ fn isByRef(ty: Type) bool { |
| 9185 | 9185 | .AnyFrame, |
| 9186 | 9186 | => return false, |
| 9187 | 9187 | |
| 9188 | .Array, .Frame => return ty.hasRuntimeBitsIgnoreComptime(), | |
| 9188 | .Array, .Frame => return ty.hasRuntimeBits(), | |
| 9189 | 9189 | .Struct => { |
| 9190 | 9190 | // Packed structs are represented to LLVM as integers. |
| 9191 | 9191 | if (ty.containerLayout() == .Packed) return false; |
| ... | ... | @@ -9204,7 +9204,7 @@ fn isByRef(ty: Type) bool { |
| 9204 | 9204 | var count: usize = 0; |
| 9205 | 9205 | const fields = ty.structFields(); |
| 9206 | 9206 | for (fields.values()) |field| { |
| 9207 | if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue; | |
| 9207 | if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; | |
| 9208 | 9208 | |
| 9209 | 9209 | count += 1; |
| 9210 | 9210 | if (count > max_fields_byval) return true; |
| ... | ... | @@ -9212,7 +9212,7 @@ fn isByRef(ty: Type) bool { |
| 9212 | 9212 | } |
| 9213 | 9213 | return false; |
| 9214 | 9214 | }, |
| 9215 | .Union => return ty.hasRuntimeBitsIgnoreComptime(), | |
| 9215 | .Union => return ty.hasRuntimeBits(), | |
| 9216 | 9216 | .ErrorUnion => return isByRef(ty.errorUnionPayload()), |
| 9217 | 9217 | .Optional => { |
| 9218 | 9218 | var buf: Type.Payload.ElemType = undefined; |
src/link/Dwarf.zig+28-26| ... | ... | @@ -352,6 +352,7 @@ pub const DeclState = struct { |
| 352 | 352 | const fields = ty.structFields(); |
| 353 | 353 | for (fields.keys()) |field_name, field_index| { |
| 354 | 354 | const field = fields.get(field_name).?; |
| 355 | if (!field.ty.hasRuntimeBits()) continue; | |
| 355 | 356 | // DW.AT.member |
| 356 | 357 | try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); |
| 357 | 358 | dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); |
| ... | ... | @@ -1037,6 +1038,7 @@ pub fn commitDeclState( |
| 1037 | 1038 | } |
| 1038 | 1039 | } |
| 1039 | 1040 | |
| 1041 | log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name}); | |
| 1040 | 1042 | try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); |
| 1041 | 1043 | |
| 1042 | 1044 | while (decl_state.abbrev_relocs.popOrNull()) |reloc| { |
| ... | ... | @@ -1098,6 +1100,7 @@ pub fn commitDeclState( |
| 1098 | 1100 | } |
| 1099 | 1101 | } |
| 1100 | 1102 | |
| 1103 | log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); | |
| 1101 | 1104 | try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items); |
| 1102 | 1105 | } |
| 1103 | 1106 | |
| ... | ... | @@ -1141,7 +1144,10 @@ fn updateDeclDebugInfoAllocation(self: *Dwarf, file: *File, atom: *Atom, len: u3 |
| 1141 | 1144 | }, |
| 1142 | 1145 | .wasm => { |
| 1143 | 1146 | const wasm_file = file.cast(File.Wasm).?; |
| 1144 | writeDbgInfoNopsBuffered(wasm_file.debug_info.items, atom.off, 0, &.{0}, atom.len, false); | |
| 1147 | const segment_index = try wasm_file.getDebugInfoIndex(); | |
| 1148 | const segment = &wasm_file.segments.items[segment_index]; | |
| 1149 | const offset = segment.offset + atom.off; | |
| 1150 | try writeDbgInfoNopsToArrayList(gpa, &wasm_file.debug_info, offset, 0, &.{0}, atom.len, false); | |
| 1145 | 1151 | }, |
| 1146 | 1152 | else => unreachable, |
| 1147 | 1153 | } |
| ... | ... | @@ -1283,8 +1289,12 @@ fn writeDeclDebugInfo(self: *Dwarf, file: *File, atom: *Atom, dbg_info_buf: []co |
| 1283 | 1289 | debug_info.items.len = needed_size; |
| 1284 | 1290 | } |
| 1285 | 1291 | const offset = segment.offset + atom.off; |
| 1286 | writeDbgInfoNopsBuffered( | |
| 1287 | debug_info.items, | |
| 1292 | log.debug(" writeDbgInfoNopsToArrayList debug_info_len={d} offset={d} content_len={d} next_padding_size={d}", .{ | |
| 1293 | debug_info.items.len, offset, dbg_info_buf.len, next_padding_size, | |
| 1294 | }); | |
| 1295 | try writeDbgInfoNopsToArrayList( | |
| 1296 | gpa, | |
| 1297 | debug_info, | |
| 1288 | 1298 | offset, |
| 1289 | 1299 | prev_padding_size, |
| 1290 | 1300 | dbg_info_buf, |
| ... | ... | @@ -1678,7 +1688,7 @@ pub fn writeDbgInfoHeader(self: *Dwarf, file: *File, module: *Module, low_pc: u6 |
| 1678 | 1688 | }, |
| 1679 | 1689 | .wasm => { |
| 1680 | 1690 | const wasm_file = file.cast(File.Wasm).?; |
| 1681 | writeDbgInfoNopsBuffered(wasm_file.debug_info.items, 0, 0, di_buf.items, jmp_amt, false); | |
| 1691 | try writeDbgInfoNopsToArrayList(self.allocator, &wasm_file.debug_info, 0, 0, di_buf.items, jmp_amt, false); | |
| 1682 | 1692 | }, |
| 1683 | 1693 | else => unreachable, |
| 1684 | 1694 | } |
| ... | ... | @@ -1884,35 +1894,25 @@ fn pwriteDbgInfoNops( |
| 1884 | 1894 | try file.pwritevAll(vecs[0..vec_index], offset - prev_padding_size); |
| 1885 | 1895 | } |
| 1886 | 1896 | |
| 1887 | fn writeDbgInfoNopsBuffered( | |
| 1888 | buf: []u8, | |
| 1897 | fn writeDbgInfoNopsToArrayList( | |
| 1898 | gpa: Allocator, | |
| 1899 | buffer: *std.ArrayListUnmanaged(u8), | |
| 1889 | 1900 | offset: u32, |
| 1890 | 1901 | prev_padding_size: usize, |
| 1891 | 1902 | content: []const u8, |
| 1892 | 1903 | next_padding_size: usize, |
| 1893 | 1904 | trailing_zero: bool, |
| 1894 | ) void { | |
| 1895 | assert(buf.len >= content.len + prev_padding_size + next_padding_size + @boolToInt(trailing_zero)); | |
| 1896 | const tracy = trace(@src()); | |
| 1897 | defer tracy.end(); | |
| 1898 | ||
| 1899 | { | |
| 1900 | var padding_left = prev_padding_size; | |
| 1901 | while (padding_left > 0) : (padding_left -= 1) { | |
| 1902 | buf[offset - padding_left] = @enumToInt(AbbrevKind.pad1); | |
| 1903 | } | |
| 1904 | } | |
| 1905 | ||
| 1906 | mem.copy(u8, buf[offset..], content); | |
| 1907 | { | |
| 1908 | var padding_left = next_padding_size; | |
| 1909 | while (padding_left > 0) : (padding_left -= 1) { | |
| 1910 | buf[offset + content.len + padding_left] = @enumToInt(AbbrevKind.pad1); | |
| 1911 | } | |
| 1912 | } | |
| 1905 | ) Allocator.Error!void { | |
| 1906 | try buffer.resize(gpa, @maximum( | |
| 1907 | buffer.items.len, | |
| 1908 | offset + content.len + next_padding_size + 1, | |
| 1909 | )); | |
| 1910 | mem.set(u8, buffer.items[offset - prev_padding_size .. offset], @enumToInt(AbbrevKind.pad1)); | |
| 1911 | mem.copy(u8, buffer.items[offset..], content); | |
| 1912 | mem.set(u8, buffer.items[offset + content.len ..][0..next_padding_size], @enumToInt(AbbrevKind.pad1)); | |
| 1913 | 1913 | |
| 1914 | 1914 | if (trailing_zero) { |
| 1915 | buf[offset + content.len + next_padding_size] = 0; | |
| 1915 | buffer.items[offset + content.len + next_padding_size] = 0; | |
| 1916 | 1916 | } |
| 1917 | 1917 | } |
| 1918 | 1918 | |
| ... | ... | @@ -2249,7 +2249,9 @@ pub fn flushModule(self: *Dwarf, file: *File, module: *Module) !void { |
| 2249 | 2249 | try addDbgInfoErrorSet(arena, module, error_ty, self.target, &dbg_info_buffer); |
| 2250 | 2250 | |
| 2251 | 2251 | try self.managed_atoms.append(gpa, atom); |
| 2252 | log.debug("updateDeclDebugInfoAllocation in flushModule", .{}); | |
| 2252 | 2253 | try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); |
| 2254 | log.debug("writeDeclDebugInfo in flushModule", .{}); | |
| 2253 | 2255 | try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items); |
| 2254 | 2256 | |
| 2255 | 2257 | const file_pos = blk: { |
src/type.zig+53-60| ... | ... | @@ -2365,6 +2365,7 @@ pub const Type = extern union { |
| 2365 | 2365 | .@"anyframe", |
| 2366 | 2366 | .anyopaque, |
| 2367 | 2367 | .@"opaque", |
| 2368 | .type_info, | |
| 2368 | 2369 | => return true, |
| 2369 | 2370 | |
| 2370 | 2371 | // These are false because they are comptime-only types. |
| ... | ... | @@ -2379,7 +2380,6 @@ pub const Type = extern union { |
| 2379 | 2380 | .enum_literal, |
| 2380 | 2381 | .empty_struct, |
| 2381 | 2382 | .empty_struct_literal, |
| 2382 | .type_info, | |
| 2383 | 2383 | .bound_fn, |
| 2384 | 2384 | // These are function *bodies*, not pointers. |
| 2385 | 2385 | // Special exceptions have to be made when emitting functions due to |
| ... | ... | @@ -2464,14 +2464,6 @@ pub const Type = extern union { |
| 2464 | 2464 | |
| 2465 | 2465 | .@"struct" => { |
| 2466 | 2466 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 2467 | if (sema_kit) |sk| { | |
| 2468 | _ = try sk.sema.typeRequiresComptime(sk.block, sk.src, ty); | |
| 2469 | } | |
| 2470 | switch (struct_obj.requires_comptime) { | |
| 2471 | .yes => return false, | |
| 2472 | .wip, .no => if (struct_obj.known_non_opv) return true, | |
| 2473 | .unknown => {}, | |
| 2474 | } | |
| 2475 | 2467 | if (struct_obj.status == .field_types_wip) { |
| 2476 | 2468 | // In this case, we guess that hasRuntimeBits() for this type is true, |
| 2477 | 2469 | // and then later if our guess was incorrect, we emit a compile error. |
| ... | ... | @@ -3550,9 +3542,19 @@ pub const Type = extern union { |
| 3550 | 3542 | ); |
| 3551 | 3543 | } |
| 3552 | 3544 | |
| 3553 | /// Asserts the type has the bit size already resolved. | |
| 3554 | 3545 | pub fn bitSize(ty: Type, target: Target) u64 { |
| 3555 | return switch (ty.tag()) { | |
| 3546 | return bitSizeAdvanced(ty, target, null) catch unreachable; | |
| 3547 | } | |
| 3548 | ||
| 3549 | /// If you pass `sema_kit`, any recursive type resolutions will happen if | |
| 3550 | /// necessary, possibly returning a CompileError. Passing `null` instead asserts | |
| 3551 | /// the type is fully resolved, and there will be no error, guaranteed. | |
| 3552 | pub fn bitSizeAdvanced( | |
| 3553 | ty: Type, | |
| 3554 | target: Target, | |
| 3555 | sema_kit: ?Module.WipAnalysis, | |
| 3556 | ) Module.CompileError!u64 { | |
| 3557 | switch (ty.tag()) { | |
| 3556 | 3558 | .fn_noreturn_no_args => unreachable, // represents machine code; not a pointer |
| 3557 | 3559 | .fn_void_no_args => unreachable, // represents machine code; not a pointer |
| 3558 | 3560 | .fn_naked_noreturn_no_args => unreachable, // represents machine code; not a pointer |
| ... | ... | @@ -3576,40 +3578,30 @@ pub const Type = extern union { |
| 3576 | 3578 | .generic_poison => unreachable, |
| 3577 | 3579 | .bound_fn => unreachable, |
| 3578 | 3580 | |
| 3579 | .void => 0, | |
| 3580 | .bool, .u1 => 1, | |
| 3581 | .u8, .i8 => 8, | |
| 3582 | .i16, .u16, .f16 => 16, | |
| 3583 | .u29 => 29, | |
| 3584 | .i32, .u32, .f32 => 32, | |
| 3585 | .i64, .u64, .f64 => 64, | |
| 3586 | .f80 => 80, | |
| 3587 | .u128, .i128, .f128 => 128, | |
| 3581 | .void => return 0, | |
| 3582 | .bool, .u1 => return 1, | |
| 3583 | .u8, .i8 => return 8, | |
| 3584 | .i16, .u16, .f16 => return 16, | |
| 3585 | .u29 => return 29, | |
| 3586 | .i32, .u32, .f32 => return 32, | |
| 3587 | .i64, .u64, .f64 => return 64, | |
| 3588 | .f80 => return 80, | |
| 3589 | .u128, .i128, .f128 => return 128, | |
| 3588 | 3590 | |
| 3589 | 3591 | .@"struct" => { |
| 3590 | const field_count = ty.structFieldCount(); | |
| 3591 | if (field_count == 0) return 0; | |
| 3592 | ||
| 3593 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 3594 | assert(struct_obj.haveFieldTypes()); | |
| 3595 | ||
| 3596 | switch (struct_obj.layout) { | |
| 3597 | .Auto, .Extern => { | |
| 3598 | var total: u64 = 0; | |
| 3599 | for (struct_obj.fields.values()) |field| { | |
| 3600 | total += field.ty.bitSize(target); | |
| 3601 | } | |
| 3602 | return total; | |
| 3603 | }, | |
| 3604 | .Packed => return struct_obj.packedIntegerBits(target), | |
| 3592 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); | |
| 3593 | var total: u64 = 0; | |
| 3594 | for (ty.structFields().values()) |field| { | |
| 3595 | total += try bitSizeAdvanced(field.ty, target, sema_kit); | |
| 3605 | 3596 | } |
| 3597 | return total; | |
| 3606 | 3598 | }, |
| 3607 | 3599 | |
| 3608 | 3600 | .tuple, .anon_struct => { |
| 3609 | const tuple = ty.tupleFields(); | |
| 3601 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); | |
| 3610 | 3602 | var total: u64 = 0; |
| 3611 | for (tuple.types) |field_ty| { | |
| 3612 | total += field_ty.bitSize(target); | |
| 3603 | for (ty.tupleFields().types) |field_ty| { | |
| 3604 | total += try bitSizeAdvanced(field_ty, target, sema_kit); | |
| 3613 | 3605 | } |
| 3614 | 3606 | return total; |
| 3615 | 3607 | }, |
| ... | ... | @@ -3617,37 +3609,35 @@ pub const Type = extern union { |
| 3617 | 3609 | .enum_simple, .enum_full, .enum_nonexhaustive, .enum_numbered => { |
| 3618 | 3610 | var buffer: Payload.Bits = undefined; |
| 3619 | 3611 | const int_tag_ty = ty.intTagType(&buffer); |
| 3620 | return int_tag_ty.bitSize(target); | |
| 3612 | return try bitSizeAdvanced(int_tag_ty, target, sema_kit); | |
| 3621 | 3613 | }, |
| 3622 | 3614 | |
| 3623 | 3615 | .@"union", .union_tagged => { |
| 3616 | if (sema_kit) |sk| _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty); | |
| 3624 | 3617 | const union_obj = ty.cast(Payload.Union).?.data; |
| 3625 | ||
| 3626 | const fields = union_obj.fields; | |
| 3627 | if (fields.count() == 0) return 0; | |
| 3628 | ||
| 3629 | 3618 | assert(union_obj.haveFieldTypes()); |
| 3630 | 3619 | |
| 3631 | 3620 | var size: u64 = 0; |
| 3632 | for (fields.values()) |field| { | |
| 3633 | size = @maximum(size, field.ty.bitSize(target)); | |
| 3621 | for (union_obj.fields.values()) |field| { | |
| 3622 | size = @maximum(size, try bitSizeAdvanced(field.ty, target, sema_kit)); | |
| 3634 | 3623 | } |
| 3635 | 3624 | return size; |
| 3636 | 3625 | }, |
| 3637 | 3626 | |
| 3638 | 3627 | .vector => { |
| 3639 | 3628 | const payload = ty.castTag(.vector).?.data; |
| 3640 | const elem_bit_size = payload.elem_type.bitSize(target); | |
| 3629 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, sema_kit); | |
| 3641 | 3630 | return elem_bit_size * payload.len; |
| 3642 | 3631 | }, |
| 3643 | .array_u8 => 8 * ty.castTag(.array_u8).?.data, | |
| 3644 | .array_u8_sentinel_0 => 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), | |
| 3632 | .array_u8 => return 8 * ty.castTag(.array_u8).?.data, | |
| 3633 | .array_u8_sentinel_0 => return 8 * (ty.castTag(.array_u8_sentinel_0).?.data + 1), | |
| 3645 | 3634 | .array => { |
| 3646 | 3635 | const payload = ty.castTag(.array).?.data; |
| 3647 | 3636 | const elem_size = std.math.max(payload.elem_type.abiAlignment(target), payload.elem_type.abiSize(target)); |
| 3648 | 3637 | if (elem_size == 0 or payload.len == 0) |
| 3649 | return 0; | |
| 3650 | return (payload.len - 1) * 8 * elem_size + payload.elem_type.bitSize(target); | |
| 3638 | return @as(u64, 0); | |
| 3639 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, sema_kit); | |
| 3640 | return (payload.len - 1) * 8 * elem_size + elem_bit_size; | |
| 3651 | 3641 | }, |
| 3652 | 3642 | .array_sentinel => { |
| 3653 | 3643 | const payload = ty.castTag(.array_sentinel).?.data; |
| ... | ... | @@ -3655,14 +3645,15 @@ pub const Type = extern union { |
| 3655 | 3645 | payload.elem_type.abiAlignment(target), |
| 3656 | 3646 | payload.elem_type.abiSize(target), |
| 3657 | 3647 | ); |
| 3658 | return payload.len * 8 * elem_size + payload.elem_type.bitSize(target); | |
| 3648 | const elem_bit_size = try bitSizeAdvanced(payload.elem_type, target, sema_kit); | |
| 3649 | return payload.len * 8 * elem_size + elem_bit_size; | |
| 3659 | 3650 | }, |
| 3660 | 3651 | |
| 3661 | 3652 | .isize, |
| 3662 | 3653 | .usize, |
| 3663 | 3654 | .@"anyframe", |
| 3664 | 3655 | .anyframe_T, |
| 3665 | => target.cpu.arch.ptrBitWidth(), | |
| 3656 | => return target.cpu.arch.ptrBitWidth(), | |
| 3666 | 3657 | |
| 3667 | 3658 | .const_slice, |
| 3668 | 3659 | .mut_slice, |
| ... | ... | @@ -3670,7 +3661,7 @@ pub const Type = extern union { |
| 3670 | 3661 | |
| 3671 | 3662 | .const_slice_u8, |
| 3672 | 3663 | .const_slice_u8_sentinel_0, |
| 3673 | => target.cpu.arch.ptrBitWidth() * 2, | |
| 3664 | => return target.cpu.arch.ptrBitWidth() * 2, | |
| 3674 | 3665 | |
| 3675 | 3666 | .optional_single_const_pointer, |
| 3676 | 3667 | .optional_single_mut_pointer, |
| ... | ... | @@ -3689,8 +3680,8 @@ pub const Type = extern union { |
| 3689 | 3680 | }, |
| 3690 | 3681 | |
| 3691 | 3682 | .pointer => switch (ty.castTag(.pointer).?.data.size) { |
| 3692 | .Slice => target.cpu.arch.ptrBitWidth() * 2, | |
| 3693 | else => target.cpu.arch.ptrBitWidth(), | |
| 3683 | .Slice => return target.cpu.arch.ptrBitWidth() * 2, | |
| 3684 | else => return target.cpu.arch.ptrBitWidth(), | |
| 3694 | 3685 | }, |
| 3695 | 3686 | |
| 3696 | 3687 | .manyptr_u8, |
| ... | ... | @@ -3716,7 +3707,7 @@ pub const Type = extern union { |
| 3716 | 3707 | .error_set_merged, |
| 3717 | 3708 | => return 16, // TODO revisit this when we have the concept of the error tag type |
| 3718 | 3709 | |
| 3719 | .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data, | |
| 3710 | .int_signed, .int_unsigned => return ty.cast(Payload.Bits).?.data, | |
| 3720 | 3711 | |
| 3721 | 3712 | .optional => { |
| 3722 | 3713 | var buf: Payload.ElemType = undefined; |
| ... | ... | @@ -3730,7 +3721,8 @@ pub const Type = extern union { |
| 3730 | 3721 | // field and a boolean as the second. Since the child type's abi alignment is |
| 3731 | 3722 | // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal |
| 3732 | 3723 | // to the child type's ABI alignment. |
| 3733 | return child_type.bitSize(target) + 1; | |
| 3724 | const child_bit_size = try bitSizeAdvanced(child_type, target, sema_kit); | |
| 3725 | return child_bit_size + 1; | |
| 3734 | 3726 | }, |
| 3735 | 3727 | |
| 3736 | 3728 | .error_union => { |
| ... | ... | @@ -3738,9 +3730,9 @@ pub const Type = extern union { |
| 3738 | 3730 | if (!payload.error_set.hasRuntimeBits() and !payload.payload.hasRuntimeBits()) { |
| 3739 | 3731 | return 0; |
| 3740 | 3732 | } else if (!payload.error_set.hasRuntimeBits()) { |
| 3741 | return payload.payload.bitSize(target); | |
| 3733 | return payload.payload.bitSizeAdvanced(target, sema_kit); | |
| 3742 | 3734 | } else if (!payload.payload.hasRuntimeBits()) { |
| 3743 | return payload.error_set.bitSize(target); | |
| 3735 | return payload.error_set.bitSizeAdvanced(target, sema_kit); | |
| 3744 | 3736 | } |
| 3745 | 3737 | @panic("TODO bitSize error union"); |
| 3746 | 3738 | }, |
| ... | ... | @@ -3757,7 +3749,7 @@ pub const Type = extern union { |
| 3757 | 3749 | .extern_options, |
| 3758 | 3750 | .type_info, |
| 3759 | 3751 | => @panic("TODO at some point we gotta resolve builtin types"), |
| 3760 | }; | |
| 3752 | } | |
| 3761 | 3753 | } |
| 3762 | 3754 | |
| 3763 | 3755 | pub fn isSinglePointer(self: Type) bool { |
| ... | ... | @@ -5514,6 +5506,7 @@ pub const Type = extern union { |
| 5514 | 5506 | switch (ty.tag()) { |
| 5515 | 5507 | .@"struct" => { |
| 5516 | 5508 | const struct_obj = ty.castTag(.@"struct").?.data; |
| 5509 | assert(struct_obj.haveFieldTypes()); | |
| 5517 | 5510 | return struct_obj.fields.count(); |
| 5518 | 5511 | }, |
| 5519 | 5512 | .empty_struct, .empty_struct_literal => return 0, |
test/behavior/eval.zig+32-1| ... | ... | @@ -1196,7 +1196,9 @@ test "equality of pointers to comptime const" { |
| 1196 | 1196 | } |
| 1197 | 1197 | |
| 1198 | 1198 | test "storing an array of type in a field" { |
| 1199 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO | |
| 1199 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1200 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1201 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1200 | 1202 | |
| 1201 | 1203 | const S = struct { |
| 1202 | 1204 | fn doTheTest() void { |
| ... | ... | @@ -1221,3 +1223,32 @@ test "storing an array of type in a field" { |
| 1221 | 1223 | |
| 1222 | 1224 | S.doTheTest(); |
| 1223 | 1225 | } |
| 1226 | ||
| 1227 | test "pass pointer to field of comptime-only type as a runtime parameter" { | |
| 1228 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 1229 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 1230 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 1231 | ||
| 1232 | const S = struct { | |
| 1233 | const Mixed = struct { | |
| 1234 | T: type, | |
| 1235 | x: i32, | |
| 1236 | }; | |
| 1237 | const bag: Mixed = .{ | |
| 1238 | .T = bool, | |
| 1239 | .x = 1234, | |
| 1240 | }; | |
| 1241 | ||
| 1242 | var ok = false; | |
| 1243 | ||
| 1244 | fn doTheTest() !void { | |
| 1245 | foo(&bag.x); | |
| 1246 | try expect(ok); | |
| 1247 | } | |
| 1248 | ||
| 1249 | fn foo(ptr: *const i32) void { | |
| 1250 | ok = ptr.* == 1234; | |
| 1251 | } | |
| 1252 | }; | |
| 1253 | try S.doTheTest(); | |
| 1254 | } |
test/behavior/packed-struct.zig+33-23| ... | ... | @@ -33,10 +33,10 @@ test "correct size of packed structs" { |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | test "flags in packed structs" { |
| 36 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; | |
| 36 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 37 | 37 | |
| 38 | 38 | const Flags1 = packed struct { |
| 39 | // byte 0 | |
| 39 | // first 8 bits | |
| 40 | 40 | b0_0: u1, |
| 41 | 41 | b0_1: u1, |
| 42 | 42 | b0_2: u1, |
| ... | ... | @@ -46,7 +46,7 @@ test "flags in packed structs" { |
| 46 | 46 | b0_6: u1, |
| 47 | 47 | b0_7: u1, |
| 48 | 48 | |
| 49 | // partial byte 1 (but not 8 bits) | |
| 49 | // 7 more bits | |
| 50 | 50 | b1_0: u1, |
| 51 | 51 | b1_1: u1, |
| 52 | 52 | b1_2: u1, |
| ... | ... | @@ -55,12 +55,12 @@ test "flags in packed structs" { |
| 55 | 55 | b1_5: u1, |
| 56 | 56 | b1_6: u1, |
| 57 | 57 | |
| 58 | // some padding to fill to size 3 | |
| 58 | // some padding to fill to 24 bits | |
| 59 | 59 | _: u9, |
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | try expectEqual(3, @sizeOf(Flags1)); | |
| 63 | try expectEqual(3 * 8, @bitSizeOf(Flags1)); | |
| 62 | try expectEqual(@sizeOf(u24), @sizeOf(Flags1)); | |
| 63 | try expectEqual(24, @bitSizeOf(Flags1)); | |
| 64 | 64 | |
| 65 | 65 | const Flags2 = packed struct { |
| 66 | 66 | // byte 0 |
| ... | ... | @@ -86,8 +86,8 @@ test "flags in packed structs" { |
| 86 | 86 | _: u10, |
| 87 | 87 | }; |
| 88 | 88 | |
| 89 | try expectEqual(4, @sizeOf(Flags2)); | |
| 90 | try expectEqual(8 + 7 + 10, @bitSizeOf(Flags2)); | |
| 89 | try expectEqual(@sizeOf(u25), @sizeOf(Flags2)); | |
| 90 | try expectEqual(25, @bitSizeOf(Flags2)); | |
| 91 | 91 | |
| 92 | 92 | const Flags3 = packed struct { |
| 93 | 93 | // byte 0 |
| ... | ... | @@ -114,30 +114,30 @@ test "flags in packed structs" { |
| 114 | 114 | _: u16, // it works, if the padding is 8-based |
| 115 | 115 | }; |
| 116 | 116 | |
| 117 | try expectEqual(4, @sizeOf(Flags3)); | |
| 118 | try expectEqual(4 * 8, @bitSizeOf(Flags3)); | |
| 117 | try expectEqual(@sizeOf(u32), @sizeOf(Flags3)); | |
| 118 | try expectEqual(32, @bitSizeOf(Flags3)); | |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | 121 | test "arrays in packed structs" { |
| 122 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; | |
| 122 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 123 | 123 | |
| 124 | 124 | const T1 = packed struct { array: [3][3]u8 }; |
| 125 | 125 | const T2 = packed struct { array: [9]u8 }; |
| 126 | 126 | |
| 127 | try expectEqual(9, @sizeOf(T1)); | |
| 128 | try expectEqual(9 * 8, @bitSizeOf(T1)); | |
| 129 | try expectEqual(9, @sizeOf(T2)); | |
| 130 | try expectEqual(9 * 8, @bitSizeOf(T2)); | |
| 127 | try expectEqual(@sizeOf(u72), @sizeOf(T1)); | |
| 128 | try expectEqual(72, @bitSizeOf(T1)); | |
| 129 | try expectEqual(@sizeOf(u72), @sizeOf(T2)); | |
| 130 | try expectEqual(72, @bitSizeOf(T2)); | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | test "consistent size of packed structs" { |
| 134 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; | |
| 134 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 135 | 135 | |
| 136 | 136 | const TxData1 = packed struct { data: u8, _23: u23, full: bool = false }; |
| 137 | 137 | const TxData2 = packed struct { data: u9, _22: u22, full: bool = false }; |
| 138 | 138 | |
| 139 | 139 | const register_size_bits = 32; |
| 140 | const register_size_bytes = register_size_bits / 8; | |
| 140 | const register_size_bytes = @sizeOf(u32); | |
| 141 | 141 | |
| 142 | 142 | try expectEqual(register_size_bits, @bitSizeOf(TxData1)); |
| 143 | 143 | try expectEqual(register_size_bytes, @sizeOf(TxData1)); |
| ... | ... | @@ -151,7 +151,7 @@ test "consistent size of packed structs" { |
| 151 | 151 | const TxData6 = packed struct { a: u24, b: u32 }; |
| 152 | 152 | |
| 153 | 153 | const expectedBitSize = 56; |
| 154 | const expectedByteSize = expectedBitSize / 8; | |
| 154 | const expectedByteSize = @sizeOf(u56); | |
| 155 | 155 | |
| 156 | 156 | try expectEqual(expectedBitSize, @bitSizeOf(TxData3)); |
| 157 | 157 | try expectEqual(expectedByteSize, @sizeOf(TxData3)); |
| ... | ... | @@ -167,7 +167,12 @@ test "consistent size of packed structs" { |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | test "correct sizeOf and offsets in packed structs" { |
| 170 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; | |
| 170 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 171 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 172 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 173 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 174 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 175 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 171 | 176 | |
| 172 | 177 | const PStruct = packed struct { |
| 173 | 178 | bool_a: bool, |
| ... | ... | @@ -234,11 +239,16 @@ test "correct sizeOf and offsets in packed structs" { |
| 234 | 239 | |
| 235 | 240 | try expectEqual(16, @offsetOf(S, "b")); |
| 236 | 241 | try expectEqual(128, @bitOffsetOf(S, "b")); |
| 237 | try expectEqual(20, @sizeOf(S)); | |
| 242 | try expectEqual(@sizeOf(u160), @sizeOf(S)); | |
| 238 | 243 | } |
| 239 | 244 | |
| 240 | 245 | test "nested packed structs" { |
| 241 | if (builtin.zig_backend != .stage1) return error.SkipZigTest; | |
| 246 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; | |
| 247 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 248 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | |
| 249 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 250 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 251 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 242 | 252 | |
| 243 | 253 | const S1 = packed struct { a: u8, b: u8, c: u8 }; |
| 244 | 254 | |
| ... | ... | @@ -248,7 +258,7 @@ test "nested packed structs" { |
| 248 | 258 | const S3Padded = packed struct { s3: S3, pad: u16 }; |
| 249 | 259 | |
| 250 | 260 | try expectEqual(48, @bitSizeOf(S3)); |
| 251 | try expectEqual(6, @sizeOf(S3)); | |
| 261 | try expectEqual(@sizeOf(u48), @sizeOf(S3)); | |
| 252 | 262 | |
| 253 | 263 | try expectEqual(3, @offsetOf(S3, "y")); |
| 254 | 264 | try expectEqual(24, @bitOffsetOf(S3, "y")); |
| ... | ... | @@ -268,7 +278,7 @@ test "nested packed structs" { |
| 268 | 278 | const S6 = packed struct { a: i32, b: S4, c: i8 }; |
| 269 | 279 | |
| 270 | 280 | const expectedBitSize = 80; |
| 271 | const expectedByteSize = expectedBitSize / 8; | |
| 281 | const expectedByteSize = @sizeOf(u80); | |
| 272 | 282 | try expectEqual(expectedBitSize, @bitSizeOf(S5)); |
| 273 | 283 | try expectEqual(expectedByteSize, @sizeOf(S5)); |
| 274 | 284 | try expectEqual(expectedBitSize, @bitSizeOf(S6)); |