Commit 7f7823e23c

Andrew Kelley <superjoe30@gmail.com>
2018-03-14 00:13:10
fix casting a function to a pointer causing compiler crash
closes #777
1 parent d6e84e3
src/all_types.hpp
@@ -144,6 +144,8 @@ enum ConstPtrSpecial {
     // This means that the pointer represents memory of assigning to _.
     // That is, storing discards the data, and loading is invalid.
     ConstPtrSpecialDiscard,
+    // This is actually a function.
+    ConstPtrSpecialFunction,
 };
 
 enum ConstPtrMut {
@@ -180,6 +182,9 @@ struct ConstPtrValue {
         struct {
             uint64_t addr;
         } hard_coded_addr;
+        struct {
+            FnTableEntry *fn_entry;
+        } fn;
     } data;
 };
 
@@ -222,10 +227,6 @@ enum RuntimeHintPtr {
     RuntimeHintPtrNonStack,
 };
 
-struct ConstFn {
-    FnTableEntry *fn_entry;
-};
-
 struct ConstGlobalRefs {
     LLVMValueRef llvm_value;
     LLVMValueRef llvm_global;
@@ -244,7 +245,6 @@ struct ConstExprValue {
         double x_f64;
         float128_t x_f128;
         bool x_bool;
-        ConstFn x_fn;
         ConstBoundFnValue x_bound_fn;
         TypeTableEntry *x_type;
         ConstExprValue *x_maybe;
src/analyze.cpp
@@ -4447,6 +4447,10 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
         case TypeTableEntryIdArgTuple:
             return (uint32_t)const_val->data.x_arg_tuple.start_index * (uint32_t)281907309 +
                 (uint32_t)const_val->data.x_arg_tuple.end_index * (uint32_t)2290442768;
+        case TypeTableEntryIdFn:
+            assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
+            assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
+            return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
         case TypeTableEntryIdPointer:
             {
                 uint32_t hash_val = 0;
@@ -4486,6 +4490,10 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
                     case ConstPtrSpecialDiscard:
                         hash_val += 2010123162;
                         return hash_val;
+                    case ConstPtrSpecialFunction:
+                        hash_val += (uint32_t)2590901619;
+                        hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry);
+                        return hash_val;
                 }
                 zig_unreachable();
             }
@@ -4517,8 +4525,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
         case TypeTableEntryIdErrorSet:
             assert(const_val->data.x_err_set != nullptr);
             return const_val->data.x_err_set->value ^ 2630160122;
-        case TypeTableEntryIdFn:
-            return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);
         case TypeTableEntryIdNamespace:
             return hash_ptr(const_val->data.x_import);
         case TypeTableEntryIdBlock:
@@ -5150,8 +5156,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
             return true;
         case TypeTableEntryIdErrorSet:
             return a->data.x_err_set->value == b->data.x_err_set->value;
-        case TypeTableEntryIdFn:
-            return a->data.x_fn.fn_entry == b->data.x_fn.fn_entry;
         case TypeTableEntryIdBool:
             return a->data.x_bool == b->data.x_bool;
         case TypeTableEntryIdFloat:
@@ -5172,6 +5176,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
         case TypeTableEntryIdNumLitInt:
             return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
         case TypeTableEntryIdPointer:
+        case TypeTableEntryIdFn:
             if (a->data.x_ptr.special != b->data.x_ptr.special)
                 return false;
             if (a->data.x_ptr.mut != b->data.x_ptr.mut)
@@ -5211,6 +5216,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
                     return true;
                 case ConstPtrSpecialDiscard:
                     return true;
+                case ConstPtrSpecialFunction:
+                    return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry;
             }
             zig_unreachable();
         case TypeTableEntryIdArray:
@@ -5371,6 +5378,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
                 buf_appendf(buf, "%s", value);
                 return;
             }
+        case TypeTableEntryIdFn:
+            {
+                assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
+                assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
+                FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
+                buf_appendf(buf, "%s", buf_ptr(&fn_entry->symbol_name));
+                return;
+            }
         case TypeTableEntryIdPointer:
             switch (const_val->data.x_ptr.special) {
                 case ConstPtrSpecialInvalid:
@@ -5396,14 +5411,14 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
                 case ConstPtrSpecialDiscard:
                     buf_append_str(buf, "&_");
                     return;
+                case ConstPtrSpecialFunction:
+                    {
+                        FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry;
+                        buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name));
+                        return;
+                    }
             }
             zig_unreachable();
-        case TypeTableEntryIdFn:
-            {
-                FnTableEntry *fn_entry = const_val->data.x_fn.fn_entry;
-                buf_appendf(buf, "%s", buf_ptr(&fn_entry->symbol_name));
-                return;
-            }
         case TypeTableEntryIdBlock:
             {
                 AstNode *node = const_val->data.x_block->source_node;
src/codegen.cpp
@@ -4840,7 +4840,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
         case TypeTableEntryIdEnum:
             return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
         case TypeTableEntryIdFn:
-            return fn_llvm_value(g, const_val->data.x_fn.fn_entry);
+            assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
+            assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst);
+            return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry);
         case TypeTableEntryIdPointer:
             {
                 render_const_val_global(g, const_val, name);
@@ -4909,6 +4911,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                             render_const_val_global(g, const_val, "");
                             return const_val->global_refs->llvm_value;
                         }
+                    case ConstPtrSpecialFunction:
+                        return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref);
                 }
             }
             zig_unreachable();
@@ -6313,7 +6317,9 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) {
         ConstExprValue *fn_field = &this_val->data.x_struct.fields[1];
         fn_field->type = fn_type;
         fn_field->special = ConstValSpecialStatic;
-        fn_field->data.x_fn.fn_entry = test_fn_entry;
+        fn_field->data.x_ptr.special = ConstPtrSpecialFunction;
+        fn_field->data.x_ptr.mut = ConstPtrMutComptimeConst;
+        fn_field->data.x_ptr.data.fn.fn_entry = test_fn_entry;
     }
 
     ConstExprValue *test_fn_slice = create_const_slice(g, test_fn_array, 0, g->test_fns.length, true);
src/ir.cpp
@@ -130,6 +130,8 @@ ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
             zig_unreachable();
         case ConstPtrSpecialDiscard:
             zig_unreachable();
+        case ConstPtrSpecialFunction:
+            zig_unreachable();
     }
     zig_unreachable();
 }
@@ -875,7 +877,9 @@ static IrInstruction *ir_create_const_fn(IrBuilder *irb, Scope *scope, AstNode *
     IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(irb, scope, source_node);
     const_instruction->base.value.type = fn_entry->type_entry;
     const_instruction->base.value.special = ConstValSpecialStatic;
-    const_instruction->base.value.data.x_fn.fn_entry = fn_entry;
+    const_instruction->base.value.data.x_ptr.data.fn.fn_entry = fn_entry;
+    const_instruction->base.value.data.x_ptr.mut = ConstPtrMutComptimeConst;
+    const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialFunction;
     return &const_instruction->base;
 }
 
@@ -8723,7 +8727,8 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
     if (!const_val)
         return nullptr;
 
-    return const_val->data.x_fn.fn_entry;
+    assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction);
+    return const_val->data.x_ptr.data.fn.fn_entry;
 }
 
 static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) {
@@ -11311,7 +11316,8 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi
         case TypeTableEntryIdUnreachable:
             zig_unreachable();
         case TypeTableEntryIdFn: {
-            FnTableEntry *fn_entry = target->value.data.x_fn.fn_entry;
+            assert(target->value.data.x_ptr.special == ConstPtrSpecialFunction);
+            FnTableEntry *fn_entry = target->value.data.x_ptr.data.fn.fn_entry;
             CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc;
             switch (cc) {
                 case CallingConventionUnspecified: {
@@ -12852,6 +12858,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
                         zig_panic("TODO elem ptr on a const inner struct");
                     case ConstPtrSpecialHardCodedAddr:
                         zig_unreachable();
+                    case ConstPtrSpecialFunction:
+                        zig_panic("TODO element ptr of a function casted to a ptr");
                 }
                 if (new_index >= mem_size) {
                     ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
@@ -12901,6 +12909,8 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
                         zig_panic("TODO elem ptr on a slice backed by const inner struct");
                     case ConstPtrSpecialHardCodedAddr:
                         zig_unreachable();
+                    case ConstPtrSpecialFunction:
+                        zig_panic("TODO elem ptr on a slice that was ptrcast from a function");
                 }
                 return return_type;
             } else if (array_type->id == TypeTableEntryIdArray) {
@@ -13101,7 +13111,9 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source
             ConstExprValue *const_val = create_const_vals(1);
             const_val->special = ConstValSpecialStatic;
             const_val->type = fn_entry->type_entry;
-            const_val->data.x_fn.fn_entry = fn_entry;
+            const_val->data.x_ptr.data.fn.fn_entry = fn_entry;
+            const_val->data.x_ptr.special = ConstPtrSpecialFunction;
+            const_val->data.x_ptr.mut = ConstPtrMutComptimeConst;
 
             if (tld_fn->extern_lib_name != nullptr) {
                 add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_instruction->source_node);
@@ -13771,7 +13783,8 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
         fast_math_off_ptr = &block_scope->fast_math_off;
         fast_math_set_node_ptr = &block_scope->fast_math_set_node;
     } else if (target_type->id == TypeTableEntryIdFn) {
-        FnTableEntry *target_fn = target_val->data.x_fn.fn_entry;
+        assert(target_val->data.x_ptr.special == ConstPtrSpecialFunction);
+        FnTableEntry *target_fn = target_val->data.x_ptr.data.fn.fn_entry;
         assert(target_fn->def_scope);
         fast_math_off_ptr = &target_fn->def_scope->fast_math_off;
         fast_math_set_node_ptr = &target_fn->def_scope->fast_math_set_node;
@@ -15673,6 +15686,8 @@ static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructi
                 zig_panic("TODO memset on const inner struct");
             case ConstPtrSpecialHardCodedAddr:
                 zig_unreachable();
+            case ConstPtrSpecialFunction:
+                zig_panic("TODO memset on ptr cast from function");
         }
 
         size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint);
@@ -15769,6 +15784,8 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
                 zig_panic("TODO memcpy on const inner struct");
             case ConstPtrSpecialHardCodedAddr:
                 zig_unreachable();
+            case ConstPtrSpecialFunction:
+                zig_panic("TODO memcpy on ptr cast from function");
         }
 
         if (dest_start + count > dest_end) {
@@ -15803,6 +15820,8 @@ static TypeTableEntry *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructi
                 zig_panic("TODO memcpy on const inner struct");
             case ConstPtrSpecialHardCodedAddr:
                 zig_unreachable();
+            case ConstPtrSpecialFunction:
+                zig_panic("TODO memcpy on ptr cast from function");
         }
 
         if (src_start + count > src_end) {
@@ -15925,6 +15944,8 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
                     abs_offset = 0;
                     rel_end = SIZE_MAX;
                     break;
+                case ConstPtrSpecialFunction:
+                    zig_panic("TODO slice of ptr cast from function");
             }
         } else if (is_slice(array_type)) {
             ConstExprValue *slice_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
@@ -15952,6 +15973,8 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
                     abs_offset = 0;
                     rel_end = bigint_as_unsigned(&len_val->data.x_bigint);
                     break;
+                case ConstPtrSpecialFunction:
+                    zig_panic("TODO slice of slice cast from function");
             }
         } else {
             zig_unreachable();
@@ -16021,6 +16044,9 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
                     parent_ptr->type->data.pointer.child_type,
                     parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
                     slice_is_const(return_type));
+                break;
+            case ConstPtrSpecialFunction:
+                zig_panic("TODO");
         }
 
         ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
test/cases/misc.zig
@@ -660,3 +660,10 @@ test "slicing zero length array" {
     assert(mem.eql(u8, s1, ""));
     assert(mem.eql(u32, s2, []u32{}));
 }
+
+
+const addr1 = @ptrCast(&const u8, emptyFn);
+test "comptime cast fn to ptr" {
+    const addr2 = @ptrCast(&const u8, emptyFn);
+    comptime assert(addr1 == addr2);
+}