Commit 1f44b29724

LemonBoy <thatlemon@gmail.com>
2020-03-09 20:58:25
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
1 parent 638d5c3
Changed files (5)
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();
+}