Commit 4c3f27ce1e

Jimmi HC <jhc@liab.dk>
2018-06-29 10:21:43
ir_resolve_const now checks recursivly for undef values
1 parent b1128b1
src/analyze.cpp
@@ -5288,6 +5288,141 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_
     return const_val;
 }
 
+bool contains_comptime_undefined_value(ConstExprValue *value) {
+    assert(value->special != ConstValSpecialRuntime);
+    if (value->special == ConstValSpecialUndef)
+        return true;
+
+    switch (value->type->id) {
+        case TypeTableEntryIdInvalid:
+            zig_unreachable();
+
+        case TypeTableEntryIdPointer: {
+            ConstPtrValue *ptr = &value->data.x_ptr;
+            if (ptr->mut == ConstPtrMutRuntimeVar)
+                return false;
+
+            switch (ptr->special) {
+                case ConstPtrSpecialInvalid:
+                    zig_unreachable();
+                case ConstPtrSpecialRef:
+                    return contains_comptime_undefined_value(ptr->data.ref.pointee);
+                case ConstPtrSpecialBaseArray: {
+                    size_t index = ptr->data.base_array.elem_index;
+                    ConstExprValue *arr = ptr->data.base_array.array_val;
+                    if (arr->special == ConstValSpecialUndef)
+                        return true;
+                    if (arr->data.x_array.special == ConstArraySpecialUndef)
+                        return true;
+
+                    return contains_comptime_undefined_value(&arr->data.x_array.s_none.elements[index]);
+                }
+                case ConstPtrSpecialBaseStruct: {
+                    size_t index = ptr->data.base_struct.field_index;
+                    ConstExprValue *str = ptr->data.base_struct.struct_val;
+                    if (str->special == ConstValSpecialUndef)
+                        return true;
+
+                    return contains_comptime_undefined_value(&str->data.x_struct.fields[index]);
+                }
+                case ConstPtrSpecialFunction: // TODO: Can a fn ptr have an undefined value?
+                case ConstPtrSpecialDiscard:
+                case ConstPtrSpecialHardCodedAddr:
+                    return false;
+            }
+        }
+        case TypeTableEntryIdArray: {
+            ConstArrayValue *arr = &value->data.x_array;
+            if (arr->special == ConstArraySpecialUndef)
+                return true;
+
+            for (size_t i = 0; i < value->type->data.array.len; ++i) {
+                if (contains_comptime_undefined_value(&arr->s_none.elements[i]))
+                    return true;
+            }
+            return false;
+        }
+        case TypeTableEntryIdStruct: {
+            ConstStructValue *str = &value->data.x_struct;
+            if (value->type->data.structure.is_slice) {
+                ConstExprValue *len = &str->fields[slice_len_index];
+                ConstExprValue *ptr = &str->fields[slice_ptr_index];
+                if (len->special == ConstValSpecialUndef)
+                    return true;
+                if (ptr->special == ConstValSpecialUndef)
+                    return true;
+
+                switch (ptr->data.x_ptr.special) {
+                    case ConstPtrSpecialRef:
+                        return contains_comptime_undefined_value(ptr->data.x_ptr.data.ref.pointee);
+                    case ConstPtrSpecialBaseArray: {
+                        size_t offset = ptr->data.x_ptr.data.base_array.elem_index;
+                        ConstExprValue *arr = ptr->data.x_ptr.data.base_array.array_val;
+                        if (arr->special == ConstValSpecialUndef)
+                            return true;
+                        if (arr->data.x_array.special == ConstArraySpecialUndef)
+                            return true;
+
+                        uint64_t slice_len = bigint_as_unsigned(&len->data.x_bigint);
+                        for (size_t i = 0; i < slice_len; ++i) {
+                            if (contains_comptime_undefined_value(&arr->data.x_array.s_none.elements[i + offset]))
+                                return true;
+                        }
+
+                        return false;
+                    }
+                    case ConstPtrSpecialBaseStruct:
+                    case ConstPtrSpecialInvalid:
+                    case ConstPtrSpecialFunction:
+                    case ConstPtrSpecialDiscard:
+                    case ConstPtrSpecialHardCodedAddr:
+                        zig_unreachable();
+                }
+            }
+
+            for (size_t i = 0; i < value->type->data.structure.src_field_count; ++i) {
+                if (contains_comptime_undefined_value(&str->fields[i]))
+                    return true;
+            }
+            return false;
+        }
+        case TypeTableEntryIdOptional:
+            if (value->data.x_optional == nullptr)
+                return false;
+
+            return contains_comptime_undefined_value(value->data.x_optional);
+        case TypeTableEntryIdErrorUnion:
+            // TODO: Can error union error be undefined?
+            if (value->data.x_err_union.err != nullptr)
+                return false;
+
+            return contains_comptime_undefined_value(value->data.x_err_union.payload);
+        case TypeTableEntryIdUnion:
+            return contains_comptime_undefined_value(value->data.x_union.payload);
+
+        case TypeTableEntryIdArgTuple:
+        case TypeTableEntryIdVoid:
+        case TypeTableEntryIdBool:
+        case TypeTableEntryIdUnreachable:
+        case TypeTableEntryIdInt:
+        case TypeTableEntryIdFloat:
+        case TypeTableEntryIdComptimeFloat:
+        case TypeTableEntryIdComptimeInt:
+        case TypeTableEntryIdUndefined:
+        case TypeTableEntryIdNull:
+        case TypeTableEntryIdErrorSet:
+        case TypeTableEntryIdEnum:
+        case TypeTableEntryIdFn:
+        case TypeTableEntryIdNamespace:
+        case TypeTableEntryIdBlock:
+        case TypeTableEntryIdBoundFn:
+        case TypeTableEntryIdMetaType:
+        case TypeTableEntryIdOpaque:
+        case TypeTableEntryIdPromise:
+            return false;
+    }
+    zig_unreachable();
+}
 
 void init_const_undefined(CodeGen *g, ConstExprValue *const_val) {
     TypeTableEntry *wanted_type = const_val->type;
src/analyze.hpp
@@ -93,6 +93,7 @@ void ensure_complete_type(CodeGen *g, TypeTableEntry *type_entry);
 void type_ensure_zero_bits_known(CodeGen *g, TypeTableEntry *type_entry);
 void complete_enum(CodeGen *g, TypeTableEntry *enum_type);
 bool ir_get_var_is_comptime(VariableTableEntry *var);
+bool contains_comptime_undefined_value(ConstExprValue *value);
 bool const_values_equal(ConstExprValue *a, ConstExprValue *b);
 void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val, bool is_max);
 void eval_min_max_value_int(CodeGen *g, TypeTableEntry *int_type, BigInt *bigint, bool is_max);
src/ir.cpp
@@ -9148,8 +9148,15 @@ enum UndefAllowed {
 
 static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) {
     switch (value->value.special) {
-        case ConstValSpecialStatic:
-            return &value->value;
+        case ConstValSpecialStatic: {
+            ConstExprValue *res = &value->value;
+            if (undef_allowed == UndefBad && contains_comptime_undefined_value(res)) {
+                ir_add_error(ira, value, buf_sprintf("use of undefined value"));
+                return nullptr;
+            }
+
+            return res;
+        }
         case ConstValSpecialRuntime:
             ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression"));
             return nullptr;
test/compile_errors.zig
@@ -4124,4 +4124,19 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
     ,
         ".tmp_source.zig:3:36: error: @ArgType could not resolve the type of arg 0 because 'fn(var)var' is generic",
     );
+
+    cases.add(
+        "Trying to pass undefined array to function taking comptime array by value",
+        \\fn a(comptime b: [2]u8) u8 { return b[0]; }
+        \\
+        \\test "" {
+        \\    const arr: [2]u8 = undefined;
+        \\    _ = a(arr);
+        \\}
+    ,
+        ".tmp_source.zig:5:11: error: use of undefined value",
+    );
+
+
+
 }