| 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,3 +630,7 @@ Converts an integer to a pointer. To convert the other way, use `usize(ptr)`. |
| 630 | ### @enumTagName(value: var) -> []const u8 | 630 | ### @enumTagName(value: var) -> []const u8 |
| 631 | 631 | ||
| 632 | Converts an enum tag name to a slice of bytes. Example: | 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,6 +1189,7 @@ enum BuiltinFnId { |
| 1189 | BuiltinFnIdPtrCast, | 1189 | BuiltinFnIdPtrCast, |
| 1190 | BuiltinFnIdIntToPtr, | 1190 | BuiltinFnIdIntToPtr, |
| 1191 | BuiltinFnIdEnumTagName, | 1191 | BuiltinFnIdEnumTagName, |
| 1192 | BuiltinFnIdFieldParentPtr, | ||
| 1192 | }; | 1193 | }; |
| 1193 | 1194 | ||
| 1194 | struct BuiltinFnEntry { | 1195 | struct BuiltinFnEntry { |
| ... | @@ -1736,6 +1737,7 @@ enum IrInstructionId { | ... | @@ -1736,6 +1737,7 @@ enum IrInstructionId { |
| 1736 | IrInstructionIdPanic, | 1737 | IrInstructionIdPanic, |
| 1737 | IrInstructionIdEnumTagName, | 1738 | IrInstructionIdEnumTagName, |
| 1738 | IrInstructionIdSetFnRefInline, | 1739 | IrInstructionIdSetFnRefInline, |
| 1740 | IrInstructionIdFieldParentPtr, | ||
| 1739 | }; | 1741 | }; |
| 1740 | 1742 | ||
| 1741 | struct IrInstruction { | 1743 | struct IrInstruction { |
| ... | @@ -2488,6 +2490,15 @@ struct IrInstructionSetFnRefInline { | ... | @@ -2488,6 +2490,15 @@ struct IrInstructionSetFnRefInline { |
| 2488 | IrInstruction *fn_ref; | 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 | static const size_t slice_ptr_index = 0; | 2502 | static const size_t slice_ptr_index = 0; |
| 2492 | static const size_t slice_len_index = 1; | 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,6 +2261,34 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable |
| 2261 | return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); | 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 | static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { | 2293 | static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { |
| 2266 | switch (atomic_order) { | 2294 | switch (atomic_order) { |
| ... | @@ -2963,6 +2991,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -2963,6 +2991,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 2963 | return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); | 2991 | return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); |
| 2964 | case IrInstructionIdEnumTagName: | 2992 | case IrInstructionIdEnumTagName: |
| 2965 | return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction); | 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 | zig_unreachable(); | 2997 | zig_unreachable(); |
| 2968 | } | 2998 | } |
| ... | @@ -4509,6 +4539,7 @@ static void define_builtin_fns(CodeGen *g) { | ... | @@ -4509,6 +4539,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 4509 | create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2); | 4539 | create_builtin_fn(g, BuiltinFnIdPtrCast, "ptrcast", 2); |
| 4510 | create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); | 4540 | create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); |
| 4511 | create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); | 4541 | create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); |
| 4542 | create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); | ||
| 4512 | } | 4543 | } |
| 4513 | 4544 | ||
| 4514 | static void add_compile_var(CodeGen *g, const char *name, ConstExprValue *value) { | 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,6 +549,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSetFnRefInline * |
| 549 | return IrInstructionIdSetFnRefInline; | 549 | return IrInstructionIdSetFnRefInline; |
| 550 | } | 550 | } |
| 551 | 551 | ||
| 552 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) { | ||
| 553 | return IrInstructionIdFieldParentPtr; | ||
| 554 | } | ||
| 555 | |||
| 552 | template<typename T> | 556 | template<typename T> |
| 553 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 557 | static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 554 | T *special_instruction = allocate<T>(1); | 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,6 +2166,23 @@ static IrInstruction *ir_build_set_fn_ref_inline(IrBuilder *irb, Scope *scope, A |
| 2162 | return &instruction->base; | 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 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { | 2186 | static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) { |
| 2166 | return nullptr; | 2187 | return nullptr; |
| 2167 | } | 2188 | } |
| ... | @@ -2833,6 +2854,15 @@ static IrInstruction *ir_instruction_setfnrefinline_get_dep(IrInstructionSetFnRe | ... | @@ -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 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { | 2867 | static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) { |
| 2838 | switch (instruction->id) { | 2868 | switch (instruction->id) { |
| ... | @@ -3026,6 +3056,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3026,6 +3056,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3026 | return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); | 3056 | return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); |
| 3027 | case IrInstructionIdSetFnRefInline: | 3057 | case IrInstructionIdSetFnRefInline: |
| 3028 | return ir_instruction_setfnrefinline_get_dep((IrInstructionSetFnRefInline *) instruction, index); | 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 | zig_unreachable(); | 3062 | zig_unreachable(); |
| 3031 | } | 3063 | } |
| ... | @@ -4333,6 +4365,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo | ... | @@ -4333,6 +4365,25 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4333 | IrInstruction *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value); | 4365 | IrInstruction *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value); |
| 4334 | return ir_build_enum_tag_name(irb, scope, node, actual_tag); | 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 | zig_unreachable(); | 4388 | zig_unreachable(); |
| 4338 | } | 4389 | } |
| ... | @@ -11263,6 +11314,89 @@ static TypeTableEntry *ir_analyze_instruction_set_fn_ref_inline(IrAnalyze *ira, | ... | @@ -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 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { | 11400 | static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) { |
| 11267 | IrInstruction *type_value = instruction->type_value->other; | 11401 | IrInstruction *type_value = instruction->type_value->other; |
| 11268 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); | 11402 | TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); |
| ... | @@ -12781,6 +12915,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -12781,6 +12915,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 12781 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); | 12915 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); |
| 12782 | case IrInstructionIdSetFnRefInline: | 12916 | case IrInstructionIdSetFnRefInline: |
| 12783 | return ir_analyze_instruction_set_fn_ref_inline(ira, (IrInstructionSetFnRefInline *)instruction); | 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 | case IrInstructionIdMaybeWrap: | 12920 | case IrInstructionIdMaybeWrap: |
| 12785 | case IrInstructionIdErrWrapCode: | 12921 | case IrInstructionIdErrWrapCode: |
| 12786 | case IrInstructionIdErrWrapPayload: | 12922 | case IrInstructionIdErrWrapPayload: |
| ... | @@ -12964,6 +13100,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -12964,6 +13100,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 12964 | case IrInstructionIdTypeName: | 13100 | case IrInstructionIdTypeName: |
| 12965 | case IrInstructionIdEnumTagName: | 13101 | case IrInstructionIdEnumTagName: |
| 12966 | case IrInstructionIdSetFnRefInline: | 13102 | case IrInstructionIdSetFnRefInline: |
| 13103 | case IrInstructionIdFieldParentPtr: | ||
| 12967 | return false; | 13104 | return false; |
| 12968 | case IrInstructionIdAsm: | 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,6 +875,16 @@ static void ir_print_set_fn_ref_inline(IrPrint *irp, IrInstructionSetFnRefInline |
| 875 | ir_print_other_instruction(irp, instruction->fn_ref); | 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 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | 888 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 879 | ir_print_prefix(irp, instruction); | 889 | ir_print_prefix(irp, instruction); |
| 880 | switch (instruction->id) { | 890 | switch (instruction->id) { |
| ... | @@ -1162,6 +1172,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1162,6 +1172,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1162 | case IrInstructionIdSetFnRefInline: | 1172 | case IrInstructionIdSetFnRefInline: |
| 1163 | ir_print_set_fn_ref_inline(irp, (IrInstructionSetFnRefInline *)instruction); | 1173 | ir_print_set_fn_ref_inline(irp, (IrInstructionSetFnRefInline *)instruction); |
| 1164 | break; | 1174 | break; |
| 1175 | case IrInstructionIdFieldParentPtr: | ||
| 1176 | ir_print_field_parent_ptr(irp, (IrInstructionFieldParentPtr *)instruction); | ||
| 1177 | break; | ||
| 1165 | } | 1178 | } |
| 1166 | fprintf(irp->f, "\n"); | 1179 | fprintf(irp->f, "\n"); |
| 1167 | } | 1180 | } |
std/build.zig+6-18| ... | @@ -580,9 +580,7 @@ const Exe = struct { | ... | @@ -580,9 +580,7 @@ const Exe = struct { |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | fn make(step: &Step) -> %void { | 582 | fn make(step: &Step) -> %void { |
| 583 | // TODO issue #320 | 583 | const exe = @fieldParentPtr(Exe, "step", step); |
| 584 | //const self = @fieldParentPtr(Exe, "step", step); | ||
| 585 | const exe = @ptrcast(&Exe, step); | ||
| 586 | const builder = exe.builder; | 584 | const builder = exe.builder; |
| 587 | 585 | ||
| 588 | var zig_args = List([]const u8).init(builder.allocator); | 586 | var zig_args = List([]const u8).init(builder.allocator); |
| ... | @@ -754,9 +752,7 @@ const CLibrary = struct { | ... | @@ -754,9 +752,7 @@ const CLibrary = struct { |
| 754 | } | 752 | } |
| 755 | 753 | ||
| 756 | fn make(step: &Step) -> %void { | 754 | fn make(step: &Step) -> %void { |
| 757 | // TODO issue #320 | 755 | const self = @fieldParentPtr(CLibrary, "step", step); |
| 758 | //const self = @fieldParentPtr(CLibrary, "step", step); | ||
| 759 | const self = @ptrcast(&CLibrary, step); | ||
| 760 | const cc = os.getEnv("CC") ?? "cc"; | 756 | const cc = os.getEnv("CC") ?? "cc"; |
| 761 | const builder = self.builder; | 757 | const builder = self.builder; |
| 762 | 758 | ||
| ... | @@ -897,9 +893,7 @@ const CExecutable = struct { | ... | @@ -897,9 +893,7 @@ const CExecutable = struct { |
| 897 | } | 893 | } |
| 898 | 894 | ||
| 899 | fn make(step: &Step) -> %void { | 895 | fn make(step: &Step) -> %void { |
| 900 | // TODO issue #320 | 896 | const self = @fieldParentPtr(CExecutable, "step", step); |
| 901 | //const self = @fieldParentPtr(CExecutable, "step", step); | ||
| 902 | const self = @ptrcast(&CExecutable, step); | ||
| 903 | const cc = os.getEnv("CC") ?? "cc"; | 897 | const cc = os.getEnv("CC") ?? "cc"; |
| 904 | const builder = self.builder; | 898 | const builder = self.builder; |
| 905 | 899 | ||
| ... | @@ -987,9 +981,7 @@ const CommandStep = struct { | ... | @@ -987,9 +981,7 @@ const CommandStep = struct { |
| 987 | } | 981 | } |
| 988 | 982 | ||
| 989 | fn make(step: &Step) -> %void { | 983 | fn make(step: &Step) -> %void { |
| 990 | // TODO issue #320 | 984 | const self = @fieldParentPtr(CommandStep, "step", step); |
| 991 | //const self = @fieldParentPtr(CExecutable, "step", step); | ||
| 992 | const self = @ptrcast(&CommandStep, step); | ||
| 993 | 985 | ||
| 994 | // TODO set cwd | 986 | // TODO set cwd |
| 995 | self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args); | 987 | self.builder.spawnChildEnvMap(self.env_map, self.exe_path, self.args); |
| ... | @@ -1021,9 +1013,7 @@ const InstallCLibraryStep = struct { | ... | @@ -1021,9 +1013,7 @@ const InstallCLibraryStep = struct { |
| 1021 | } | 1013 | } |
| 1022 | 1014 | ||
| 1023 | fn make(step: &Step) -> %void { | 1015 | fn make(step: &Step) -> %void { |
| 1024 | // TODO issue #320 | 1016 | const self = @fieldParentPtr(InstallCLibraryStep, "step", step); |
| 1025 | //const self = @fieldParentPtr(InstallCLibraryStep, "step", step); | ||
| 1026 | const self = @ptrcast(&InstallCLibraryStep, step); | ||
| 1027 | 1017 | ||
| 1028 | self.builder.copyFile(self.lib.out_filename, self.dest_file); | 1018 | self.builder.copyFile(self.lib.out_filename, self.dest_file); |
| 1029 | if (!self.lib.static) { | 1019 | if (!self.lib.static) { |
| ... | @@ -1051,9 +1041,7 @@ const InstallFileStep = struct { | ... | @@ -1051,9 +1041,7 @@ const InstallFileStep = struct { |
| 1051 | } | 1041 | } |
| 1052 | 1042 | ||
| 1053 | fn make(step: &Step) -> %void { | 1043 | fn make(step: &Step) -> %void { |
| 1054 | // TODO issue #320 | 1044 | const self = @fieldParentPtr(InstallFileStep, "step", step); |
| 1055 | //const self = @fieldParentPtr(InstallFileStep, "step", step); | ||
| 1056 | const self = @ptrcast(&InstallFileStep, step); | ||
| 1057 | 1045 | ||
| 1058 | debug.panic("TODO install file"); | 1046 | debug.panic("TODO install file"); |
| 1059 | } | 1047 | } |
std/mem.zig+1-3| ... | @@ -76,9 +76,7 @@ pub const IncrementingAllocator = struct { | ... | @@ -76,9 +76,7 @@ pub const IncrementingAllocator = struct { |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | fn alloc(allocator: &Allocator, n: usize) -> %[]u8 { | 78 | fn alloc(allocator: &Allocator, n: usize) -> %[]u8 { |
| 79 | // TODO issue #320 | 79 | const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); |
| 80 | //const self = @fieldParentPtr(IncrementingAllocator, "allocator", allocator); | ||
| 81 | const self = @ptrcast(&IncrementingAllocator, allocator); | ||
| 82 | const new_end_index = self.end_index + n; | 80 | const new_end_index = self.end_index + n; |
| 83 | if (new_end_index > self.bytes.len) { | 81 | if (new_end_index > self.bytes.len) { |
| 84 | return error.NoMem; | 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,6 +1902,56 @@ export fn foo() { |
| 1902 | var y: &void = @intToPtr(&void, x); | 1902 | var y: &void = @intToPtr(&void, x); |
| 1903 | } | 1903 | } |
| 1904 | )SOURCE", 1, ".tmp_source.zig:4:31: error: type '&void' has 0 bits and cannot store information"); | 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,6 +10,7 @@ comptime { |
| 10 | _ = @import("cases/enum_with_members.zig"); | 10 | _ = @import("cases/enum_with_members.zig"); |
| 11 | _ = @import("cases/error.zig"); | 11 | _ = @import("cases/error.zig"); |
| 12 | _ = @import("cases/eval.zig"); | 12 | _ = @import("cases/eval.zig"); |
| 13 | _ = @import("cases/field_parent_ptr.zig"); | ||
| 13 | _ = @import("cases/fn.zig"); | 14 | _ = @import("cases/fn.zig"); |
| 14 | _ = @import("cases/for.zig"); | 15 | _ = @import("cases/for.zig"); |
| 15 | _ = @import("cases/generics.zig"); | 16 | _ = @import("cases/generics.zig"); |