authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-21 14:15:58-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-21 14:15:58-04:00
log7c5e3e1f8e4671b383865df0150b549e2445d170
tree5bc73aa60ecc49695fd9bf8bab550ac1e75657be
parent5a21d3dce0c020833bfe426049e2391ae3977846
signaturelock-open Commit is signed but in an unrecognized format.

fixups


5 files changed, 104 insertions(+), 63 deletions(-)

doc/langref.html.in+28-12
...@@ -1947,6 +1947,15 @@ test "linked list" {...@@ -1947,6 +1947,15 @@ test "linked list" {
1947 assert(list2.first.?.data == 1234);1947 assert(list2.first.?.data == 1234);
1948}1948}
1949 {#code_end#}1949 {#code_end#}
1950 {#header_open|packed struct#}
1951 <p>{#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout.</p>
1952 <p>TODO bit fields</p>
1953 <p>TODO alignment</p>
1954 <p>TODO endianness</p>
1955 <p>TODO @bitOffsetOf and @byteOffsetOf</p>
1956 <p>TODO mention how volatile loads and stores of bit packed fields could be more efficient when
1957 done by hand instead of with packed struct</p>
1958 {#header_close#}
1950 {#header_open|struct Naming#}1959 {#header_open|struct Naming#}
1951 <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p>1960 <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p>
1952 <ul>1961 <ul>
...@@ -5135,6 +5144,18 @@ fn seq(c: u8) void {...@@ -5135,6 +5144,18 @@ fn seq(c: u8) void {
5135 Works at compile-time if {#syntax#}value{#endsyntax#} is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works.5144 Works at compile-time if {#syntax#}value{#endsyntax#} is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works.
5136 </p>5145 </p>
5137 {#header_close#}5146 {#header_close#}
5147 {#header_open|@bitOffsetOf#}
5148 <pre>{#syntax#}@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
5149 <p>
5150 Returns the bit offset of a field relative to its containing struct.
5151 </p>
5152 <p>
5153 For non {#link|packed structs|packed struct#}, this will always be divisible by {#syntax#}8{#endsyntax#}.
5154 For packed structs, non-byte-aligned fields will share a byte offset, but they will have different
5155 bit offsets.
5156 </p>
5157 {#see_also|@byteOffsetOf#}
5158 {#header_close#}
5138 {#header_open|@breakpoint#}5159 {#header_open|@breakpoint#}
5139 <pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>5160 <pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
5140 <p>5161 <p>
...@@ -5145,6 +5166,13 @@ fn seq(c: u8) void {...@@ -5145,6 +5166,13 @@ fn seq(c: u8) void {
5145 This function is only valid within function scope.5166 This function is only valid within function scope.
5146 </p>5167 </p>
51475168
5169 {#header_close#}
5170 {#header_open|@byteOffsetOf#}
5171 <pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
5172 <p>
5173 Returns the byte offset of a field relative to its containing struct.
5174 </p>
5175 {#see_also|@bitOffsetOf#}
5148 {#header_close#}5176 {#header_close#}
5149 {#header_open|@alignCast#}5177 {#header_open|@alignCast#}
5150 <pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>5178 <pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>
...@@ -5868,18 +5896,6 @@ fn add(a: i32, b: i32) i32 {...@@ -5868,18 +5896,6 @@ fn add(a: i32, b: i32) i32 {
5868 </p>5896 </p>
5869 {#see_also|@inlineCall#}5897 {#see_also|@inlineCall#}
5870 {#header_close#}5898 {#header_close#}
5871 {#header_open|@offsetOf#}
5872 <pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
5873 <p>
5874 This function returns the byte offset of a field relative to its containing struct.
5875 </p>
5876 {#header_close#}
5877 {#header_open|@bitOffsetOf#}
5878 <pre><code class="zig">@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre>
5879 <p>
5880 This function returns the bit offset of a field relative to its containing struct.
5881 </p>
5882 {#header_close#}
5883 {#header_open|@OpaqueType#}5899 {#header_open|@OpaqueType#}
5884 <pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>5900 <pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
5885 <p>5901 <p>
src/ir.cpp+19-13
...@@ -17088,30 +17088,36 @@ static ZigType *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira,...@@ -17088,30 +17088,36 @@ static ZigType *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira,
17088 IrInstructionByteOffsetOf *instruction)17088 IrInstructionByteOffsetOf *instruction)
17089{17089{
17090 IrInstruction *type_value = instruction->type_value->other;17090 IrInstruction *type_value = instruction->type_value->other;
17091 if (type_is_invalid(type_value->value.type))
17092 return ira->codegen->builtin_types.entry_invalid;
17093
17091 IrInstruction *field_name_value = instruction->field_name->other;17094 IrInstruction *field_name_value = instruction->field_name->other;
17092 size_t byte_offset = 0;17095 size_t byte_offset = 0;
17093 if (validate_byte_offset(ira, type_value, field_name_value, &byte_offset)) {17096 if (!validate_byte_offset(ira, type_value, field_name_value, &byte_offset))
17094 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);17097 return ira->codegen->builtin_types.entry_invalid;
17095 bigint_init_unsigned(&out_val->data.x_bigint, byte_offset);17098
17096 return ira->codegen->builtin_types.entry_num_lit_int;17099
17097 }17100 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17098 return ira->codegen->builtin_types.entry_invalid;17101 bigint_init_unsigned(&out_val->data.x_bigint, byte_offset);
17102 return ira->codegen->builtin_types.entry_num_lit_int;
17099}17103}
1710017104
17101static ZigType *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,17105static ZigType *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
17102 IrInstructionBitOffsetOf *instruction)17106 IrInstructionBitOffsetOf *instruction)
17103{17107{
17104 IrInstruction *type_value = instruction->type_value->other;17108 IrInstruction *type_value = instruction->type_value->other;
17109 if (type_is_invalid(type_value->value.type))
17110 return ira->codegen->builtin_types.entry_invalid;
17105 IrInstruction *field_name_value = instruction->field_name->other;17111 IrInstruction *field_name_value = instruction->field_name->other;
17106 size_t byte_offset = 0;17112 size_t byte_offset = 0;
17107 TypeStructField *field = nullptr;17113 TypeStructField *field = nullptr;
17108 if ((field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset))) {17114 if (!(field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset)))
17109 size_t bit_offset = byte_offset * 8 + field->packed_bits_offset;17115 return ira->codegen->builtin_types.entry_invalid;
17110 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);17116
17111 bigint_init_unsigned(&out_val->data.x_bigint, bit_offset);17117 size_t bit_offset = byte_offset * 8 + field->packed_bits_offset;
17112 return ira->codegen->builtin_types.entry_num_lit_int;17118 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17113 }17119 bigint_init_unsigned(&out_val->data.x_bigint, bit_offset);
17114 return ira->codegen->builtin_types.entry_invalid;17120 return ira->codegen->builtin_types.entry_num_lit_int;
17115}17121}
1711617122
17117static void ensure_field_index(ZigType *type, const char *field_name, size_t index)17123static void ensure_field_index(ZigType *type, const char *field_name, size_t index)
std/c/darwin.zig+13-13
...@@ -158,12 +158,12 @@ const std = @import("../index.zig");...@@ -158,12 +158,12 @@ const std = @import("../index.zig");
158const assert = std.debug.assert;158const assert = std.debug.assert;
159159
160comptime {160comptime {
161 assert(@offsetOf(Kevent, "ident") == 0);161 assert(@byteOffsetOf(Kevent, "ident") == 0);
162 assert(@offsetOf(Kevent, "filter") == 8);162 assert(@byteOffsetOf(Kevent, "filter") == 8);
163 assert(@offsetOf(Kevent, "flags") == 10);163 assert(@byteOffsetOf(Kevent, "flags") == 10);
164 assert(@offsetOf(Kevent, "fflags") == 12);164 assert(@byteOffsetOf(Kevent, "fflags") == 12);
165 assert(@offsetOf(Kevent, "data") == 16);165 assert(@byteOffsetOf(Kevent, "data") == 16);
166 assert(@offsetOf(Kevent, "udata") == 24);166 assert(@byteOffsetOf(Kevent, "udata") == 24);
167}167}
168168
169pub const kevent64_s = extern struct {169pub const kevent64_s = extern struct {
...@@ -180,11 +180,11 @@ pub const kevent64_s = extern struct {...@@ -180,11 +180,11 @@ pub const kevent64_s = extern struct {
180// to make sure the struct is laid out the same. These values were180// to make sure the struct is laid out the same. These values were
181// produced from C code using the offsetof macro.181// produced from C code using the offsetof macro.
182comptime {182comptime {
183 assert(@offsetOf(kevent64_s, "ident") == 0);183 assert(@byteOffsetOf(kevent64_s, "ident") == 0);
184 assert(@offsetOf(kevent64_s, "filter") == 8);184 assert(@byteOffsetOf(kevent64_s, "filter") == 8);
185 assert(@offsetOf(kevent64_s, "flags") == 10);185 assert(@byteOffsetOf(kevent64_s, "flags") == 10);
186 assert(@offsetOf(kevent64_s, "fflags") == 12);186 assert(@byteOffsetOf(kevent64_s, "fflags") == 12);
187 assert(@offsetOf(kevent64_s, "data") == 16);187 assert(@byteOffsetOf(kevent64_s, "data") == 16);
188 assert(@offsetOf(kevent64_s, "udata") == 24);188 assert(@byteOffsetOf(kevent64_s, "udata") == 24);
189 assert(@offsetOf(kevent64_s, "ext") == 32);189 assert(@byteOffsetOf(kevent64_s, "ext") == 32);
190}190}
test/cases/sizeof_and_typeof.zig+40-21
...@@ -1,13 +1,14 @@...@@ -1,13 +1,14 @@
1const builtin = @import("builtin");
1const assert = @import("std").debug.assert;2const assert = @import("std").debug.assert;
23
3test "sizeofAndTypeOf" {4test "@sizeOf and @typeOf" {
4 const y: @typeOf(x) = 120;5 const y: @typeOf(x) = 120;
5 assert(@sizeOf(@typeOf(y)) == 2);6 assert(@sizeOf(@typeOf(y)) == 2);
6}7}
7const x: u16 = 13;8const x: u16 = 13;
8const z: @typeOf(x) = 19;9const z: @typeOf(x) = 19;
910
10const S = struct {11const A = struct {
11 a: u8,12 a: u8,
12 b: u32,13 b: u32,
13 c: u8,14 c: u8,
...@@ -27,24 +28,42 @@ const P = packed struct {...@@ -27,24 +28,42 @@ const P = packed struct {
27 g: u16,28 g: u16,
28};29};
2930
30test "byteOffsetOf" {31test "@byteOffsetOf" {
31 const p: P = undefined;32 // Packed structs have fixed memory layout
32 std.debug.assert(@byteOffsetOf(P, "a") == 0 and @byteOffsetOf(S, "a") == 0);33 assert(@byteOffsetOf(P, "a") == 0);
33 std.debug.assert(@byteOffsetOf(P, "b") == 1 and @byteOffsetOf(S, "b") == 4);34 assert(@byteOffsetOf(P, "b") == 1);
34 std.debug.assert(@byteOffsetOf(P, "c") == 5 and @byteOffsetOf(S, "c") == 8);35 assert(@byteOffsetOf(P, "c") == 5);
35 std.debug.assert(@byteOffsetOf(P, "d") == 6 and @byteOffsetOf(S, "d") == 9);36 assert(@byteOffsetOf(P, "d") == 6);
36 std.debug.assert(@byteOffsetOf(P, "e") == 6 and @byteOffsetOf(S, "e") == 10);37 assert(@byteOffsetOf(P, "e") == 6);
37 std.debug.assert(@byteOffsetOf(P, "f") == 7 and @byteOffsetOf(S, "f") == 12);38 assert(@byteOffsetOf(P, "f") == 7);
38 std.debug.assert(@byteOffsetOf(P, "g") == 9 and @byteOffsetOf(S, "g") == 14);39 assert(@byteOffsetOf(P, "g") == 9);
40
41 // Normal struct fields can be moved/padded
42 var a: A = undefined;
43 assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
44 assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
45 assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
46 assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
47 assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
48 assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
49 assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
39}50}
4051
41test "bitOffsetOf" {
42 const p: P = undefined;
43 std.debug.assert(@bitOffsetOf(P, "a") == 0 and @bitOffsetOf(S, "a") == 0);
44 std.debug.assert(@bitOffsetOf(P, "b") == 8 and @bitOffsetOf(S, "b") == 32);
45 std.debug.assert(@bitOffsetOf(P, "c") == 40 and @bitOffsetOf(S, "c") == 64);
46 std.debug.assert(@bitOffsetOf(P, "d") == 48 and @bitOffsetOf(S, "d") == 72);
47 std.debug.assert(@bitOffsetOf(P, "e") == 51 and @bitOffsetOf(S, "e") == 80);
48 std.debug.assert(@bitOffsetOf(P, "f") == 56 and @bitOffsetOf(S, "f") == 96);
49 std.debug.assert(@bitOffsetOf(P, "g") == 72 and @bitOffsetOf(S, "g") == 112);
50}
\ No newline at end of file
52test "@bitOffsetOf" {
53 // Packed structs have fixed memory layout
54 assert(@bitOffsetOf(P, "a") == 0);
55 assert(@bitOffsetOf(P, "b") == 8);
56 assert(@bitOffsetOf(P, "c") == 40);
57 assert(@bitOffsetOf(P, "d") == 48);
58 assert(@bitOffsetOf(P, "e") == 51);
59 assert(@bitOffsetOf(P, "f") == 56);
60 assert(@bitOffsetOf(P, "g") == 72);
61
62 assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
63 assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
64 assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
65 assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
66 assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
67 assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
68 assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
69}
test/compile_errors.zig+4-4
...@@ -3769,7 +3769,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3769,7 +3769,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3769 \\ return @byteOffsetOf(Foo, "a",);3769 \\ return @byteOffsetOf(Foo, "a",);
3770 \\}3770 \\}
3771 ,3771 ,
3772 ".tmp_source.zig:3:22: error: expected struct type, found 'i32'",3772 ".tmp_source.zig:3:26: error: expected struct type, found 'i32'",
3773 );3773 );
37743774
3775 cases.add(3775 cases.add(
...@@ -3781,7 +3781,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3781,7 +3781,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3781 \\ return @byteOffsetOf(Foo, "a",);3781 \\ return @byteOffsetOf(Foo, "a",);
3782 \\}3782 \\}
3783 ,3783 ,
3784 ".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'",3784 ".tmp_source.zig:5:31: error: struct 'Foo' has no field 'a'",
3785 );3785 );
37863786
3787 cases.addExe(3787 cases.addExe(
...@@ -5092,7 +5092,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5092,7 +5092,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5092 \\ const fieldOffset = @byteOffsetOf(Empty, "val",);5092 \\ const fieldOffset = @byteOffsetOf(Empty, "val",);
5093 \\}5093 \\}
5094 ,5094 ,
5095 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",5095 ".tmp_source.zig:5:46: error: zero-bit field 'val' in struct 'Empty' has no offset",
5096 );5096 );
50975097
5098 cases.add(5098 cases.add(
...@@ -5104,7 +5104,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -5104,7 +5104,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
5104 \\ const fieldOffset = @bitOffsetOf(Empty, "val",);5104 \\ const fieldOffset = @bitOffsetOf(Empty, "val",);
5105 \\}5105 \\}
5106 ,5106 ,
5107 ".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",5107 ".tmp_source.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
5108 );5108 );
51095109
5110 cases.add(5110 cases.add(