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:
LemonBoy 2020-03-09 20:58:25 +01:00 committed by Andrew Kelley
parent 638d5c3aca
commit 1f44b29724
5 changed files with 77 additions and 19 deletions

View File

@ -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:

View File

@ -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);

View File

@ -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)) {

View File

@ -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;

View File

@ -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();
}