diff options
| -rw-r--r-- | src/analyze.cpp | 34 | ||||
| -rw-r--r-- | src/analyze.hpp | 1 | ||||
| -rw-r--r-- | src/codegen.cpp | 12 | ||||
| -rw-r--r-- | src/ir.cpp | 26 | ||||
| -rw-r--r-- | test/stage1/behavior/optional.zig | 23 |
5 files changed, 77 insertions, 19 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp index d924002426..905a6a6f94 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5797,6 +5797,7 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { ZigValue *result = g->pass1_arena->create<ZigValue>(); result->type = type_entry; result->special = ConstValSpecialStatic; + if (result->type->id == ZigTypeIdStruct) { // The fields array cannot be left unpopulated const ZigType *struct_type = result->type; @@ -5808,6 +5809,22 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { assert(field_type != nullptr); result->data.x_struct.fields[i] = get_the_one_possible_value(g, field_type); } + } else if (result->type->id == ZigTypeIdArray) { + // The elements array cannot be left unpopulated + ZigType *array_type = result->type; + ZigType *elem_type = array_type->data.array.child_type; + ZigValue *sentinel_value = array_type->data.array.sentinel; + const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); + + result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count); + for (size_t i = 0; i < elem_count; i += 1) { + ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; + copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); + } + if (sentinel_value != nullptr) { + ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1]; + copy_const_val(g, last_elem_val, sentinel_value); + } } else if (result->type->id == ZigTypeIdPointer) { result->data.x_ptr.special = ConstPtrSpecialRef; result->data.x_ptr.data.ref.pointee = get_the_one_possible_value(g, result->type->data.pointer.child_type); @@ -9537,6 +9554,23 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { } } +bool optional_value_is_null(ZigValue *val) { + assert(val->special == ConstValSpecialStatic); + if (get_src_ptr_type(val->type) != nullptr) { + if (val->data.x_ptr.special == ConstPtrSpecialNull) { + return true; + } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { + return val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else { + return false; + } + } else if (is_opt_err_set(val->type)) { + return val->data.x_err_set == nullptr; + } else { + return val->data.x_optional == nullptr; + } +} + bool type_is_numeric(ZigType *ty) { switch (ty->id) { case ZigTypeIdInvalid: diff --git a/src/analyze.hpp b/src/analyze.hpp index 98d09d452f..0b48d357f6 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -198,6 +198,7 @@ size_t type_id_index(ZigType *entry); ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); LinkLib *create_link_lib(Buf *name); LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); +bool optional_value_is_null(ZigValue *val); uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry); ZigType *get_align_amt_type(CodeGen *g); diff --git a/src/codegen.cpp b/src/codegen.cpp index a67b8dc00b..22cb975205 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6902,8 +6902,18 @@ check: switch (const_val->special) { case ZigTypeIdOptional: { ZigType *child_type = type_entry->data.maybe.child_type; + if (get_src_ptr_type(type_entry) != nullptr) { - return gen_const_val_ptr(g, const_val, name); + bool has_bits; + if ((err = type_has_bits2(g, child_type, &has_bits))) + codegen_report_errors_and_exit(g); + + if (has_bits) + return gen_const_val_ptr(g, const_val, name); + + // No bits, treat this value as a boolean + const unsigned bool_val = optional_value_is_null(const_val) ? 0 : 1; + return LLVMConstInt(LLVMInt1Type(), bool_val, false); } else if (child_type->id == ZigTypeIdErrorSet) { return gen_const_val_err_set(g, const_val, name); } else if (!type_has_bits(g, child_type)) { diff --git a/src/ir.cpp b/src/ir.cpp index aab2bff813..e2cf13b77d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15478,23 +15478,6 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { } } -static bool optional_value_is_null(ZigValue *val) { - assert(val->special == ConstValSpecialStatic); - if (get_src_ptr_type(val->type) != nullptr) { - if (val->data.x_ptr.special == ConstPtrSpecialNull) { - return true; - } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - return val->data.x_ptr.data.hard_coded_addr.addr == 0; - } else { - return false; - } - } else if (is_opt_err_set(val->type)) { - return val->data.x_err_set == nullptr; - } else { - return val->data.x_optional == nullptr; - } -} - static void set_optional_value_to_null(ZigValue *val) { assert(val->special == ConstValSpecialStatic); if (val->type->id == ZigTypeIdNull) return; // nothing to do @@ -17594,7 +17577,14 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV ZigValue *init_val = nullptr; if (instr_is_comptime(var_ptr) && var_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - init_val = const_ptr_pointee(ira, ira->codegen, var_ptr->value, decl_var_instruction->base.base.source_node); + ZigValue *ptr_val = ir_resolve_const(ira, var_ptr, UndefBad); + if (ptr_val == nullptr) + return ira->codegen->invalid_inst_gen; + + init_val = const_ptr_pointee(ira, ira->codegen, ptr_val, decl_var_instruction->base.base.source_node); + if (init_val == nullptr) + return ira->codegen->invalid_inst_gen; + if (is_comptime_var) { if (var->gen_is_const) { var->const_value = init_val; diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index fa002b707e..7dd48769db 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -175,3 +175,26 @@ test "0-bit child type coerced to optional return ptr result location" { S.doTheTest(); comptime S.doTheTest(); } + +test "0-bit child type coerced to optional" { + const S = struct { + fn doTheTest() void { + var it: Foo = .{ + .list = undefined, + }; + expect(it.foo() != null); + } + + const Empty = struct {}; + const Foo = struct { + list: [10]Empty, + + fn foo(self: *Foo) ?*Empty { + const data = &self.list[0]; + return data; + } + }; + }; + S.doTheTest(); + comptime S.doTheTest(); +} |
