ir: Fix codegen of ?*T types where T is zero-sized
* 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 #4673
This commit is contained in:
parent
638d5c3aca
commit
1f44b29724
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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)) {
|
||||
|
26
src/ir.cpp
26
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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user