Commit 1f44b29724
Changed files (5)
test
stage1
behavior
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:
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);
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)) {
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;
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();
+}