| author | |
| committer | |
| log | 0ca12ded2ffbbc6f703d66541481bab5d8cbb2e3 |
| tree | 5bc73aa60ecc49695fd9bf8bab550ac1e75657be |
| parent | 44f2ee101f244342ec7e4cd81bb21d9a0c23267b |
| parent | 7c5e3e1f8e4671b383865df0150b549e2445d170 |
| signature |
8 files changed, 233 insertions(+), 72 deletions(-)
doc/langref.html.in+28-6| ... | ... | @@ -1947,6 +1947,15 @@ test "linked list" { |
| 1947 | 1947 | assert(list2.first.?.data == 1234); |
| 1948 | 1948 | } |
| 1949 | 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 | 1959 | {#header_open|struct Naming#} |
| 1951 | 1960 | <p>Since all structs are anonymous, Zig infers the type name based on a few rules.</p> |
| 1952 | 1961 | <ul> |
| ... | ... | @@ -5135,6 +5144,18 @@ fn seq(c: u8) void { |
| 5135 | 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 | 5145 | </p> |
| 5137 | 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 | 5159 | {#header_open|@breakpoint#} |
| 5139 | 5160 | <pre>{#syntax#}@breakpoint(){#endsyntax#}</pre> |
| 5140 | 5161 | <p> |
| ... | ... | @@ -5145,6 +5166,13 @@ fn seq(c: u8) void { |
| 5145 | 5166 | This function is only valid within function scope. |
| 5146 | 5167 | </p> |
| 5147 | 5168 | |
| 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 | 5176 | {#header_close#} |
| 5149 | 5177 | {#header_open|@alignCast#} |
| 5150 | 5178 | <pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre> |
| ... | ... | @@ -5868,12 +5896,6 @@ fn add(a: i32, b: i32) i32 { |
| 5868 | 5896 | </p> |
| 5869 | 5897 | {#see_also|@inlineCall#} |
| 5870 | 5898 | {#header_close#} |
| 5871 | {#header_open|@offsetOf#} | |
| 5872 | <pre>{#syntax#}@offsetOf(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 | 5899 | {#header_open|@OpaqueType#} |
| 5878 | 5900 | <pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre> |
| 5879 | 5901 | <p> |
src/all_types.hpp+12-3| ... | ... | @@ -1409,7 +1409,8 @@ enum BuiltinFnId { |
| 1409 | 1409 | BuiltinFnIdTagName, |
| 1410 | 1410 | BuiltinFnIdTagType, |
| 1411 | 1411 | BuiltinFnIdFieldParentPtr, |
| 1412 | BuiltinFnIdOffsetOf, | |
| 1412 | BuiltinFnIdByteOffsetOf, | |
| 1413 | BuiltinFnIdBitOffsetOf, | |
| 1413 | 1414 | BuiltinFnIdInlineCall, |
| 1414 | 1415 | BuiltinFnIdNoInlineCall, |
| 1415 | 1416 | BuiltinFnIdNewStackCall, |
| ... | ... | @@ -2134,7 +2135,8 @@ enum IrInstructionId { |
| 2134 | 2135 | IrInstructionIdTagName, |
| 2135 | 2136 | IrInstructionIdTagType, |
| 2136 | 2137 | IrInstructionIdFieldParentPtr, |
| 2137 | IrInstructionIdOffsetOf, | |
| 2138 | IrInstructionIdByteOffsetOf, | |
| 2139 | IrInstructionIdBitOffsetOf, | |
| 2138 | 2140 | IrInstructionIdTypeInfo, |
| 2139 | 2141 | IrInstructionIdTypeId, |
| 2140 | 2142 | IrInstructionIdSetEvalBranchQuota, |
| ... | ... | @@ -3037,7 +3039,14 @@ struct IrInstructionFieldParentPtr { |
| 3037 | 3039 | TypeStructField *field; |
| 3038 | 3040 | }; |
| 3039 | 3041 | |
| 3040 | struct IrInstructionOffsetOf { | |
| 3042 | struct IrInstructionByteOffsetOf { | |
| 3043 | IrInstruction base; | |
| 3044 | ||
| 3045 | IrInstruction *type_value; | |
| 3046 | IrInstruction *field_name; | |
| 3047 | }; | |
| 3048 | ||
| 3049 | struct IrInstructionBitOffsetOf { | |
| 3041 | 3050 | IrInstruction base; |
| 3042 | 3051 | |
| 3043 | 3052 | IrInstruction *type_value; |
src/codegen.cpp+4-2| ... | ... | @@ -5098,7 +5098,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 5098 | 5098 | case IrInstructionIdTypeName: |
| 5099 | 5099 | case IrInstructionIdDeclRef: |
| 5100 | 5100 | case IrInstructionIdSwitchVar: |
| 5101 | case IrInstructionIdOffsetOf: | |
| 5101 | case IrInstructionIdByteOffsetOf: | |
| 5102 | case IrInstructionIdBitOffsetOf: | |
| 5102 | 5103 | case IrInstructionIdTypeInfo: |
| 5103 | 5104 | case IrInstructionIdTypeId: |
| 5104 | 5105 | case IrInstructionIdSetEvalBranchQuota: |
| ... | ... | @@ -6671,7 +6672,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 6671 | 6672 | create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); |
| 6672 | 6673 | create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1); |
| 6673 | 6674 | create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); |
| 6674 | create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); | |
| 6675 | create_builtin_fn(g, BuiltinFnIdByteOffsetOf, "byteOffsetOf", 2); | |
| 6676 | create_builtin_fn(g, BuiltinFnIdBitOffsetOf, "bitOffsetOf", 2); | |
| 6675 | 6677 | create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); |
| 6676 | 6678 | create_builtin_fn(g, BuiltinFnIdDivTrunc, "divTrunc", 2); |
| 6677 | 6679 | create_builtin_fn(g, BuiltinFnIdDivFloor, "divFloor", 2); |
src/ir.cpp+94-24| ... | ... | @@ -720,8 +720,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr * |
| 720 | 720 | return IrInstructionIdFieldParentPtr; |
| 721 | 721 | } |
| 722 | 722 | |
| 723 | static constexpr IrInstructionId ir_instruction_id(IrInstructionOffsetOf *) { | |
| 724 | return IrInstructionIdOffsetOf; | |
| 723 | static constexpr IrInstructionId ir_instruction_id(IrInstructionByteOffsetOf *) { | |
| 724 | return IrInstructionIdByteOffsetOf; | |
| 725 | } | |
| 726 | ||
| 727 | static constexpr IrInstructionId ir_instruction_id(IrInstructionBitOffsetOf *) { | |
| 728 | return IrInstructionIdBitOffsetOf; | |
| 725 | 729 | } |
| 726 | 730 | |
| 727 | 731 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { |
| ... | ... | @@ -2628,10 +2632,23 @@ static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, As |
| 2628 | 2632 | return &instruction->base; |
| 2629 | 2633 | } |
| 2630 | 2634 | |
| 2631 | static IrInstruction *ir_build_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2635 | static IrInstruction *ir_build_byte_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2632 | 2636 | IrInstruction *type_value, IrInstruction *field_name) |
| 2633 | 2637 | { |
| 2634 | IrInstructionOffsetOf *instruction = ir_build_instruction<IrInstructionOffsetOf>(irb, scope, source_node); | |
| 2638 | IrInstructionByteOffsetOf *instruction = ir_build_instruction<IrInstructionByteOffsetOf>(irb, scope, source_node); | |
| 2639 | instruction->type_value = type_value; | |
| 2640 | instruction->field_name = field_name; | |
| 2641 | ||
| 2642 | ir_ref_instruction(type_value, irb->current_basic_block); | |
| 2643 | ir_ref_instruction(field_name, irb->current_basic_block); | |
| 2644 | ||
| 2645 | return &instruction->base; | |
| 2646 | } | |
| 2647 | ||
| 2648 | static IrInstruction *ir_build_bit_offset_of(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2649 | IrInstruction *type_value, IrInstruction *field_name) | |
| 2650 | { | |
| 2651 | IrInstructionBitOffsetOf *instruction = ir_build_instruction<IrInstructionBitOffsetOf>(irb, scope, source_node); | |
| 2635 | 2652 | instruction->type_value = type_value; |
| 2636 | 2653 | instruction->field_name = field_name; |
| 2637 | 2654 | |
| ... | ... | @@ -4688,7 +4705,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4688 | 4705 | IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); |
| 4689 | 4706 | return ir_lval_wrap(irb, scope, field_parent_ptr, lval); |
| 4690 | 4707 | } |
| 4691 | case BuiltinFnIdOffsetOf: | |
| 4708 | case BuiltinFnIdByteOffsetOf: | |
| 4692 | 4709 | { |
| 4693 | 4710 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 4694 | 4711 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| ... | ... | @@ -4700,7 +4717,22 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4700 | 4717 | if (arg1_value == irb->codegen->invalid_instruction) |
| 4701 | 4718 | return arg1_value; |
| 4702 | 4719 | |
| 4703 | IrInstruction *offset_of = ir_build_offset_of(irb, scope, node, arg0_value, arg1_value); | |
| 4720 | IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value); | |
| 4721 | return ir_lval_wrap(irb, scope, offset_of, lval); | |
| 4722 | } | |
| 4723 | case BuiltinFnIdBitOffsetOf: | |
| 4724 | { | |
| 4725 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4726 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4727 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4728 | return arg0_value; | |
| 4729 | ||
| 4730 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 4731 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 4732 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 4733 | return arg1_value; | |
| 4734 | ||
| 4735 | IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); | |
| 4704 | 4736 | return ir_lval_wrap(irb, scope, offset_of, lval); |
| 4705 | 4737 | } |
| 4706 | 4738 | case BuiltinFnIdInlineCall: |
| ... | ... | @@ -17010,49 +17042,84 @@ static ZigType *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 17010 | 17042 | return result_type; |
| 17011 | 17043 | } |
| 17012 | 17044 | |
| 17013 | static ZigType *ir_analyze_instruction_offset_of(IrAnalyze *ira, | |
| 17014 | IrInstructionOffsetOf *instruction) | |
| 17045 | static TypeStructField *validate_byte_offset(IrAnalyze *ira, | |
| 17046 | IrInstruction *type_value, | |
| 17047 | IrInstruction *field_name_value, | |
| 17048 | size_t *byte_offset) | |
| 17015 | 17049 | { |
| 17016 | Error err; | |
| 17017 | IrInstruction *type_value = instruction->type_value->other; | |
| 17018 | 17050 | ZigType *container_type = ir_resolve_type(ira, type_value); |
| 17019 | 17051 | if (type_is_invalid(container_type)) |
| 17020 | return ira->codegen->builtin_types.entry_invalid; | |
| 17052 | return nullptr; | |
| 17021 | 17053 | |
| 17054 | Error err; | |
| 17022 | 17055 | if ((err = ensure_complete_type(ira->codegen, container_type))) |
| 17023 | return ira->codegen->builtin_types.entry_invalid; | |
| 17056 | return nullptr; | |
| 17024 | 17057 | |
| 17025 | IrInstruction *field_name_value = instruction->field_name->other; | |
| 17026 | 17058 | Buf *field_name = ir_resolve_str(ira, field_name_value); |
| 17027 | 17059 | if (!field_name) |
| 17028 | return ira->codegen->builtin_types.entry_invalid; | |
| 17060 | return nullptr; | |
| 17029 | 17061 | |
| 17030 | 17062 | if (container_type->id != ZigTypeIdStruct) { |
| 17031 | 17063 | ir_add_error(ira, type_value, |
| 17032 | 17064 | buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); |
| 17033 | return ira->codegen->builtin_types.entry_invalid; | |
| 17065 | return nullptr; | |
| 17034 | 17066 | } |
| 17035 | 17067 | |
| 17036 | 17068 | TypeStructField *field = find_struct_type_field(container_type, field_name); |
| 17037 | 17069 | if (field == nullptr) { |
| 17038 | 17070 | ir_add_error(ira, field_name_value, |
| 17039 | 17071 | buf_sprintf("struct '%s' has no field '%s'", |
| 17040 | buf_ptr(&container_type->name), buf_ptr(field_name))); | |
| 17041 | return ira->codegen->builtin_types.entry_invalid; | |
| 17072 | buf_ptr(&container_type->name), buf_ptr(field_name))); | |
| 17073 | return nullptr; | |
| 17042 | 17074 | } |
| 17043 | 17075 | |
| 17044 | 17076 | if (!type_has_bits(field->type_entry)) { |
| 17045 | 17077 | ir_add_error(ira, field_name_value, |
| 17046 | buf_sprintf("zero-bit field '%s' in struct '%s' has no offset", | |
| 17047 | buf_ptr(field_name), buf_ptr(&container_type->name))); | |
| 17048 | return ira->codegen->builtin_types.entry_invalid; | |
| 17078 | buf_sprintf("zero-bit field '%s' in struct '%s' has no offset", | |
| 17079 | buf_ptr(field_name), buf_ptr(&container_type->name))); | |
| 17080 | return nullptr; | |
| 17049 | 17081 | } |
| 17050 | size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index); | |
| 17082 | ||
| 17083 | *byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, container_type->type_ref, field->gen_index); | |
| 17084 | return field; | |
| 17085 | } | |
| 17086 | ||
| 17087 | static ZigType *ir_analyze_instruction_byte_offset_of(IrAnalyze *ira, | |
| 17088 | IrInstructionByteOffsetOf *instruction) | |
| 17089 | { | |
| 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 | ||
| 17094 | IrInstruction *field_name_value = instruction->field_name->other; | |
| 17095 | size_t byte_offset = 0; | |
| 17096 | if (!validate_byte_offset(ira, type_value, field_name_value, &byte_offset)) | |
| 17097 | return ira->codegen->builtin_types.entry_invalid; | |
| 17098 | ||
| 17099 | ||
| 17051 | 17100 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 17052 | 17101 | bigint_init_unsigned(&out_val->data.x_bigint, byte_offset); |
| 17053 | 17102 | return ira->codegen->builtin_types.entry_num_lit_int; |
| 17054 | 17103 | } |
| 17055 | 17104 | |
| 17105 | static ZigType *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, | |
| 17106 | IrInstructionBitOffsetOf *instruction) | |
| 17107 | { | |
| 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; | |
| 17111 | IrInstruction *field_name_value = instruction->field_name->other; | |
| 17112 | size_t byte_offset = 0; | |
| 17113 | TypeStructField *field = nullptr; | |
| 17114 | if (!(field = validate_byte_offset(ira, type_value, field_name_value, &byte_offset))) | |
| 17115 | return ira->codegen->builtin_types.entry_invalid; | |
| 17116 | ||
| 17117 | size_t bit_offset = byte_offset * 8 + field->packed_bits_offset; | |
| 17118 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 17119 | bigint_init_unsigned(&out_val->data.x_bigint, bit_offset); | |
| 17120 | return ira->codegen->builtin_types.entry_num_lit_int; | |
| 17121 | } | |
| 17122 | ||
| 17056 | 17123 | static void ensure_field_index(ZigType *type, const char *field_name, size_t index) |
| 17057 | 17124 | { |
| 17058 | 17125 | Buf *field_name_buf; |
| ... | ... | @@ -21550,8 +21617,10 @@ static ZigType *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *ins |
| 21550 | 21617 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction); |
| 21551 | 21618 | case IrInstructionIdFieldParentPtr: |
| 21552 | 21619 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); |
| 21553 | case IrInstructionIdOffsetOf: | |
| 21554 | return ir_analyze_instruction_offset_of(ira, (IrInstructionOffsetOf *)instruction); | |
| 21620 | case IrInstructionIdByteOffsetOf: | |
| 21621 | return ir_analyze_instruction_byte_offset_of(ira, (IrInstructionByteOffsetOf *)instruction); | |
| 21622 | case IrInstructionIdBitOffsetOf: | |
| 21623 | return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); | |
| 21555 | 21624 | case IrInstructionIdTypeInfo: |
| 21556 | 21625 | return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); |
| 21557 | 21626 | case IrInstructionIdTypeId: |
| ... | ... | @@ -21835,7 +21904,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 21835 | 21904 | case IrInstructionIdTypeName: |
| 21836 | 21905 | case IrInstructionIdTagName: |
| 21837 | 21906 | case IrInstructionIdFieldParentPtr: |
| 21838 | case IrInstructionIdOffsetOf: | |
| 21907 | case IrInstructionIdByteOffsetOf: | |
| 21908 | case IrInstructionIdBitOffsetOf: | |
| 21839 | 21909 | case IrInstructionIdTypeInfo: |
| 21840 | 21910 | case IrInstructionIdTypeId: |
| 21841 | 21911 | case IrInstructionIdAlignCast: |
src/ir_print.cpp+15-4| ... | ... | @@ -1041,8 +1041,16 @@ static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr |
| 1041 | 1041 | fprintf(irp->f, ")"); |
| 1042 | 1042 | } |
| 1043 | 1043 | |
| 1044 | static void ir_print_offset_of(IrPrint *irp, IrInstructionOffsetOf *instruction) { | |
| 1045 | fprintf(irp->f, "@offset_of("); | |
| 1044 | static void ir_print_byte_offset_of(IrPrint *irp, IrInstructionByteOffsetOf *instruction) { | |
| 1045 | fprintf(irp->f, "@byte_offset_of("); | |
| 1046 | ir_print_other_instruction(irp, instruction->type_value); | |
| 1047 | fprintf(irp->f, ","); | |
| 1048 | ir_print_other_instruction(irp, instruction->field_name); | |
| 1049 | fprintf(irp->f, ")"); | |
| 1050 | } | |
| 1051 | ||
| 1052 | static void ir_print_bit_offset_of(IrPrint *irp, IrInstructionBitOffsetOf *instruction) { | |
| 1053 | fprintf(irp->f, "@bit_offset_of("); | |
| 1046 | 1054 | ir_print_other_instruction(irp, instruction->type_value); |
| 1047 | 1055 | fprintf(irp->f, ","); |
| 1048 | 1056 | ir_print_other_instruction(irp, instruction->field_name); |
| ... | ... | @@ -1649,8 +1657,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1649 | 1657 | case IrInstructionIdFieldParentPtr: |
| 1650 | 1658 | ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction); |
| 1651 | 1659 | break; |
| 1652 | case IrInstructionIdOffsetOf: | |
| 1653 | ir_print_offset_of(irp, (IrInstructionOffsetOf *)instruction); | |
| 1660 | case IrInstructionIdByteOffsetOf: | |
| 1661 | ir_print_byte_offset_of(irp, (IrInstructionByteOffsetOf *)instruction); | |
| 1662 | break; | |
| 1663 | case IrInstructionIdBitOffsetOf: | |
| 1664 | ir_print_bit_offset_of(irp, (IrInstructionBitOffsetOf *)instruction); | |
| 1654 | 1665 | break; |
| 1655 | 1666 | case IrInstructionIdTypeInfo: |
| 1656 | 1667 | ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); |
std/c/darwin.zig+13-13| ... | ... | @@ -158,12 +158,12 @@ const std = @import("../index.zig"); |
| 158 | 158 | const assert = std.debug.assert; |
| 159 | 159 | |
| 160 | 160 | comptime { |
| 161 | assert(@offsetOf(Kevent, "ident") == 0); | |
| 162 | assert(@offsetOf(Kevent, "filter") == 8); | |
| 163 | assert(@offsetOf(Kevent, "flags") == 10); | |
| 164 | assert(@offsetOf(Kevent, "fflags") == 12); | |
| 165 | assert(@offsetOf(Kevent, "data") == 16); | |
| 166 | assert(@offsetOf(Kevent, "udata") == 24); | |
| 161 | assert(@byteOffsetOf(Kevent, "ident") == 0); | |
| 162 | assert(@byteOffsetOf(Kevent, "filter") == 8); | |
| 163 | assert(@byteOffsetOf(Kevent, "flags") == 10); | |
| 164 | assert(@byteOffsetOf(Kevent, "fflags") == 12); | |
| 165 | assert(@byteOffsetOf(Kevent, "data") == 16); | |
| 166 | assert(@byteOffsetOf(Kevent, "udata") == 24); | |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | 169 | pub const kevent64_s = extern struct { |
| ... | ... | @@ -180,11 +180,11 @@ pub const kevent64_s = extern struct { |
| 180 | 180 | // to make sure the struct is laid out the same. These values were |
| 181 | 181 | // produced from C code using the offsetof macro. |
| 182 | 182 | comptime { |
| 183 | assert(@offsetOf(kevent64_s, "ident") == 0); | |
| 184 | assert(@offsetOf(kevent64_s, "filter") == 8); | |
| 185 | assert(@offsetOf(kevent64_s, "flags") == 10); | |
| 186 | assert(@offsetOf(kevent64_s, "fflags") == 12); | |
| 187 | assert(@offsetOf(kevent64_s, "data") == 16); | |
| 188 | assert(@offsetOf(kevent64_s, "udata") == 24); | |
| 189 | assert(@offsetOf(kevent64_s, "ext") == 32); | |
| 183 | assert(@byteOffsetOf(kevent64_s, "ident") == 0); | |
| 184 | assert(@byteOffsetOf(kevent64_s, "filter") == 8); | |
| 185 | assert(@byteOffsetOf(kevent64_s, "flags") == 10); | |
| 186 | assert(@byteOffsetOf(kevent64_s, "fflags") == 12); | |
| 187 | assert(@byteOffsetOf(kevent64_s, "data") == 16); | |
| 188 | assert(@byteOffsetOf(kevent64_s, "udata") == 24); | |
| 189 | assert(@byteOffsetOf(kevent64_s, "ext") == 32); | |
| 190 | 190 | } |
test/cases/sizeof_and_typeof.zig+46-11| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const assert = @import("std").debug.assert; |
| 2 | 3 | |
| 3 | test "sizeofAndTypeOf" { | |
| 4 | test "@sizeOf and @typeOf" { | |
| 4 | 5 | const y: @typeOf(x) = 120; |
| 5 | 6 | assert(@sizeOf(@typeOf(y)) == 2); |
| 6 | 7 | } |
| ... | ... | @@ -11,24 +12,58 @@ const A = struct { |
| 11 | 12 | a: u8, |
| 12 | 13 | b: u32, |
| 13 | 14 | c: u8, |
| 15 | d: u3, | |
| 16 | e: u5, | |
| 17 | f: u16, | |
| 18 | g: u16, | |
| 14 | 19 | }; |
| 15 | 20 | |
| 16 | 21 | const P = packed struct { |
| 17 | 22 | a: u8, |
| 18 | 23 | b: u32, |
| 19 | 24 | c: u8, |
| 25 | d: u3, | |
| 26 | e: u5, | |
| 27 | f: u16, | |
| 28 | g: u16, | |
| 20 | 29 | }; |
| 21 | 30 | |
| 22 | test "offsetOf" { | |
| 31 | test "@byteOffsetOf" { | |
| 23 | 32 | // Packed structs have fixed memory layout |
| 24 | const p: P = undefined; | |
| 25 | assert(@offsetOf(P, "a") == 0); | |
| 26 | assert(@offsetOf(@typeOf(p), "b") == 1); | |
| 27 | assert(@offsetOf(@typeOf(p), "c") == 5); | |
| 33 | assert(@byteOffsetOf(P, "a") == 0); | |
| 34 | assert(@byteOffsetOf(P, "b") == 1); | |
| 35 | assert(@byteOffsetOf(P, "c") == 5); | |
| 36 | assert(@byteOffsetOf(P, "d") == 6); | |
| 37 | assert(@byteOffsetOf(P, "e") == 6); | |
| 38 | assert(@byteOffsetOf(P, "f") == 7); | |
| 39 | assert(@byteOffsetOf(P, "g") == 9); | |
| 28 | 40 | |
| 29 | // Non-packed struct fields can be moved/padded | |
| 30 | const a: A = undefined; | |
| 31 | assert(@ptrToInt(&a.a) - @ptrToInt(&a) == @offsetOf(A, "a")); | |
| 32 | assert(@ptrToInt(&a.b) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "b")); | |
| 33 | assert(@ptrToInt(&a.c) - @ptrToInt(&a) == @offsetOf(@typeOf(a), "c")); | |
| 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")); | |
| 50 | } | |
| 51 | ||
| 52 | test "@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")); | |
| 34 | 69 | } |
test/compile_errors.zig+21-9| ... | ... | @@ -3763,25 +3763,25 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3763 | 3763 | ); |
| 3764 | 3764 | |
| 3765 | 3765 | cases.add( |
| 3766 | "@offsetOf - non struct", | |
| 3766 | "@byteOffsetOf - non struct", | |
| 3767 | 3767 | \\const Foo = i32; |
| 3768 | 3768 | \\export fn foo() usize { |
| 3769 | \\ return @offsetOf(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 | ); |
| 3774 | 3774 | |
| 3775 | 3775 | cases.add( |
| 3776 | "@offsetOf - bad field name", | |
| 3776 | "@byteOffsetOf - bad field name", | |
| 3777 | 3777 | \\const Foo = struct { |
| 3778 | 3778 | \\ derp: i32, |
| 3779 | 3779 | \\}; |
| 3780 | 3780 | \\export fn foo() usize { |
| 3781 | \\ return @offsetOf(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 | ); |
| 3786 | 3786 | |
| 3787 | 3787 | cases.addExe( |
| ... | ... | @@ -5084,15 +5084,27 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5084 | 5084 | ); |
| 5085 | 5085 | |
| 5086 | 5086 | cases.add( |
| 5087 | "taking offset of void field in struct", | |
| 5087 | "taking byte offset of void field in struct", | |
| 5088 | 5088 | \\const Empty = struct { |
| 5089 | 5089 | \\ val: void, |
| 5090 | 5090 | \\}; |
| 5091 | 5091 | \\export fn foo() void { |
| 5092 | \\ const fieldOffset = @offsetOf(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 | ); | |
| 5097 | ||
| 5098 | cases.add( | |
| 5099 | "taking bit offset of void field in struct", | |
| 5100 | \\const Empty = struct { | |
| 5101 | \\ val: void, | |
| 5102 | \\}; | |
| 5103 | \\export fn foo() void { | |
| 5104 | \\ const fieldOffset = @bitOffsetOf(Empty, "val",); | |
| 5105 | \\} | |
| 5106 | , | |
| 5107 | ".tmp_source.zig:5:45: error: zero-bit field 'val' in struct 'Empty' has no offset", | |
| 5096 | 5108 | ); |
| 5097 | 5109 | |
| 5098 | 5110 | cases.add( |