| author | |
| committer | |
| log | 1f44b29724b52433d84b43345a52da59f9220e62 |
| tree | a02ff60c378f78fee29d6559d44954b13ce0417a |
| parent | 638d5c3aca7ce1e4fd10060079caa0acb66144c0 |
* Fix codegen for optional types that decay to a pointer, the type
behaves as a boolean
* Fix comptime evaluation of zero-sized arrays, always initialize the
internal array elements
Closes #46735 files changed, 77 insertions(+), 19 deletions(-)
src/analyze.cpp+34| ... | ... | @@ -5797,6 +5797,7 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 5797 | 5797 | ZigValue *result = g->pass1_arena->create<ZigValue>(); |
| 5798 | 5798 | result->type = type_entry; |
| 5799 | 5799 | result->special = ConstValSpecialStatic; |
| 5800 | ||
| 5800 | 5801 | if (result->type->id == ZigTypeIdStruct) { |
| 5801 | 5802 | // The fields array cannot be left unpopulated |
| 5802 | 5803 | const ZigType *struct_type = result->type; |
| ... | ... | @@ -5808,6 +5809,22 @@ ZigValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 5808 | 5809 | assert(field_type != nullptr); |
| 5809 | 5810 | result->data.x_struct.fields[i] = get_the_one_possible_value(g, field_type); |
| 5810 | 5811 | } |
| 5812 | } else if (result->type->id == ZigTypeIdArray) { | |
| 5813 | // The elements array cannot be left unpopulated | |
| 5814 | ZigType *array_type = result->type; | |
| 5815 | ZigType *elem_type = array_type->data.array.child_type; | |
| 5816 | ZigValue *sentinel_value = array_type->data.array.sentinel; | |
| 5817 | const size_t elem_count = array_type->data.array.len + (sentinel_value != nullptr); | |
| 5818 | ||
| 5819 | result->data.x_array.data.s_none.elements = g->pass1_arena->allocate<ZigValue>(elem_count); | |
| 5820 | for (size_t i = 0; i < elem_count; i += 1) { | |
| 5821 | ZigValue *elem_val = &result->data.x_array.data.s_none.elements[i]; | |
| 5822 | copy_const_val(g, elem_val, get_the_one_possible_value(g, elem_type)); | |
| 5823 | } | |
| 5824 | if (sentinel_value != nullptr) { | |
| 5825 | ZigValue *last_elem_val = &result->data.x_array.data.s_none.elements[elem_count - 1]; | |
| 5826 | copy_const_val(g, last_elem_val, sentinel_value); | |
| 5827 | } | |
| 5811 | 5828 | } else if (result->type->id == ZigTypeIdPointer) { |
| 5812 | 5829 | result->data.x_ptr.special = ConstPtrSpecialRef; |
| 5813 | 5830 | 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) { |
| 9537 | 9554 | } |
| 9538 | 9555 | } |
| 9539 | 9556 | |
| 9557 | bool optional_value_is_null(ZigValue *val) { | |
| 9558 | assert(val->special == ConstValSpecialStatic); | |
| 9559 | if (get_src_ptr_type(val->type) != nullptr) { | |
| 9560 | if (val->data.x_ptr.special == ConstPtrSpecialNull) { | |
| 9561 | return true; | |
| 9562 | } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { | |
| 9563 | return val->data.x_ptr.data.hard_coded_addr.addr == 0; | |
| 9564 | } else { | |
| 9565 | return false; | |
| 9566 | } | |
| 9567 | } else if (is_opt_err_set(val->type)) { | |
| 9568 | return val->data.x_err_set == nullptr; | |
| 9569 | } else { | |
| 9570 | return val->data.x_optional == nullptr; | |
| 9571 | } | |
| 9572 | } | |
| 9573 | ||
| 9540 | 9574 | bool type_is_numeric(ZigType *ty) { |
| 9541 | 9575 | switch (ty->id) { |
| 9542 | 9576 | case ZigTypeIdInvalid: |
src/analyze.hpp+1| ... | ... | @@ -198,6 +198,7 @@ size_t type_id_index(ZigType *entry); |
| 198 | 198 | ZigType *get_generic_fn_type(CodeGen *g, FnTypeId *fn_type_id); |
| 199 | 199 | LinkLib *create_link_lib(Buf *name); |
| 200 | 200 | LinkLib *add_link_lib(CodeGen *codegen, Buf *lib); |
| 201 | bool optional_value_is_null(ZigValue *val); | |
| 201 | 202 | |
| 202 | 203 | uint32_t get_abi_alignment(CodeGen *g, ZigType *type_entry); |
| 203 | 204 | ZigType *get_align_amt_type(CodeGen *g); |
src/codegen.cpp+11-1| ... | ... | @@ -6902,8 +6902,18 @@ check: switch (const_val->special) { |
| 6902 | 6902 | case ZigTypeIdOptional: |
| 6903 | 6903 | { |
| 6904 | 6904 | ZigType *child_type = type_entry->data.maybe.child_type; |
| 6905 | ||
| 6905 | 6906 | if (get_src_ptr_type(type_entry) != nullptr) { |
| 6906 | return gen_const_val_ptr(g, const_val, name); | |
| 6907 | bool has_bits; | |
| 6908 | if ((err = type_has_bits2(g, child_type, &has_bits))) | |
| 6909 | codegen_report_errors_and_exit(g); | |
| 6910 | ||
| 6911 | if (has_bits) | |
| 6912 | return gen_const_val_ptr(g, const_val, name); | |
| 6913 | ||
| 6914 | // No bits, treat this value as a boolean | |
| 6915 | const unsigned bool_val = optional_value_is_null(const_val) ? 0 : 1; | |
| 6916 | return LLVMConstInt(LLVMInt1Type(), bool_val, false); | |
| 6907 | 6917 | } else if (child_type->id == ZigTypeIdErrorSet) { |
| 6908 | 6918 | return gen_const_val_err_set(g, const_val, name); |
| 6909 | 6919 | } else if (!type_has_bits(g, child_type)) { |
src/ir.cpp+8-18| ... | ... | @@ -15478,23 +15478,6 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { |
| 15478 | 15478 | } |
| 15479 | 15479 | } |
| 15480 | 15480 | |
| 15481 | static bool optional_value_is_null(ZigValue *val) { | |
| 15482 | assert(val->special == ConstValSpecialStatic); | |
| 15483 | if (get_src_ptr_type(val->type) != nullptr) { | |
| 15484 | if (val->data.x_ptr.special == ConstPtrSpecialNull) { | |
| 15485 | return true; | |
| 15486 | } else if (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { | |
| 15487 | return val->data.x_ptr.data.hard_coded_addr.addr == 0; | |
| 15488 | } else { | |
| 15489 | return false; | |
| 15490 | } | |
| 15491 | } else if (is_opt_err_set(val->type)) { | |
| 15492 | return val->data.x_err_set == nullptr; | |
| 15493 | } else { | |
| 15494 | return val->data.x_optional == nullptr; | |
| 15495 | } | |
| 15496 | } | |
| 15497 | ||
| 15498 | 15481 | static void set_optional_value_to_null(ZigValue *val) { |
| 15499 | 15482 | assert(val->special == ConstValSpecialStatic); |
| 15500 | 15483 | if (val->type->id == ZigTypeIdNull) return; // nothing to do |
| ... | ... | @@ -17594,7 +17577,14 @@ static IrInstGen *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstSrcDeclV |
| 17594 | 17577 | |
| 17595 | 17578 | ZigValue *init_val = nullptr; |
| 17596 | 17579 | if (instr_is_comptime(var_ptr) && var_ptr->value->data.x_ptr.mut != ConstPtrMutRuntimeVar) { |
| 17597 | init_val = const_ptr_pointee(ira, ira->codegen, var_ptr->value, decl_var_instruction->base.base.source_node); | |
| 17580 | ZigValue *ptr_val = ir_resolve_const(ira, var_ptr, UndefBad); | |
| 17581 | if (ptr_val == nullptr) | |
| 17582 | return ira->codegen->invalid_inst_gen; | |
| 17583 | ||
| 17584 | init_val = const_ptr_pointee(ira, ira->codegen, ptr_val, decl_var_instruction->base.base.source_node); | |
| 17585 | if (init_val == nullptr) | |
| 17586 | return ira->codegen->invalid_inst_gen; | |
| 17587 | ||
| 17598 | 17588 | if (is_comptime_var) { |
| 17599 | 17589 | if (var->gen_is_const) { |
| 17600 | 17590 | var->const_value = init_val; |
test/stage1/behavior/optional.zig+23| ... | ... | @@ -175,3 +175,26 @@ test "0-bit child type coerced to optional return ptr result location" { |
| 175 | 175 | S.doTheTest(); |
| 176 | 176 | comptime S.doTheTest(); |
| 177 | 177 | } |
| 178 | ||
| 179 | test "0-bit child type coerced to optional" { | |
| 180 | const S = struct { | |
| 181 | fn doTheTest() void { | |
| 182 | var it: Foo = .{ | |
| 183 | .list = undefined, | |
| 184 | }; | |
| 185 | expect(it.foo() != null); | |
| 186 | } | |
| 187 | ||
| 188 | const Empty = struct {}; | |
| 189 | const Foo = struct { | |
| 190 | list: [10]Empty, | |
| 191 | ||
| 192 | fn foo(self: *Foo) ?*Empty { | |
| 193 | const data = &self.list[0]; | |
| 194 | return data; | |
| 195 | } | |
| 196 | }; | |
| 197 | }; | |
| 198 | S.doTheTest(); | |
| 199 | comptime S.doTheTest(); | |
| 200 | } |