| author | |
| committer | |
| log | 7651913fd20c3bd8ee4b2c8bb180c068e3e037a8 |
| tree | 8487dfd20828f723229dcca1adccfd6174d46bd1 |
| parent | cc5c25d48b5331396bfa5218dc7f29dff26e20f9 |
| parent | 5cbb35abd06f7975c17b0a188b7a1b88e08dbd1e |
| signature |
Stage2 bitOffsetOf and offsetOf builtin functions5 files changed, 305 insertions(+), 168 deletions(-)
src/Sema.zig+53-5| ... | @@ -11046,15 +11046,63 @@ fn zirShrExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai | ... | @@ -11046,15 +11046,63 @@ fn zirShrExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 11046 | } | 11046 | } |
| 11047 | 11047 | ||
| 11048 | fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 11048 | fn zirBitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 11049 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 11049 | const offset = try bitOffsetOf(sema, block, inst); |
| 11050 | const src = inst_data.src(); | 11050 | return sema.addIntUnsigned(Type.comptime_int, offset); |
| 11051 | return sema.fail(block, src, "TODO: Sema.zirBitOffsetOf", .{}); | ||
| 11052 | } | 11051 | } |
| 11053 | 11052 | ||
| 11054 | fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 11053 | fn zirOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 11054 | const offset = try bitOffsetOf(sema, block, inst); | ||
| 11055 | return sema.addIntUnsigned(Type.comptime_int, offset / 8); | ||
| 11056 | } | ||
| 11057 | |||
| 11058 | fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u64 { | ||
| 11055 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; | 11059 | const inst_data = sema.code.instructions.items(.data)[inst].pl_node; |
| 11056 | const src = inst_data.src(); | 11060 | sema.src = .{ .node_offset_bin_op = inst_data.src_node }; |
| 11057 | return sema.fail(block, src, "TODO: Sema.zirOffsetOf", .{}); | 11061 | const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node }; |
| 11062 | const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node }; | ||
| 11063 | const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; | ||
| 11064 | |||
| 11065 | const ty = try sema.resolveType(block, lhs_src, extra.lhs); | ||
| 11066 | const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs); | ||
| 11067 | |||
| 11068 | try sema.resolveTypeLayout(block, lhs_src, ty); | ||
| 11069 | if (ty.tag() != .@"struct") { | ||
| 11070 | return sema.fail( | ||
| 11071 | block, | ||
| 11072 | lhs_src, | ||
| 11073 | "expected struct type, found '{}'", | ||
| 11074 | .{ty}, | ||
| 11075 | ); | ||
| 11076 | } | ||
| 11077 | |||
| 11078 | const index = ty.structFields().getIndex(field_name) orelse { | ||
| 11079 | return sema.fail( | ||
| 11080 | block, | ||
| 11081 | rhs_src, | ||
| 11082 | "struct '{}' has no field '{s}'", | ||
| 11083 | .{ ty, field_name }, | ||
| 11084 | ); | ||
| 11085 | }; | ||
| 11086 | |||
| 11087 | const target = sema.mod.getTarget(); | ||
| 11088 | const layout = ty.containerLayout(); | ||
| 11089 | if (layout == .Packed) { | ||
| 11090 | var it = ty.iteratePackedStructOffsets(target); | ||
| 11091 | while (it.next()) |field_offset| { | ||
| 11092 | if (field_offset.field == index) { | ||
| 11093 | return (field_offset.offset * 8) + field_offset.running_bits; | ||
| 11094 | } | ||
| 11095 | } | ||
| 11096 | } else { | ||
| 11097 | var it = ty.iterateStructOffsets(target); | ||
| 11098 | while (it.next()) |field_offset| { | ||
| 11099 | if (field_offset.field == index) { | ||
| 11100 | return field_offset.offset * 8; | ||
| 11101 | } | ||
| 11102 | } | ||
| 11103 | } | ||
| 11104 | |||
| 11105 | unreachable; | ||
| 11058 | } | 11106 | } |
| 11059 | 11107 | ||
| 11060 | /// Returns `true` if the type was a comptime_int. | 11108 | /// Returns `true` if the type was a comptime_int. |
src/type.zig+137-49| ... | @@ -2922,6 +2922,15 @@ pub const Type = extern union { | ... | @@ -2922,6 +2922,15 @@ pub const Type = extern union { |
| 2922 | } | 2922 | } |
| 2923 | } | 2923 | } |
| 2924 | 2924 | ||
| 2925 | pub fn containerLayout(ty: Type) std.builtin.TypeInfo.ContainerLayout { | ||
| 2926 | return switch (ty.tag()) { | ||
| 2927 | .@"struct" => ty.castTag(.@"struct").?.data.layout, | ||
| 2928 | .@"union" => ty.castTag(.@"union").?.data.layout, | ||
| 2929 | .union_tagged => ty.castTag(.union_tagged).?.data.layout, | ||
| 2930 | else => unreachable, | ||
| 2931 | }; | ||
| 2932 | } | ||
| 2933 | |||
| 2925 | /// Asserts that the type is an error union. | 2934 | /// Asserts that the type is an error union. |
| 2926 | pub fn errorUnionPayload(self: Type) Type { | 2935 | pub fn errorUnionPayload(self: Type) Type { |
| 2927 | return switch (self.tag()) { | 2936 | return switch (self.tag()) { |
| ... | @@ -3765,6 +3774,116 @@ pub const Type = extern union { | ... | @@ -3765,6 +3774,116 @@ pub const Type = extern union { |
| 3765 | } | 3774 | } |
| 3766 | } | 3775 | } |
| 3767 | 3776 | ||
| 3777 | pub const PackedFieldOffset = struct { | ||
| 3778 | field: usize, | ||
| 3779 | offset: u64, | ||
| 3780 | running_bits: u16, | ||
| 3781 | }; | ||
| 3782 | |||
| 3783 | pub const PackedStructOffsetIterator = struct { | ||
| 3784 | field: usize = 0, | ||
| 3785 | offset: u64 = 0, | ||
| 3786 | big_align: u32 = 0, | ||
| 3787 | running_bits: u16 = 0, | ||
| 3788 | struct_obj: *Module.Struct, | ||
| 3789 | target: Target, | ||
| 3790 | |||
| 3791 | pub fn next(it: *PackedStructOffsetIterator) ?PackedFieldOffset { | ||
| 3792 | comptime assert(Type.packed_struct_layout_version == 1); | ||
| 3793 | if (it.struct_obj.fields.count() <= it.field) | ||
| 3794 | return null; | ||
| 3795 | |||
| 3796 | const field = it.struct_obj.fields.values()[it.field]; | ||
| 3797 | defer it.field += 1; | ||
| 3798 | if (!field.ty.hasCodeGenBits()) { | ||
| 3799 | return PackedFieldOffset{ | ||
| 3800 | .field = it.field, | ||
| 3801 | .offset = it.offset, | ||
| 3802 | .running_bits = it.running_bits, | ||
| 3803 | }; | ||
| 3804 | } | ||
| 3805 | |||
| 3806 | const field_align = field.packedAlignment(); | ||
| 3807 | if (field_align == 0) { | ||
| 3808 | defer it.running_bits += @intCast(u16, field.ty.bitSize(it.target)); | ||
| 3809 | return PackedFieldOffset{ | ||
| 3810 | .field = it.field, | ||
| 3811 | .offset = it.offset, | ||
| 3812 | .running_bits = it.running_bits, | ||
| 3813 | }; | ||
| 3814 | } else { | ||
| 3815 | it.big_align = @maximum(it.big_align, field_align); | ||
| 3816 | |||
| 3817 | if (it.running_bits != 0) { | ||
| 3818 | var int_payload: Payload.Bits = .{ | ||
| 3819 | .base = .{ .tag = .int_unsigned }, | ||
| 3820 | .data = it.running_bits, | ||
| 3821 | }; | ||
| 3822 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; | ||
| 3823 | const int_align = int_ty.abiAlignment(it.target); | ||
| 3824 | it.big_align = @maximum(it.big_align, int_align); | ||
| 3825 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, int_align); | ||
| 3826 | it.offset += int_ty.abiSize(it.target); | ||
| 3827 | it.running_bits = 0; | ||
| 3828 | } | ||
| 3829 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); | ||
| 3830 | defer it.offset += field.ty.abiSize(it.target); | ||
| 3831 | return PackedFieldOffset{ | ||
| 3832 | .field = it.field, | ||
| 3833 | .offset = it.offset, | ||
| 3834 | .running_bits = it.running_bits, | ||
| 3835 | }; | ||
| 3836 | } | ||
| 3837 | } | ||
| 3838 | }; | ||
| 3839 | |||
| 3840 | /// Get an iterator that iterates over all the struct field, returning the field and | ||
| 3841 | /// offset of that field. Asserts that the type is a none packed struct. | ||
| 3842 | pub fn iteratePackedStructOffsets(ty: Type, target: Target) PackedStructOffsetIterator { | ||
| 3843 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 3844 | assert(struct_obj.haveLayout()); | ||
| 3845 | assert(struct_obj.layout == .Packed); | ||
| 3846 | return .{ .struct_obj = struct_obj, .target = target }; | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | pub const FieldOffset = struct { | ||
| 3850 | field: usize, | ||
| 3851 | offset: u64, | ||
| 3852 | }; | ||
| 3853 | |||
| 3854 | pub const StructOffsetIterator = struct { | ||
| 3855 | field: usize = 0, | ||
| 3856 | offset: u64 = 0, | ||
| 3857 | big_align: u32 = 0, | ||
| 3858 | struct_obj: *Module.Struct, | ||
| 3859 | target: Target, | ||
| 3860 | |||
| 3861 | pub fn next(it: *StructOffsetIterator) ?FieldOffset { | ||
| 3862 | if (it.struct_obj.fields.count() <= it.field) | ||
| 3863 | return null; | ||
| 3864 | |||
| 3865 | const field = it.struct_obj.fields.values()[it.field]; | ||
| 3866 | defer it.field += 1; | ||
| 3867 | if (!field.ty.hasCodeGenBits()) | ||
| 3868 | return FieldOffset{ .field = it.field, .offset = it.offset }; | ||
| 3869 | |||
| 3870 | const field_align = field.normalAlignment(it.target); | ||
| 3871 | it.big_align = @maximum(it.big_align, field_align); | ||
| 3872 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align); | ||
| 3873 | defer it.offset += field.ty.abiSize(it.target); | ||
| 3874 | return FieldOffset{ .field = it.field, .offset = it.offset }; | ||
| 3875 | } | ||
| 3876 | }; | ||
| 3877 | |||
| 3878 | /// Get an iterator that iterates over all the struct field, returning the field and | ||
| 3879 | /// offset of that field. Asserts that the type is a none packed struct. | ||
| 3880 | pub fn iterateStructOffsets(ty: Type, target: Target) StructOffsetIterator { | ||
| 3881 | const struct_obj = ty.castTag(.@"struct").?.data; | ||
| 3882 | assert(struct_obj.haveLayout()); | ||
| 3883 | assert(struct_obj.layout != .Packed); | ||
| 3884 | return .{ .struct_obj = struct_obj, .target = target }; | ||
| 3885 | } | ||
| 3886 | |||
| 3768 | /// Supports structs and unions. | 3887 | /// Supports structs and unions. |
| 3769 | /// For packed structs, it returns the byte offset of the containing integer. | 3888 | /// For packed structs, it returns the byte offset of the containing integer. |
| 3770 | pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 { | 3889 | pub fn structFieldOffset(ty: Type, index: usize, target: Target) u64 { |
| ... | @@ -3774,65 +3893,34 @@ pub const Type = extern union { | ... | @@ -3774,65 +3893,34 @@ pub const Type = extern union { |
| 3774 | assert(struct_obj.haveLayout()); | 3893 | assert(struct_obj.haveLayout()); |
| 3775 | const is_packed = struct_obj.layout == .Packed; | 3894 | const is_packed = struct_obj.layout == .Packed; |
| 3776 | if (!is_packed) { | 3895 | if (!is_packed) { |
| 3777 | var offset: u64 = 0; | 3896 | var it = ty.iterateStructOffsets(target); |
| 3778 | var big_align: u32 = 0; | 3897 | while (it.next()) |field_offset| { |
| 3779 | for (struct_obj.fields.values()) |field, i| { | 3898 | if (index == field_offset.field) |
| 3780 | if (!field.ty.hasCodeGenBits()) continue; | 3899 | return field_offset.offset; |
| 3781 | |||
| 3782 | const field_align = field.normalAlignment(target); | ||
| 3783 | big_align = @maximum(big_align, field_align); | ||
| 3784 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | ||
| 3785 | if (i == index) return offset; | ||
| 3786 | offset += field.ty.abiSize(target); | ||
| 3787 | } | 3900 | } |
| 3788 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | ||
| 3789 | return offset; | ||
| 3790 | } | ||
| 3791 | 3901 | ||
| 3792 | comptime assert(Type.packed_struct_layout_version == 1); | 3902 | return std.mem.alignForwardGeneric(u64, it.offset, it.big_align); |
| 3793 | var offset: u64 = 0; | 3903 | } |
| 3794 | var big_align: u32 = 0; | ||
| 3795 | var running_bits: u16 = 0; | ||
| 3796 | for (struct_obj.fields.values()) |field, i| { | ||
| 3797 | if (!field.ty.hasCodeGenBits()) continue; | ||
| 3798 | |||
| 3799 | const field_align = field.packedAlignment(); | ||
| 3800 | if (field_align == 0) { | ||
| 3801 | if (i == index) return offset; | ||
| 3802 | running_bits += @intCast(u16, field.ty.bitSize(target)); | ||
| 3803 | } else { | ||
| 3804 | big_align = @maximum(big_align, field_align); | ||
| 3805 | 3904 | ||
| 3806 | if (running_bits != 0) { | 3905 | var it = ty.iteratePackedStructOffsets(target); |
| 3807 | var int_payload: Payload.Bits = .{ | 3906 | while (it.next()) |field_offset| { |
| 3808 | .base = .{ .tag = .int_unsigned }, | 3907 | if (index == field_offset.field) |
| 3809 | .data = running_bits, | 3908 | return field_offset.offset; |
| 3810 | }; | ||
| 3811 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; | ||
| 3812 | const int_align = int_ty.abiAlignment(target); | ||
| 3813 | big_align = @maximum(big_align, int_align); | ||
| 3814 | offset = std.mem.alignForwardGeneric(u64, offset, int_align); | ||
| 3815 | offset += int_ty.abiSize(target); | ||
| 3816 | running_bits = 0; | ||
| 3817 | } | ||
| 3818 | offset = std.mem.alignForwardGeneric(u64, offset, field_align); | ||
| 3819 | if (i == index) return offset; | ||
| 3820 | offset += field.ty.abiSize(target); | ||
| 3821 | } | ||
| 3822 | } | 3909 | } |
| 3823 | if (running_bits != 0) { | 3910 | |
| 3911 | if (it.running_bits != 0) { | ||
| 3824 | var int_payload: Payload.Bits = .{ | 3912 | var int_payload: Payload.Bits = .{ |
| 3825 | .base = .{ .tag = .int_unsigned }, | 3913 | .base = .{ .tag = .int_unsigned }, |
| 3826 | .data = running_bits, | 3914 | .data = it.running_bits, |
| 3827 | }; | 3915 | }; |
| 3828 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; | 3916 | const int_ty: Type = .{ .ptr_otherwise = &int_payload.base }; |
| 3829 | const int_align = int_ty.abiAlignment(target); | 3917 | const int_align = int_ty.abiAlignment(target); |
| 3830 | big_align = @maximum(big_align, int_align); | 3918 | it.big_align = @maximum(it.big_align, int_align); |
| 3831 | offset = std.mem.alignForwardGeneric(u64, offset, int_align); | 3919 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, int_align); |
| 3832 | offset += int_ty.abiSize(target); | 3920 | it.offset += int_ty.abiSize(target); |
| 3833 | } | 3921 | } |
| 3834 | offset = std.mem.alignForwardGeneric(u64, offset, big_align); | 3922 | it.offset = std.mem.alignForwardGeneric(u64, it.offset, it.big_align); |
| 3835 | return offset; | 3923 | return it.offset; |
| 3836 | }, | 3924 | }, |
| 3837 | .@"union" => return 0, | 3925 | .@"union" => return 0, |
| 3838 | .union_tagged => { | 3926 | .union_tagged => { |
test/behavior.zig+2-2| ... | @@ -81,6 +81,7 @@ test { | ... | @@ -81,6 +81,7 @@ test { |
| 81 | _ = @import("behavior/bugs/1310.zig"); | 81 | _ = @import("behavior/bugs/1310.zig"); |
| 82 | _ = @import("behavior/bugs/1381.zig"); | 82 | _ = @import("behavior/bugs/1381.zig"); |
| 83 | _ = @import("behavior/bugs/1500.zig"); | 83 | _ = @import("behavior/bugs/1500.zig"); |
| 84 | _ = @import("behavior/bugs/1735.zig"); | ||
| 84 | _ = @import("behavior/bugs/1741.zig"); | 85 | _ = @import("behavior/bugs/1741.zig"); |
| 85 | _ = @import("behavior/bugs/2006.zig"); | 86 | _ = @import("behavior/bugs/2006.zig"); |
| 86 | _ = @import("behavior/bugs/2578.zig"); | 87 | _ = @import("behavior/bugs/2578.zig"); |
| ... | @@ -98,6 +99,7 @@ test { | ... | @@ -98,6 +99,7 @@ test { |
| 98 | _ = @import("behavior/generics_llvm.zig"); | 99 | _ = @import("behavior/generics_llvm.zig"); |
| 99 | _ = @import("behavior/math.zig"); | 100 | _ = @import("behavior/math.zig"); |
| 100 | _ = @import("behavior/maximum_minimum.zig"); | 101 | _ = @import("behavior/maximum_minimum.zig"); |
| 102 | _ = @import("behavior/merge_error_sets.zig"); | ||
| 101 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); | 103 | _ = @import("behavior/namespace_depends_on_compile_var.zig"); |
| 102 | _ = @import("behavior/null_llvm.zig"); | 104 | _ = @import("behavior/null_llvm.zig"); |
| 103 | _ = @import("behavior/optional_llvm.zig"); | 105 | _ = @import("behavior/optional_llvm.zig"); |
| ... | @@ -137,7 +139,6 @@ test { | ... | @@ -137,7 +139,6 @@ test { |
| 137 | _ = @import("behavior/bugs/1421.zig"); | 139 | _ = @import("behavior/bugs/1421.zig"); |
| 138 | _ = @import("behavior/bugs/1442.zig"); | 140 | _ = @import("behavior/bugs/1442.zig"); |
| 139 | _ = @import("behavior/bugs/1607.zig"); | 141 | _ = @import("behavior/bugs/1607.zig"); |
| 140 | _ = @import("behavior/bugs/1735.zig"); | ||
| 141 | _ = @import("behavior/bugs/1851.zig"); | 142 | _ = @import("behavior/bugs/1851.zig"); |
| 142 | _ = @import("behavior/bugs/1914.zig"); | 143 | _ = @import("behavior/bugs/1914.zig"); |
| 143 | _ = @import("behavior/bugs/2114.zig"); | 144 | _ = @import("behavior/bugs/2114.zig"); |
| ... | @@ -171,7 +172,6 @@ test { | ... | @@ -171,7 +172,6 @@ test { |
| 171 | _ = @import("behavior/if_stage1.zig"); | 172 | _ = @import("behavior/if_stage1.zig"); |
| 172 | _ = @import("behavior/ir_block_deps.zig"); | 173 | _ = @import("behavior/ir_block_deps.zig"); |
| 173 | _ = @import("behavior/math_stage1.zig"); | 174 | _ = @import("behavior/math_stage1.zig"); |
| 174 | _ = @import("behavior/merge_error_sets.zig"); | ||
| 175 | _ = @import("behavior/misc.zig"); | 175 | _ = @import("behavior/misc.zig"); |
| 176 | _ = @import("behavior/muladd.zig"); | 176 | _ = @import("behavior/muladd.zig"); |
| 177 | _ = @import("behavior/null_stage1.zig"); | 177 | _ = @import("behavior/null_stage1.zig"); |
test/behavior/sizeof_and_typeof.zig+113| ... | @@ -47,3 +47,116 @@ fn fn1(alpha: bool) void { | ... | @@ -47,3 +47,116 @@ fn fn1(alpha: bool) void { |
| 47 | test "lazy @sizeOf result is checked for definedness" { | 47 | test "lazy @sizeOf result is checked for definedness" { |
| 48 | _ = fn1; | 48 | _ = fn1; |
| 49 | } | 49 | } |
| 50 | |||
| 51 | const A = struct { | ||
| 52 | a: u8, | ||
| 53 | b: u32, | ||
| 54 | c: u8, | ||
| 55 | d: u3, | ||
| 56 | e: u5, | ||
| 57 | f: u16, | ||
| 58 | g: u16, | ||
| 59 | h: u9, | ||
| 60 | i: u7, | ||
| 61 | }; | ||
| 62 | |||
| 63 | const P = packed struct { | ||
| 64 | a: u8, | ||
| 65 | b: u32, | ||
| 66 | c: u8, | ||
| 67 | d: u3, | ||
| 68 | e: u5, | ||
| 69 | f: u16, | ||
| 70 | g: u16, | ||
| 71 | h: u9, | ||
| 72 | i: u7, | ||
| 73 | }; | ||
| 74 | |||
| 75 | test "@offsetOf" { | ||
| 76 | |||
| 77 | // Packed structs have fixed memory layout | ||
| 78 | try expect(@offsetOf(P, "a") == 0); | ||
| 79 | try expect(@offsetOf(P, "b") == 1); | ||
| 80 | try expect(@offsetOf(P, "c") == 5); | ||
| 81 | try expect(@offsetOf(P, "d") == 6); | ||
| 82 | try expect(@offsetOf(P, "e") == 6); | ||
| 83 | try expect(@offsetOf(P, "f") == 7); | ||
| 84 | try expect(@offsetOf(P, "g") == 9); | ||
| 85 | try expect(@offsetOf(P, "h") == 11); | ||
| 86 | try expect(@offsetOf(P, "i") == 12); | ||
| 87 | |||
| 88 | // // Normal struct fields can be moved/padded | ||
| 89 | var a: A = undefined; | ||
| 90 | try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a")); | ||
| 91 | try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(A, "b")); | ||
| 92 | try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(A, "c")); | ||
| 93 | try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @offsetOf(A, "d")); | ||
| 94 | try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @offsetOf(A, "e")); | ||
| 95 | try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @offsetOf(A, "f")); | ||
| 96 | try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @offsetOf(A, "g")); | ||
| 97 | try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @offsetOf(A, "h")); | ||
| 98 | try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @offsetOf(A, "i")); | ||
| 99 | } | ||
| 100 | |||
| 101 | test "@offsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" { | ||
| 102 | const p3a_len = 3; | ||
| 103 | const P3 = packed struct { | ||
| 104 | a: [p3a_len]u8, | ||
| 105 | b: usize, | ||
| 106 | }; | ||
| 107 | try std.testing.expect(0 == @offsetOf(P3, "a")); | ||
| 108 | try std.testing.expect(p3a_len == @offsetOf(P3, "b")); | ||
| 109 | |||
| 110 | const p5a_len = 5; | ||
| 111 | const P5 = packed struct { | ||
| 112 | a: [p5a_len]u8, | ||
| 113 | b: usize, | ||
| 114 | }; | ||
| 115 | try std.testing.expect(0 == @offsetOf(P5, "a")); | ||
| 116 | try std.testing.expect(p5a_len == @offsetOf(P5, "b")); | ||
| 117 | |||
| 118 | const p6a_len = 6; | ||
| 119 | const P6 = packed struct { | ||
| 120 | a: [p6a_len]u8, | ||
| 121 | b: usize, | ||
| 122 | }; | ||
| 123 | try std.testing.expect(0 == @offsetOf(P6, "a")); | ||
| 124 | try std.testing.expect(p6a_len == @offsetOf(P6, "b")); | ||
| 125 | |||
| 126 | const p7a_len = 7; | ||
| 127 | const P7 = packed struct { | ||
| 128 | a: [p7a_len]u8, | ||
| 129 | b: usize, | ||
| 130 | }; | ||
| 131 | try std.testing.expect(0 == @offsetOf(P7, "a")); | ||
| 132 | try std.testing.expect(p7a_len == @offsetOf(P7, "b")); | ||
| 133 | |||
| 134 | const p9a_len = 9; | ||
| 135 | const P9 = packed struct { | ||
| 136 | a: [p9a_len]u8, | ||
| 137 | b: usize, | ||
| 138 | }; | ||
| 139 | try std.testing.expect(0 == @offsetOf(P9, "a")); | ||
| 140 | try std.testing.expect(p9a_len == @offsetOf(P9, "b")); | ||
| 141 | |||
| 142 | // 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases | ||
| 143 | } | ||
| 144 | |||
| 145 | test "@bitOffsetOf" { | ||
| 146 | // Packed structs have fixed memory layout | ||
| 147 | try expect(@bitOffsetOf(P, "a") == 0); | ||
| 148 | try expect(@bitOffsetOf(P, "b") == 8); | ||
| 149 | try expect(@bitOffsetOf(P, "c") == 40); | ||
| 150 | try expect(@bitOffsetOf(P, "d") == 48); | ||
| 151 | try expect(@bitOffsetOf(P, "e") == 51); | ||
| 152 | try expect(@bitOffsetOf(P, "f") == 56); | ||
| 153 | try expect(@bitOffsetOf(P, "g") == 72); | ||
| 154 | |||
| 155 | try expect(@offsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); | ||
| 156 | try expect(@offsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); | ||
| 157 | try expect(@offsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); | ||
| 158 | try expect(@offsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); | ||
| 159 | try expect(@offsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); | ||
| 160 | try expect(@offsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); | ||
| 161 | try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); | ||
| 162 | } |
test/behavior/sizeof_and_typeof_stage1.zig-112| ... | @@ -2,118 +2,6 @@ const std = @import("std"); | ... | @@ -2,118 +2,6 @@ const std = @import("std"); |
| 2 | const expect = std.testing.expect; | 2 | const expect = std.testing.expect; |
| 3 | const expectEqual = std.testing.expectEqual; | 3 | const expectEqual = std.testing.expectEqual; |
| 4 | 4 | ||
| 5 | const A = struct { | ||
| 6 | a: u8, | ||
| 7 | b: u32, | ||
| 8 | c: u8, | ||
| 9 | d: u3, | ||
| 10 | e: u5, | ||
| 11 | f: u16, | ||
| 12 | g: u16, | ||
| 13 | h: u9, | ||
| 14 | i: u7, | ||
| 15 | }; | ||
| 16 | |||
| 17 | const P = packed struct { | ||
| 18 | a: u8, | ||
| 19 | b: u32, | ||
| 20 | c: u8, | ||
| 21 | d: u3, | ||
| 22 | e: u5, | ||
| 23 | f: u16, | ||
| 24 | g: u16, | ||
| 25 | h: u9, | ||
| 26 | i: u7, | ||
| 27 | }; | ||
| 28 | |||
| 29 | test "@offsetOf" { | ||
| 30 | // Packed structs have fixed memory layout | ||
| 31 | try expect(@offsetOf(P, "a") == 0); | ||
| 32 | try expect(@offsetOf(P, "b") == 1); | ||
| 33 | try expect(@offsetOf(P, "c") == 5); | ||
| 34 | try expect(@offsetOf(P, "d") == 6); | ||
| 35 | try expect(@offsetOf(P, "e") == 6); | ||
| 36 | try expect(@offsetOf(P, "f") == 7); | ||
| 37 | try expect(@offsetOf(P, "g") == 9); | ||
| 38 | try expect(@offsetOf(P, "h") == 11); | ||
| 39 | try expect(@offsetOf(P, "i") == 12); | ||
| 40 | |||
| 41 | // Normal struct fields can be moved/padded | ||
| 42 | var a: A = undefined; | ||
| 43 | try expect(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a")); | ||
| 44 | try expect(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(A, "b")); | ||
| 45 | try expect(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(A, "c")); | ||
| 46 | try expect(@ptrToInt(&a.d) - @ptrToInt(&a) == @offsetOf(A, "d")); | ||
| 47 | try expect(@ptrToInt(&a.e) - @ptrToInt(&a) == @offsetOf(A, "e")); | ||
| 48 | try expect(@ptrToInt(&a.f) - @ptrToInt(&a) == @offsetOf(A, "f")); | ||
| 49 | try expect(@ptrToInt(&a.g) - @ptrToInt(&a) == @offsetOf(A, "g")); | ||
| 50 | try expect(@ptrToInt(&a.h) - @ptrToInt(&a) == @offsetOf(A, "h")); | ||
| 51 | try expect(@ptrToInt(&a.i) - @ptrToInt(&a) == @offsetOf(A, "i")); | ||
| 52 | } | ||
| 53 | |||
| 54 | test "@offsetOf packed struct, array length not power of 2 or multiple of native pointer width in bytes" { | ||
| 55 | const p3a_len = 3; | ||
| 56 | const P3 = packed struct { | ||
| 57 | a: [p3a_len]u8, | ||
| 58 | b: usize, | ||
| 59 | }; | ||
| 60 | try std.testing.expectEqual(0, @offsetOf(P3, "a")); | ||
| 61 | try std.testing.expectEqual(p3a_len, @offsetOf(P3, "b")); | ||
| 62 | |||
| 63 | const p5a_len = 5; | ||
| 64 | const P5 = packed struct { | ||
| 65 | a: [p5a_len]u8, | ||
| 66 | b: usize, | ||
| 67 | }; | ||
| 68 | try std.testing.expectEqual(0, @offsetOf(P5, "a")); | ||
| 69 | try std.testing.expectEqual(p5a_len, @offsetOf(P5, "b")); | ||
| 70 | |||
| 71 | const p6a_len = 6; | ||
| 72 | const P6 = packed struct { | ||
| 73 | a: [p6a_len]u8, | ||
| 74 | b: usize, | ||
| 75 | }; | ||
| 76 | try std.testing.expectEqual(0, @offsetOf(P6, "a")); | ||
| 77 | try std.testing.expectEqual(p6a_len, @offsetOf(P6, "b")); | ||
| 78 | |||
| 79 | const p7a_len = 7; | ||
| 80 | const P7 = packed struct { | ||
| 81 | a: [p7a_len]u8, | ||
| 82 | b: usize, | ||
| 83 | }; | ||
| 84 | try std.testing.expectEqual(0, @offsetOf(P7, "a")); | ||
| 85 | try std.testing.expectEqual(p7a_len, @offsetOf(P7, "b")); | ||
| 86 | |||
| 87 | const p9a_len = 9; | ||
| 88 | const P9 = packed struct { | ||
| 89 | a: [p9a_len]u8, | ||
| 90 | b: usize, | ||
| 91 | }; | ||
| 92 | try std.testing.expectEqual(0, @offsetOf(P9, "a")); | ||
| 93 | try std.testing.expectEqual(p9a_len, @offsetOf(P9, "b")); | ||
| 94 | |||
| 95 | // 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 25 etc. are further cases | ||
| 96 | } | ||
| 97 | |||
| 98 | test "@bitOffsetOf" { | ||
| 99 | // Packed structs have fixed memory layout | ||
| 100 | try expect(@bitOffsetOf(P, "a") == 0); | ||
| 101 | try expect(@bitOffsetOf(P, "b") == 8); | ||
| 102 | try expect(@bitOffsetOf(P, "c") == 40); | ||
| 103 | try expect(@bitOffsetOf(P, "d") == 48); | ||
| 104 | try expect(@bitOffsetOf(P, "e") == 51); | ||
| 105 | try expect(@bitOffsetOf(P, "f") == 56); | ||
| 106 | try expect(@bitOffsetOf(P, "g") == 72); | ||
| 107 | |||
| 108 | try expect(@offsetOf(A, "a") * 8 == @bitOffsetOf(A, "a")); | ||
| 109 | try expect(@offsetOf(A, "b") * 8 == @bitOffsetOf(A, "b")); | ||
| 110 | try expect(@offsetOf(A, "c") * 8 == @bitOffsetOf(A, "c")); | ||
| 111 | try expect(@offsetOf(A, "d") * 8 == @bitOffsetOf(A, "d")); | ||
| 112 | try expect(@offsetOf(A, "e") * 8 == @bitOffsetOf(A, "e")); | ||
| 113 | try expect(@offsetOf(A, "f") * 8 == @bitOffsetOf(A, "f")); | ||
| 114 | try expect(@offsetOf(A, "g") * 8 == @bitOffsetOf(A, "g")); | ||
| 115 | } | ||
| 116 | |||
| 117 | test "@sizeOf(T) == 0 doesn't force resolving struct size" { | 5 | test "@sizeOf(T) == 0 doesn't force resolving struct size" { |
| 118 | const S = struct { | 6 | const S = struct { |
| 119 | const Foo = struct { | 7 | const Foo = struct { |