mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 08:45:52 +00:00
fixups
This commit is contained in:
parent
5a21d3dce0
commit
7c5e3e1f8e
@ -1947,6 +1947,15 @@ test "linked list" {
|
||||
assert(list2.first.?.data == 1234);
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_open|packed struct#}
|
||||
<p>{#syntax#}packed{#endsyntax#} structs have guaranteed in-memory layout.</p>
|
||||
<p>TODO bit fields</p>
|
||||
<p>TODO alignment</p>
|
||||
<p>TODO endianness</p>
|
||||
<p>TODO @bitOffsetOf and @byteOffsetOf</p>
|
||||
<p>TODO mention how volatile loads and stores of bit packed fields could be more efficient when
|
||||
done by hand instead of with packed struct</p>
|
||||
{#header_close#}
|
||||
{#header_open|struct Naming#}
|
||||
<p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p>
|
||||
<ul>
|
||||
@ -5135,6 +5144,18 @@ fn seq(c: u8) void {
|
||||
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.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@bitOffsetOf#}
|
||||
<pre>{#syntax#}@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the bit offset of a field relative to its containing struct.
|
||||
</p>
|
||||
<p>
|
||||
For non {#link|packed structs|packed struct#}, this will always be divisible by {#syntax#}8{#endsyntax#}.
|
||||
For packed structs, non-byte-aligned fields will share a byte offset, but they will have different
|
||||
bit offsets.
|
||||
</p>
|
||||
{#see_also|@byteOffsetOf#}
|
||||
{#header_close#}
|
||||
{#header_open|@breakpoint#}
|
||||
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
|
||||
<p>
|
||||
@ -5145,6 +5166,13 @@ fn seq(c: u8) void {
|
||||
This function is only valid within function scope.
|
||||
</p>
|
||||
|
||||
{#header_close#}
|
||||
{#header_open|@byteOffsetOf#}
|
||||
<pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
Returns the byte offset of a field relative to its containing struct.
|
||||
</p>
|
||||
{#see_also|@bitOffsetOf#}
|
||||
{#header_close#}
|
||||
{#header_open|@alignCast#}
|
||||
<pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>
|
||||
@ -5868,18 +5896,6 @@ fn add(a: i32, b: i32) i32 {
|
||||
</p>
|
||||
{#see_also|@inlineCall#}
|
||||
{#header_close#}
|
||||
{#header_open|@offsetOf#}
|
||||
<pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
|
||||
<p>
|
||||
This function returns the byte offset of a field relative to its containing struct.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@bitOffsetOf#}
|
||||
<pre><code class="zig">@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) (number literal)</code></pre>
|
||||
<p>
|
||||
This function returns the bit offset of a field relative to its containing struct.
|
||||
</p>
|
||||
{#header_close#}
|
||||
{#header_open|@OpaqueType#}
|
||||
<pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
|
||||
<p>
|
||||
|
||||
32
src/ir.cpp
32
src/ir.cpp
@ -17088,30 +17088,36 @@ static ZigType *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira,
|
||||
IrInstructionByteOffsetOf *instruction)
|
||||
{
|
||||
IrInstruction *type_value = instruction->type_value->other;
|
||||
if (type_is_invalid(type_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *field_name_value = instruction->field_name->other;
|
||||
size_t byte_offset = 0;
|
||||
if (validate_byte_offset(ira, type_value, field_name_value, &byte_offset)) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_bigint, byte_offset);
|
||||
return ira->codegen->builtin_types.entry_num_lit_int;
|
||||
}
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (!validate_byte_offset(ira, type_value, field_name_value, &byte_offset))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_bigint, byte_offset);
|
||||
return ira->codegen->builtin_types.entry_num_lit_int;
|
||||
}
|
||||
|
||||
static ZigType *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira,
|
||||
IrInstructionBitOffsetOf *instruction)
|
||||
{
|
||||
IrInstruction *type_value = instruction->type_value->other;
|
||||
if (type_is_invalid(type_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
IrInstruction *field_name_value = instruction->field_name->other;
|
||||
size_t byte_offset = 0;
|
||||
TypeStructField *field = nullptr;
|
||||
if ((field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset))) {
|
||||
size_t bit_offset = byte_offset * 8 + field->packed_bits_offset;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_bigint, bit_offset);
|
||||
return ira->codegen->builtin_types.entry_num_lit_int;
|
||||
}
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
if (!(field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset)))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
size_t bit_offset = byte_offset * 8 + field->packed_bits_offset;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_bigint, bit_offset);
|
||||
return ira->codegen->builtin_types.entry_num_lit_int;
|
||||
}
|
||||
|
||||
static void ensure_field_index(ZigType *type, const char *field_name, size_t index)
|
||||
|
||||
@ -158,12 +158,12 @@ const std = @import("../index.zig");
|
||||
const assert = std.debug.assert;
|
||||
|
||||
comptime {
|
||||
assert(@offsetOf(Kevent, "ident") == 0);
|
||||
assert(@offsetOf(Kevent, "filter") == 8);
|
||||
assert(@offsetOf(Kevent, "flags") == 10);
|
||||
assert(@offsetOf(Kevent, "fflags") == 12);
|
||||
assert(@offsetOf(Kevent, "data") == 16);
|
||||
assert(@offsetOf(Kevent, "udata") == 24);
|
||||
assert(@byteOffsetOf(Kevent, "ident") == 0);
|
||||
assert(@byteOffsetOf(Kevent, "filter") == 8);
|
||||
assert(@byteOffsetOf(Kevent, "flags") == 10);
|
||||
assert(@byteOffsetOf(Kevent, "fflags") == 12);
|
||||
assert(@byteOffsetOf(Kevent, "data") == 16);
|
||||
assert(@byteOffsetOf(Kevent, "udata") == 24);
|
||||
}
|
||||
|
||||
pub const kevent64_s = extern struct {
|
||||
@ -180,11 +180,11 @@ pub const kevent64_s = extern struct {
|
||||
// to make sure the struct is laid out the same. These values were
|
||||
// produced from C code using the offsetof macro.
|
||||
comptime {
|
||||
assert(@offsetOf(kevent64_s, "ident") == 0);
|
||||
assert(@offsetOf(kevent64_s, "filter") == 8);
|
||||
assert(@offsetOf(kevent64_s, "flags") == 10);
|
||||
assert(@offsetOf(kevent64_s, "fflags") == 12);
|
||||
assert(@offsetOf(kevent64_s, "data") == 16);
|
||||
assert(@offsetOf(kevent64_s, "udata") == 24);
|
||||
assert(@offsetOf(kevent64_s, "ext") == 32);
|
||||
assert(@byteOffsetOf(kevent64_s, "ident") == 0);
|
||||
assert(@byteOffsetOf(kevent64_s, "filter") == 8);
|
||||
assert(@byteOffsetOf(kevent64_s, "flags") == 10);
|
||||
assert(@byteOffsetOf(kevent64_s, "fflags") == 12);
|
||||
assert(@byteOffsetOf(kevent64_s, "data") == 16);
|
||||
assert(@byteOffsetOf(kevent64_s, "udata") == 24);
|
||||
assert(@byteOffsetOf(kevent64_s, "ext") == 32);
|
||||
}
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
const builtin = @import("builtin");
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
test "sizeofAndTypeOf" {
|
||||
test "@sizeOf and @typeOf" {
|
||||
const y: @typeOf(x) = 120;
|
||||
assert(@sizeOf(@typeOf(y)) == 2);
|
||||
}
|
||||
const x: u16 = 13;
|
||||
const z: @typeOf(x) = 19;
|
||||
|
||||
const S = struct {
|
||||
const A = struct {
|
||||
a: u8,
|
||||
b: u32,
|
||||
c: u8,
|
||||
@ -27,24 +28,42 @@ const P = packed struct {
|
||||
g: u16,
|
||||
};
|
||||
|
||||
test "byteOffsetOf" {
|
||||
const p: P = undefined;
|
||||
std.debug.assert(@byteOffsetOf(P, "a") == 0 and @byteOffsetOf(S, "a") == 0);
|
||||
std.debug.assert(@byteOffsetOf(P, "b") == 1 and @byteOffsetOf(S, "b") == 4);
|
||||
std.debug.assert(@byteOffsetOf(P, "c") == 5 and @byteOffsetOf(S, "c") == 8);
|
||||
std.debug.assert(@byteOffsetOf(P, "d") == 6 and @byteOffsetOf(S, "d") == 9);
|
||||
std.debug.assert(@byteOffsetOf(P, "e") == 6 and @byteOffsetOf(S, "e") == 10);
|
||||
std.debug.assert(@byteOffsetOf(P, "f") == 7 and @byteOffsetOf(S, "f") == 12);
|
||||
std.debug.assert(@byteOffsetOf(P, "g") == 9 and @byteOffsetOf(S, "g") == 14);
|
||||
test "@byteOffsetOf" {
|
||||
// Packed structs have fixed memory layout
|
||||
assert(@byteOffsetOf(P, "a") == 0);
|
||||
assert(@byteOffsetOf(P, "b") == 1);
|
||||
assert(@byteOffsetOf(P, "c") == 5);
|
||||
assert(@byteOffsetOf(P, "d") == 6);
|
||||
assert(@byteOffsetOf(P, "e") == 6);
|
||||
assert(@byteOffsetOf(P, "f") == 7);
|
||||
assert(@byteOffsetOf(P, "g") == 9);
|
||||
|
||||
// Normal struct fields can be moved/padded
|
||||
var a: A = undefined;
|
||||
assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @byteOffsetOf(A, "a"));
|
||||
assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @byteOffsetOf(A, "b"));
|
||||
assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @byteOffsetOf(A, "c"));
|
||||
assert(@ptrToInt(&a.d) - @ptrToInt(&a) == @byteOffsetOf(A, "d"));
|
||||
assert(@ptrToInt(&a.e) - @ptrToInt(&a) == @byteOffsetOf(A, "e"));
|
||||
assert(@ptrToInt(&a.f) - @ptrToInt(&a) == @byteOffsetOf(A, "f"));
|
||||
assert(@ptrToInt(&a.g) - @ptrToInt(&a) == @byteOffsetOf(A, "g"));
|
||||
}
|
||||
|
||||
test "bitOffsetOf" {
|
||||
const p: P = undefined;
|
||||
std.debug.assert(@bitOffsetOf(P, "a") == 0 and @bitOffsetOf(S, "a") == 0);
|
||||
std.debug.assert(@bitOffsetOf(P, "b") == 8 and @bitOffsetOf(S, "b") == 32);
|
||||
std.debug.assert(@bitOffsetOf(P, "c") == 40 and @bitOffsetOf(S, "c") == 64);
|
||||
std.debug.assert(@bitOffsetOf(P, "d") == 48 and @bitOffsetOf(S, "d") == 72);
|
||||
std.debug.assert(@bitOffsetOf(P, "e") == 51 and @bitOffsetOf(S, "e") == 80);
|
||||
std.debug.assert(@bitOffsetOf(P, "f") == 56 and @bitOffsetOf(S, "f") == 96);
|
||||
std.debug.assert(@bitOffsetOf(P, "g") == 72 and @bitOffsetOf(S, "g") == 112);
|
||||
}
|
||||
test "@bitOffsetOf" {
|
||||
// Packed structs have fixed memory layout
|
||||
assert(@bitOffsetOf(P, "a") == 0);
|
||||
assert(@bitOffsetOf(P, "b") == 8);
|
||||
assert(@bitOffsetOf(P, "c") == 40);
|
||||
assert(@bitOffsetOf(P, "d") == 48);
|
||||
assert(@bitOffsetOf(P, "e") == 51);
|
||||
assert(@bitOffsetOf(P, "f") == 56);
|
||||
assert(@bitOffsetOf(P, "g") == 72);
|
||||
|
||||
assert(@byteOffsetOf(A, "a") * 8 == @bitOffsetOf(A, "a"));
|
||||
assert(@byteOffsetOf(A, "b") * 8 == @bitOffsetOf(A, "b"));
|
||||
assert(@byteOffsetOf(A, "c") * 8 == @bitOffsetOf(A, "c"));
|
||||
assert(@byteOffsetOf(A, "d") * 8 == @bitOffsetOf(A, "d"));
|
||||
assert(@byteOffsetOf(A, "e") * 8 == @bitOffsetOf(A, "e"));
|
||||
assert(@byteOffsetOf(A, "f") * 8 == @bitOffsetOf(A, "f"));
|
||||
assert(@byteOffsetOf(A, "g") * 8 == @bitOffsetOf(A, "g"));
|
||||
}
|
||||
|
||||
@ -3769,7 +3769,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ return @byteOffsetOf(Foo, "a",);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:22: error: expected struct type, found 'i32'",
|
||||
".tmp_source.zig:3:26: error: expected struct type, found 'i32'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3781,7 +3781,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ return @byteOffsetOf(Foo, "a",);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:5:27: error: struct 'Foo' has no field 'a'",
|
||||
".tmp_source.zig:5:31: error: struct 'Foo' has no field 'a'",
|
||||
);
|
||||
|
||||
cases.addExe(
|
||||
@ -5092,7 +5092,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const fieldOffset = @byteOffsetOf(Empty, "val",);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",
|
||||
".tmp_source.zig:5:46: error: zero-bit field 'val' in struct 'Empty' has no offset",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -5104,7 +5104,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\ const fieldOffset = @bitOffsetOf(Empty, "val",);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:5:42: error: zero-bit field 'val' in struct 'Empty' has no offset",
|
||||
".tmp_source.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user