| author | |
| committer | |
| log | a791417552f200911e534aebe312ab3c527b1a2b |
| tree | 365c97b3f139de892893427ea14e34c8045eb2f9 |
| parent | 407916cd2f3f4931de29fd87b8c9ae3faeba8452 |
closes #32010 files changed, 295 insertions(+), 21 deletions(-)
doc/langref.md+4| ... | ... | @@ -630,3 +630,7 @@ Converts an integer to a pointer. To convert the other way, use `usize(ptr)`. |
| 630 | 630 | ### @enumTagName(value: var) -> []const u8 |
| 631 | 631 | |
| 632 | 632 | Converts an enum tag name to a slice of bytes. Example: |
| 633 | ||
| 634 | ### @fieldParentPtr(comptime ParentType: type, comptime field_name: []const u8, field_ptr: &T) -> &ParentType | |
| 635 | ||
| 636 | Given a pointer to a field, returns the base pointer of a struct. |
src/all_types.hpp+11| ... | ... | @@ -1189,6 +1189,7 @@ enum BuiltinFnId { |
| 1189 | 1189 | BuiltinFnIdPtrCast, |
| 1190 | 1190 | BuiltinFnIdIntToPtr, |
| 1191 | 1191 | BuiltinFnIdEnumTagName, |
| 1192 | BuiltinFnIdFieldParentPtr, | |
| 1192 | 1193 | }; |
| 1193 | 1194 | |
| 1194 | 1195 | struct BuiltinFnEntry { |
| ... | ... | @@ -1736,6 +1737,7 @@ enum IrInstructionId { |
| 1736 | 1737 | IrInstructionIdPanic, |
| 1737 | 1738 | IrInstructionIdEnumTagName, |
| 1738 | 1739 | IrInstructionIdSetFnRefInline, |
| 1740 | IrInstructionIdFieldParentPtr, | |
| 1739 | 1741 | }; |
| 1740 | 1742 | |
| 1741 | 1743 | struct IrInstruction { |
| ... | ... | @@ -2488,6 +2490,15 @@ struct IrInstructionSetFnRefInline { |
| 2488 | 2490 | IrInstruction *fn_ref; |
| 2489 | 2491 | }; |
| 2490 | 2492 | |
| 2493 | struct IrInstructionFieldParentPtr { | |
| 2494 | IrInstruction base; | |
| 2495 | ||
| 2496 | IrInstruction *type_value; | |
| 2497 | IrInstruction *field_name; | |
| 2498 | IrInstruction *field_ptr; | |
| 2499 | TypeStructField *field; | |
| 2500 | }; | |
| 2501 | ||
| 2491 | 2502 | static const size_t slice_ptr_index = 0; |
| 2492 | 2503 | static const size_t slice_len_index = 1; |
| 2493 | 2504 |
src/codegen.cpp+31| ... | ... | @@ -2261,6 +2261,34 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable |
| 2261 | 2261 | return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); |
| 2262 | 2262 | } |
| 2263 | 2263 | |
| 2264 | static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable, | |
| 2265 | IrInstructionFieldParentPtr *instruction) | |
| 2266 | { | |
| 2267 | TypeTableEntry *container_ptr_type = instruction->base.value.type; | |
| 2268 | assert(container_ptr_type->id == TypeTableEntryIdPointer); | |
| 2269 | ||
| 2270 | TypeTableEntry *container_type = container_ptr_type->data.pointer.child_type; | |
| 2271 | ||
| 2272 | size_t byte_offset = LLVMOffsetOfElement(g->target_data_ref, | |
| 2273 | container_type->type_ref, instruction->field->gen_index); | |
| 2274 | ||
| 2275 | LLVMValueRef field_ptr_val = ir_llvm_value(g, instruction->field_ptr); | |
| 2276 | ||
| 2277 | if (byte_offset == 0) { | |
| 2278 | return LLVMBuildBitCast(g->builder, field_ptr_val, container_ptr_type->type_ref, ""); | |
| 2279 | } else { | |
| 2280 | TypeTableEntry *usize = g->builtin_types.entry_usize; | |
| 2281 | ||
| 2282 | LLVMValueRef field_ptr_int = LLVMBuildPtrToInt(g->builder, field_ptr_val, | |
| 2283 | usize->type_ref, ""); | |
| 2284 | ||
| 2285 | LLVMValueRef base_ptr_int = LLVMBuildNUWSub(g->builder, field_ptr_int, | |
| 2286 | LLVMConstInt(usize->type_ref, byte_offset, false), ""); | |
| 2287 | ||
| 2288 | return LLVMBuildIntToPtr(g->builder, base_ptr_int, container_ptr_type->type_ref, ""); | |
| 2289 | } | |
| 2290 | } | |
| 2291 | ||
| 2264 | 2292 | |
| 2265 | 2293 | static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { |
| 2266 | 2294 | switch (atomic_order) { |
| ... | ... | @@ -2963,6 +2991,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2963 | 2991 | return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); |
| 2964 | 2992 | case IrInstructionIdEnumTagName: |
| 2965 | 2993 | return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction); |
| 2994 | case IrInstructionIdFieldParentPtr: | |
| 2995 | return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction); | |
| 2966 | 2996 | } |
| 2967 | 2997 | zig_unreachable(); |
| 2968 | 2998 | } |
| ... | ... | @@ -4509,6 +4539,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4509 | 4539 | create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2); |
| 4510 | 4540 | create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); |
| 4511 | 4541 | create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); |
| 4542 | create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); | |
| 4512 | 4543 | } |
| 4513 | 4544 | |
| 4514 | 4545 | static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) { |
src/ir.cpp+137| ... | ... | @@ -549,6 +549,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnRefInline * |
| 549 | 549 | return IrInstructionIdSetFnRefInline; |
| 550 | 550 | } |
| 551 | 551 | |
| 552 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) { | |
| 553 | return IrInstructionIdFieldParentPtr; | |
| 554 | } | |
| 555 | ||
| 552 | 556 | template<typename T> |
| 553 | 557 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 554 | 558 | T *special_instruction = allocate<T>(1); |
| ... | ... | @@ -2162,6 +2166,23 @@ static IrInstruction *ir_build_set_fn_ref_inline(IrBuilder *irb, Scope *scope, A |
| 2162 | 2166 | return &instruction->base; |
| 2163 | 2167 | } |
| 2164 | 2168 | |
| 2169 | static IrInstruction *ir_build_field_parent_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2170 | IrInstruction *type_value, IrInstruction *field_name, IrInstruction *field_ptr, TypeStructField *field) | |
| 2171 | { | |
| 2172 | IrInstructionFieldParentPtr *instruction = ir_build_instruction<IrInstructionFieldParentPtr>( | |
| 2173 | irb, scope, source_node); | |
| 2174 | instruction->type_value = type_value; | |
| 2175 | instruction->field_name = field_name; | |
| 2176 | instruction->field_ptr = field_ptr; | |
| 2177 | instruction->field = field; | |
| 2178 | ||
| 2179 | ir_ref_instruction(type_value, irb->current_basic_block); | |
| 2180 | ir_ref_instruction(field_name, irb->current_basic_block); | |
| 2181 | ir_ref_instruction(field_ptr, irb->current_basic_block); | |
| 2182 | ||
| 2183 | return &instruction->base; | |
| 2184 | } | |
| 2185 | ||
| 2165 | 2186 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2166 | 2187 | return nullptr; |
| 2167 | 2188 | } |
| ... | ... | @@ -2833,6 +2854,15 @@ static IrInstruction *ir_instruction_setfnrefinline_get_dep(IrInstructionSetFnRe |
| 2833 | 2854 | } |
| 2834 | 2855 | } |
| 2835 | 2856 | |
| 2857 | static IrInstruction *ir_instruction_fieldparentptr_get_dep(IrInstructionFieldParentPtr *instruction, size_t index) { | |
| 2858 | switch (index) { | |
| 2859 | case 0: return instruction->type_value; | |
| 2860 | case 1: return instruction->field_name; | |
| 2861 | case 2: return instruction->field_ptr; | |
| 2862 | default: return nullptr; | |
| 2863 | } | |
| 2864 | } | |
| 2865 | ||
| 2836 | 2866 | |
| 2837 | 2867 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2838 | 2868 | switch (instruction->id) { |
| ... | ... | @@ -3026,6 +3056,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3026 | 3056 | return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); |
| 3027 | 3057 | case IrInstructionIdSetFnRefInline: |
| 3028 | 3058 | return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index); |
| 3059 | case IrInstructionIdFieldParentPtr: | |
| 3060 | return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index); | |
| 3029 | 3061 | } |
| 3030 | 3062 | zig_unreachable(); |
| 3031 | 3063 | } |
| ... | ... | @@ -4333,6 +4365,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4333 | 4365 | IrInstruction *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value); |
| 4334 | 4366 | return ir_build_enum_tag_name(irb, scope, node, actual_tag); |
| 4335 | 4367 | } |
| 4368 | case BuiltinFnIdFieldParentPtr: | |
| 4369 | { | |
| 4370 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4371 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4372 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4373 | return arg0_value; | |
| 4374 | ||
| 4375 | AstNode *arg1_node = node->data.fn_call_expr.params.at(1); | |
| 4376 | IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); | |
| 4377 | if (arg1_value == irb->codegen->invalid_instruction) | |
| 4378 | return arg1_value; | |
| 4379 | ||
| 4380 | AstNode *arg2_node = node->data.fn_call_expr.params.at(2); | |
| 4381 | IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); | |
| 4382 | if (arg2_value == irb->codegen->invalid_instruction) | |
| 4383 | return arg2_value; | |
| 4384 | ||
| 4385 | return ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); | |
| 4386 | } | |
| 4336 | 4387 | } |
| 4337 | 4388 | zig_unreachable(); |
| 4338 | 4389 | } |
| ... | ... | @@ -11263,6 +11314,89 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_ref_inline(IrAnalyze *ira, |
| 11263 | 11314 | } |
| 11264 | 11315 | } |
| 11265 | 11316 | |
| 11317 | static TypeTableEntry *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, | |
| 11318 | IrInstructionFieldParentPtr *instruction) | |
| 11319 | { | |
| 11320 | IrInstruction *type_value = instruction->type_value->other; | |
| 11321 | TypeTableEntry *container_type = ir_resolve_type(ira, type_value); | |
| 11322 | if (type_is_invalid(container_type)) | |
| 11323 | return ira->codegen->builtin_types.entry_invalid; | |
| 11324 | ||
| 11325 | IrInstruction *field_name_value = instruction->field_name->other; | |
| 11326 | Buf *field_name = ir_resolve_str(ira, field_name_value); | |
| 11327 | if (!field_name) | |
| 11328 | return ira->codegen->builtin_types.entry_invalid; | |
| 11329 | ||
| 11330 | IrInstruction *field_ptr = instruction->field_ptr->other; | |
| 11331 | if (type_is_invalid(field_ptr->value.type)) | |
| 11332 | return ira->codegen->builtin_types.entry_invalid; | |
| 11333 | ||
| 11334 | if (container_type->id != TypeTableEntryIdStruct) { | |
| 11335 | ir_add_error(ira, type_value, | |
| 11336 | buf_sprintf("expected struct type, found '%s'", buf_ptr(&container_type->name))); | |
| 11337 | return ira->codegen->builtin_types.entry_invalid; | |
| 11338 | } | |
| 11339 | ||
| 11340 | ensure_complete_type(ira->codegen, container_type); | |
| 11341 | ||
| 11342 | TypeStructField *field = find_struct_type_field(container_type, field_name); | |
| 11343 | if (field == nullptr) { | |
| 11344 | ir_add_error(ira, field_name_value, | |
| 11345 | buf_sprintf("struct '%s' has no field '%s'", | |
| 11346 | buf_ptr(&container_type->name), buf_ptr(field_name))); | |
| 11347 | return ira->codegen->builtin_types.entry_invalid; | |
| 11348 | } | |
| 11349 | ||
| 11350 | if (field_ptr->value.type->id != TypeTableEntryIdPointer) { | |
| 11351 | ir_add_error(ira, field_ptr, | |
| 11352 | buf_sprintf("expected pointer, found '%s'", buf_ptr(&field_ptr->value.type->name))); | |
| 11353 | return ira->codegen->builtin_types.entry_invalid; | |
| 11354 | } | |
| 11355 | ||
| 11356 | TypeTableEntry *field_ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, | |
| 11357 | field_ptr->value.type->data.pointer.is_const, | |
| 11358 | field_ptr->value.type->data.pointer.is_volatile, 0, 0); | |
| 11359 | IrInstruction *casted_field_ptr = ir_implicit_cast(ira, field_ptr, field_ptr_type); | |
| 11360 | if (type_is_invalid(casted_field_ptr->value.type)) | |
| 11361 | return ira->codegen->builtin_types.entry_invalid; | |
| 11362 | ||
| 11363 | TypeTableEntry *result_type = get_pointer_to_type_extra(ira->codegen, container_type, | |
| 11364 | casted_field_ptr->value.type->data.pointer.is_const, | |
| 11365 | casted_field_ptr->value.type->data.pointer.is_volatile, 0, 0); | |
| 11366 | ||
| 11367 | if (instr_is_comptime(casted_field_ptr)) { | |
| 11368 | ConstExprValue *field_ptr_val = ir_resolve_const(ira, casted_field_ptr, UndefBad); | |
| 11369 | if (!field_ptr_val) | |
| 11370 | return ira->codegen->builtin_types.entry_invalid; | |
| 11371 | ||
| 11372 | if (field_ptr_val->data.x_ptr.special != ConstPtrSpecialBaseStruct) { | |
| 11373 | ir_add_error(ira, field_ptr, buf_sprintf("pointer value not based on parent struct")); | |
| 11374 | return ira->codegen->builtin_types.entry_invalid; | |
| 11375 | } | |
| 11376 | ||
| 11377 | size_t ptr_field_index = field_ptr_val->data.x_ptr.data.base_struct.field_index; | |
| 11378 | if (ptr_field_index != field->src_index) { | |
| 11379 | ir_add_error(ira, &instruction->base, | |
| 11380 | buf_sprintf("field '%s' has index %zu but pointer value is index %zu of struct '%s'", | |
| 11381 | buf_ptr(field->name), field->src_index, | |
| 11382 | ptr_field_index, buf_ptr(&container_type->name))); | |
| 11383 | return ira->codegen->builtin_types.entry_invalid; | |
| 11384 | } | |
| 11385 | ||
| 11386 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 11387 | out_val->data.x_ptr.special = ConstPtrSpecialRef; | |
| 11388 | out_val->data.x_ptr.data.ref.pointee = field_ptr_val->data.x_ptr.data.base_struct.struct_val; | |
| 11389 | out_val->data.x_ptr.mut = field_ptr_val->data.x_ptr.mut; | |
| 11390 | ||
| 11391 | return result_type; | |
| 11392 | } | |
| 11393 | ||
| 11394 | IrInstruction *result = ir_build_field_parent_ptr(&ira->new_irb, instruction->base.scope, | |
| 11395 | instruction->base.source_node, type_value, field_name_value, casted_field_ptr, field); | |
| 11396 | ir_link_new_instruction(result, &instruction->base); | |
| 11397 | return result_type; | |
| 11398 | } | |
| 11399 | ||
| 11266 | 11400 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { |
| 11267 | 11401 | IrInstruction *type_value = instruction->type_value->other; |
| 11268 | 11402 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| ... | ... | @@ -12781,6 +12915,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 12781 | 12915 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); |
| 12782 | 12916 | case IrInstructionIdSetFnRefInline: |
| 12783 | 12917 | return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction); |
| 12918 | case IrInstructionIdFieldParentPtr: | |
| 12919 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); | |
| 12784 | 12920 | case IrInstructionIdMaybeWrap: |
| 12785 | 12921 | case IrInstructionIdErrWrapCode: |
| 12786 | 12922 | case IrInstructionIdErrWrapPayload: |
| ... | ... | @@ -12964,6 +13100,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 12964 | 13100 | case IrInstructionIdTypeName: |
| 12965 | 13101 | case IrInstructionIdEnumTagName: |
| 12966 | 13102 | case IrInstructionIdSetFnRefInline: |
| 13103 | case IrInstructionIdFieldParentPtr: | |
| 12967 | 13104 | return false; |
| 12968 | 13105 | case IrInstructionIdAsm: |
| 12969 | 13106 | { |
src/ir_print.cpp+13| ... | ... | @@ -875,6 +875,16 @@ static void ir_print_set_fn_ref_inline(IrPrint *irp, IrInstructionSetFnRefInline |
| 875 | 875 | ir_print_other_instruction(irp, instruction->fn_ref); |
| 876 | 876 | } |
| 877 | 877 | |
| 878 | static void ir_print_field_parent_ptr(IrPrint *irp, IrInstructionFieldParentPtr *instruction) { | |
| 879 | fprintf(irp->f, "@fieldParentPtr("); | |
| 880 | ir_print_other_instruction(irp, instruction->type_value); | |
| 881 | fprintf(irp->f, ","); | |
| 882 | ir_print_other_instruction(irp, instruction->field_name); | |
| 883 | fprintf(irp->f, ","); | |
| 884 | ir_print_other_instruction(irp, instruction->field_ptr); | |
| 885 | fprintf(irp->f, ")"); | |
| 886 | } | |
| 887 | ||
| 878 | 888 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 879 | 889 | ir_print_prefix(irp, instruction); |
| 880 | 890 | switch (instruction->id) { |
| ... | ... | @@ -1162,6 +1172,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1162 | 1172 | case IrInstructionIdSetFnRefInline: |
| 1163 | 1173 | ir_print_set_fn_ref_inline(irp, (IrInstructionSetFnRefInline *)instruction); |
| 1164 | 1174 | break; |
| 1175 | case IrInstructionIdFieldParentPtr: | |
| 1176 | ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction); | |
| 1177 | break; | |
| 1165 | 1178 | } |
| 1166 | 1179 | fprintf(irp->f, "\n"); |
| 1167 | 1180 | } |
std/build.zig+6-18| ... | ... | @@ -580,9 +580,7 @@ const Exe = struct { |
| 580 | 580 | } |
| 581 | 581 | |
| 582 | 582 | fn make(step: &Step) -> %void { |
| 583 | // TODO issue #320 | |
| 584 | //const self = @fieldParentPtr(Exe, "step", step); | |
| 585 | const exe = @ptrcast(&Exe, step); | |
| 583 | const exe = @fieldParentPtr(Exe, "step", step); | |
| 586 | 584 | const builder = exe.builder; |
| 587 | 585 | |
| 588 | 586 | var zig_args = List([]const u8).init(builder.allocator); |
| ... | ... | @@ -754,9 +752,7 @@ const CLibrary = struct { |
| 754 | 752 | } |
| 755 | 753 | |
| 756 | 754 | fn make(step: &Step) -> %void { |
| 757 | // TODO issue #320 | |
| 758 | //const self = @fieldParentPtr(CLibrary, "step", step); | |
| 759 | const self = @ptrcast(&CLibrary, step); | |
| 755 | const self = @fieldParentPtr(CLibrary, "step", step); | |
| 760 | 756 | const cc = os.getEnv("CC") ?? "cc"; |
| 761 | 757 | const builder = self.builder; |
| 762 | 758 | |
| ... | ... | @@ -897,9 +893,7 @@ const CExecutable = struct { |
| 897 | 893 | } |
| 898 | 894 | |
| 899 | 895 | fn make(step: &Step) -> %void { |
| 900 | // TODO issue #320 | |
| 901 | //const self = @fieldParentPtr(CExecutable, "step", step); | |
| 902 | const self = @ptrcast(&CExecutable, step); | |
| 896 | const self = @fieldParentPtr(CExecutable, "step", step); | |
| 903 | 897 | const cc = os.getEnv("CC") ?? "cc"; |
| 904 | 898 | const builder = self.builder; |
| 905 | 899 | |
| ... | ... | @@ -987,9 +981,7 @@ const CommandStep = struct { |
| 987 | 981 | } |
| 988 | 982 | |
| 989 | 983 | fn make(step: &Step) -> %void { |
| 990 | // TODO issue #320 | |
| 991 | //const self = @fieldParentPtr(CExecutable, "step", step); | |
| 992 | const self = @ptrcast(&CommandStep, step); | |
| 984 | const self = @fieldParentPtr(CommandStep, "step", step); | |
| 993 | 985 | |
| 994 | 986 | // TODO set cwd |
| 995 | 987 | self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args); |
| ... | ... | @@ -1021,9 +1013,7 @@ const InstallCLibraryStep = struct { |
| 1021 | 1013 | } |
| 1022 | 1014 | |
| 1023 | 1015 | fn make(step: &Step) -> %void { |
| 1024 | // TODO issue #320 | |
| 1025 | //const self = @fieldParentPtr(InstallCLibraryStep, "step", step); | |
| 1026 | const self = @ptrcast(&InstallCLibraryStep, step); | |
| 1016 | const self = @fieldParentPtr(InstallCLibraryStep, "step", step); | |
| 1027 | 1017 | |
| 1028 | 1018 | self.builder.copyFile(self.lib.out_filename, self.dest_file); |
| 1029 | 1019 | if (!self.lib.static) { |
| ... | ... | @@ -1051,9 +1041,7 @@ const InstallFileStep = struct { |
| 1051 | 1041 | } |
| 1052 | 1042 | |
| 1053 | 1043 | fn make(step: &Step) -> %void { |
| 1054 | // TODO issue #320 | |
| 1055 | //const self = @fieldParentPtr(InstallFileStep, "step", step); | |
| 1056 | const self = @ptrcast(&InstallFileStep, step); | |
| 1044 | const self = @fieldParentPtr(InstallFileStep, "step", step); | |
| 1057 | 1045 | |
| 1058 | 1046 | debug.panic("TODO install file"); |
| 1059 | 1047 | } |
std/mem.zig+1-3| ... | ... | @@ -76,9 +76,7 @@ pub const IncrementingAllocator = struct { |
| 76 | 76 | } |
| 77 | 77 | |
| 78 | 78 | fn alloc(allocator: &Allocator, n: usize) -> %[]u8 { |
| 79 | // TODO issue #320 | |
| 80 | //const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); | |
| 81 | const self = @ptrcast(&IncrementingAllocator, allocator); | |
| 79 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); | |
| 82 | 80 | const new_end_index = self.end_index + n; |
| 83 | 81 | if (new_end_index > self.bytes.len) { |
| 84 | 82 | return error.NoMem; |
test/cases/field_parent_ptr.zig created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | const assert = @import("std").debug.assert; | |
| 2 | ||
| 3 | test "@fieldParentPtr non-first field" { | |
| 4 | testParentFieldPtr(&foo.c); | |
| 5 | comptime testParentFieldPtr(&foo.c); | |
| 6 | } | |
| 7 | ||
| 8 | test "@fieldParentPtr first field" { | |
| 9 | testParentFieldPtrFirst(&foo.a); | |
| 10 | comptime testParentFieldPtrFirst(&foo.a); | |
| 11 | } | |
| 12 | ||
| 13 | const Foo = struct { | |
| 14 | a: bool, | |
| 15 | b: f32, | |
| 16 | c: i32, | |
| 17 | d: i32, | |
| 18 | }; | |
| 19 | ||
| 20 | const foo = Foo { | |
| 21 | .a = true, | |
| 22 | .b = 0.123, | |
| 23 | .c = 1234, | |
| 24 | .d = -10, | |
| 25 | }; | |
| 26 | ||
| 27 | fn testParentFieldPtr(c: &const i32) { | |
| 28 | assert(c == &foo.c); | |
| 29 | ||
| 30 | const base = @fieldParentPtr(Foo, "c", c); | |
| 31 | assert(base == &foo); | |
| 32 | assert(&base.c == c); | |
| 33 | } | |
| 34 | ||
| 35 | fn testParentFieldPtrFirst(a: &const bool) { | |
| 36 | assert(a == &foo.a); | |
| 37 | ||
| 38 | const base = @fieldParentPtr(Foo, "a", a); | |
| 39 | assert(base == &foo); | |
| 40 | assert(&base.a == a); | |
| 41 | } |
test/run_tests.cpp+50| ... | ... | @@ -1902,6 +1902,56 @@ export fn foo() { |
| 1902 | 1902 | var y: &void = @intToPtr(&void, x); |
| 1903 | 1903 | } |
| 1904 | 1904 | )SOURCE", 1, ".tmp_source.zig:4:31: error: type '&void' has 0 bits and cannot store information"); |
| 1905 | ||
| 1906 | add_compile_fail_case("@fieldParentPtr - non struct", R"SOURCE( | |
| 1907 | const Foo = i32; | |
| 1908 | export fn foo(a: &i32) -> &Foo { | |
| 1909 | return @fieldParentPtr(Foo, "a", a); | |
| 1910 | } | |
| 1911 | )SOURCE", 1, ".tmp_source.zig:4:28: error: expected struct type, found 'i32'"); | |
| 1912 | ||
| 1913 | add_compile_fail_case("@fieldParentPtr - bad field name", R"SOURCE( | |
| 1914 | const Foo = struct { | |
| 1915 | derp: i32, | |
| 1916 | }; | |
| 1917 | export fn foo(a: &i32) -> &Foo { | |
| 1918 | return @fieldParentPtr(Foo, "a", a); | |
| 1919 | } | |
| 1920 | )SOURCE", 1, ".tmp_source.zig:6:33: error: struct 'Foo' has no field 'a'"); | |
| 1921 | ||
| 1922 | add_compile_fail_case("@fieldParentPtr - field pointer is not pointer", R"SOURCE( | |
| 1923 | const Foo = struct { | |
| 1924 | a: i32, | |
| 1925 | }; | |
| 1926 | export fn foo(a: i32) -> &Foo { | |
| 1927 | return @fieldParentPtr(Foo, "a", a); | |
| 1928 | } | |
| 1929 | )SOURCE", 1, ".tmp_source.zig:6:38: error: expected pointer, found 'i32'"); | |
| 1930 | ||
| 1931 | add_compile_fail_case("@fieldParentPtr - comptime field ptr not based on struct", R"SOURCE( | |
| 1932 | const Foo = struct { | |
| 1933 | a: i32, | |
| 1934 | b: i32, | |
| 1935 | }; | |
| 1936 | const foo = Foo { .a = 1, .b = 2, }; | |
| 1937 | ||
| 1938 | comptime { | |
| 1939 | const field_ptr = @intToPtr(&i32, 0x1234); | |
| 1940 | const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr); | |
| 1941 | } | |
| 1942 | )SOURCE", 1, ".tmp_source.zig:10:55: error: pointer value not based on parent struct"); | |
| 1943 | ||
| 1944 | add_compile_fail_case("@fieldParentPtr - comptime wrong field index", R"SOURCE( | |
| 1945 | const Foo = struct { | |
| 1946 | a: i32, | |
| 1947 | b: i32, | |
| 1948 | }; | |
| 1949 | const foo = Foo { .a = 1, .b = 2, }; | |
| 1950 | ||
| 1951 | comptime { | |
| 1952 | const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a); | |
| 1953 | } | |
| 1954 | )SOURCE", 1, ".tmp_source.zig:9:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'"); | |
| 1905 | 1955 | } |
| 1906 | 1956 | |
| 1907 | 1957 | ////////////////////////////////////////////////////////////////////////////// |
test/self_hosted.zig+1| ... | ... | @@ -10,6 +10,7 @@ comptime { |
| 10 | 10 | _ = @import("cases/enum_with_members.zig"); |
| 11 | 11 | _ = @import("cases/error.zig"); |
| 12 | 12 | _ = @import("cases/eval.zig"); |
| 13 | _ = @import("cases/field_parent_ptr.zig"); | |
| 13 | 14 | _ = @import("cases/fn.zig"); |
| 14 | 15 | _ = @import("cases/for.zig"); |
| 15 | 16 | _ = @import("cases/generics.zig"); |