diff --git a/src/codegen.cpp b/src/codegen.cpp index b28b370f9a..df5e6d1787 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2171,6 +2171,20 @@ static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, Ir return tmp_struct_ptr; } +static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) { + for (size_t i = 0; i < instruction->field_count; i += 1) { + IrInstructionStructInitField *field = &instruction->fields[i]; + TypeStructField *type_struct_field = field->type_struct_field; + if (!type_has_bits(type_struct_field->type_entry)) + continue; + + LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, type_struct_field->gen_index, ""); + LLVMValueRef value = ir_llvm_value(g, field->value); + gen_assign_raw(g, field_ptr, value, type_struct_field->type_entry, type_struct_field->type_entry); + } + return instruction->tmp_ptr; +} + static void set_debug_location(CodeGen *g, IrInstruction *instruction) { AstNode *source_node = instruction->source_node; Scope *scope = instruction->scope; @@ -2307,12 +2321,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction); case IrInstructionIdInitEnum: return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); + case IrInstructionIdStructInit: + return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); case IrInstructionIdSwitchVar: zig_panic("TODO render switch var instruction to LLVM"); case IrInstructionIdContainerInitList: zig_panic("TODO render container init list instruction to LLVM"); - case IrInstructionIdStructInit: - zig_panic("TODO render struct init to LLVM"); } zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 05427f75e8..99a80d6408 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8431,8 +8431,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru IrInstructionStructInitField *new_fields = allocate(actual_field_count); - FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); - bool outside_fn = (fn_entry == nullptr); + bool is_comptime = ir_should_inline(&ira->new_irb); ConstExprValue const_val = {}; const_val.special = ConstValSpecialStatic; @@ -8456,6 +8455,10 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru if (type_field->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; + IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry); + if (casted_field_value == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + size_t field_index = type_field->src_index; AstNode *existing_assign_node = field_assign_nodes[field_index]; if (existing_assign_node) { @@ -8465,19 +8468,19 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru } field_assign_nodes[field_index] = field->source_node; - new_fields[field_index].value = field_value; + new_fields[field_index].value = casted_field_value; new_fields[field_index].type_struct_field = type_field; if (const_val.special == ConstValSpecialStatic) { - if (outside_fn || field_value->static_value.special != ConstValSpecialRuntime) { - ConstExprValue *field_val = ir_resolve_const(ira, field_value, UndefOk); + if (is_comptime || casted_field_value->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); if (!field_val) return ira->codegen->builtin_types.entry_invalid; const_val.data.x_struct.fields[field_index] = *field_val; const_val.depends_on_compile_var = const_val.depends_on_compile_var || field_val->depends_on_compile_var; } else { - first_non_const_instruction = field_value; + first_non_const_instruction = casted_field_value; const_val.special = ConstValSpecialRuntime; } } @@ -8500,7 +8503,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru return container_type; } - if (outside_fn) { + if (is_comptime) { ir_add_error_node(ira, first_non_const_instruction->source_node, buf_sprintf("unable to evaluate constant expression")); return ira->codegen->builtin_types.entry_invalid; @@ -8513,7 +8516,9 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru return container_type; } -static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { +static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, + IrInstructionContainerInitList *instruction) +{ IrInstruction *container_type_value = instruction->container_type->other; if (container_type_value->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; @@ -8527,7 +8532,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) { - return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var); + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, + 0, nullptr, depends_on_compile_var); } else if (is_slice(container_type)) { TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; assert(pointer_type->id == TypeTableEntryIdPointer); @@ -8539,8 +8545,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira const_val.data.x_array.elements = allocate(elem_count); const_val.data.x_array.size = elem_count; - FnTableEntry *fn_entry = exec_fn_entry(ira->new_irb.exec); - bool outside_fn = (fn_entry == nullptr); + bool is_comptime = ir_should_inline(&ira->new_irb); IrInstruction **new_items = allocate(elem_count); @@ -8551,18 +8556,22 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira if (arg_value->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; - new_items[i] = arg_value; + IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); + if (casted_arg == ira->codegen->invalid_instruction) + return ira->codegen->builtin_types.entry_invalid; + + new_items[i] = casted_arg; if (const_val.special == ConstValSpecialStatic) { - if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) { - ConstExprValue *elem_val = ir_resolve_const(ira, arg_value, UndefBad); + if (is_comptime || casted_arg->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); if (!elem_val) return ira->codegen->builtin_types.entry_invalid; const_val.data.x_array.elements[i] = *elem_val; const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var; } else { - first_non_const_instruction = arg_value; + first_non_const_instruction = casted_arg; const_val.special = ConstValSpecialRuntime; } } @@ -8575,7 +8584,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira return fixed_size_array_type; } - if (outside_fn) { + if (is_comptime) { ir_add_error_node(ira, first_non_const_instruction->source_node, buf_sprintf("unable to evaluate constant expression")); return ira->codegen->builtin_types.entry_invalid; @@ -8602,10 +8611,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira return ira->codegen->builtin_types.entry_invalid; } } else if (container_type_value->type_entry->id == TypeTableEntryIdEnumTag) { - // TODO I wrote this commit message when I had some sake - // might be worth re-examining sober if (elem_count != 1) { - ir_add_error(ira, &instruction->base, buf_sprintf("expected 1 elment")); + ir_add_error(ira, &instruction->base, buf_sprintf("enum initialization requires exactly one element")); return ira->codegen->builtin_types.entry_invalid; } ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad); diff --git a/test/cases/struct_contains_slice_of_itself.zig b/test/cases3/struct_contains_slice_of_itself.zig similarity index 86% rename from test/cases/struct_contains_slice_of_itself.zig rename to test/cases3/struct_contains_slice_of_itself.zig index 2a8fc52ded..8c5739413a 100644 --- a/test/cases/struct_contains_slice_of_itself.zig +++ b/test/cases3/struct_contains_slice_of_itself.zig @@ -1,12 +1,10 @@ -const assert = @import("std").debug.assert; - -struct Node { +const Node = struct { payload: i32, children: []Node, -} +}; fn structContainsSliceOfItself() { - @setFnTest(this, true); + @setFnTest(this); var nodes = []Node { Node { @@ -42,3 +40,9 @@ fn structContainsSliceOfItself() { assert(root.children[2].children[0].payload == 31); assert(root.children[2].children[1].payload == 32); } + +// TODO const assert = @import("std").debug.assert; +fn assert(ok: bool) { + if (!ok) + @unreachable(); +} diff --git a/test/self_hosted3.zig b/test/self_hosted3.zig index b893cc65b0..448116890a 100644 --- a/test/self_hosted3.zig +++ b/test/self_hosted3.zig @@ -20,3 +20,4 @@ const test_struct = @import("cases3/struct.zig"); const test_switch = @import("cases3/switch.zig"); const test_this = @import("cases3/this.zig"); const test_while = @import("cases3/while.zig"); +const test_struct_contains_slice_of_itself = @import("cases3/struct_contains_slice_of_itself.zig");