diff --git a/src/all_types.hpp b/src/all_types.hpp index c671682363..14a44ea768 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -144,6 +144,9 @@ enum ConstPtrSpecial { // understand the value of pointee at compile time. However, we will still // emit a binary with a compile time known address. // In this case index is the numeric address value. + // We also use this for null pointer. We need the data layout for ConstCastOnly == true + // types to be the same, so all nullables of pointer types use x_ptr + // instead of x_nullable ConstPtrSpecialHardCodedAddr, // This means that the pointer represents memory of assigning to _. // That is, storing discards the data, and loading is invalid. @@ -251,7 +254,7 @@ struct ConstExprValue { bool x_bool; ConstBoundFnValue x_bound_fn; TypeTableEntry *x_type; - ConstExprValue *x_maybe; + ConstExprValue *x_nullable; ConstErrValue x_err_union; ErrorTableEntry *x_err_set; BigInt x_enum_tag; diff --git a/src/analyze.cpp b/src/analyze.cpp index 84f1473ea1..16b2cb0590 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4578,6 +4578,52 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { return true; } +static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { + uint32_t hash_val = 0; + switch (const_val->data.x_ptr.mut) { + case ConstPtrMutRuntimeVar: + hash_val += (uint32_t)3500721036; + break; + case ConstPtrMutComptimeConst: + hash_val += (uint32_t)4214318515; + break; + case ConstPtrMutComptimeVar: + hash_val += (uint32_t)1103195694; + break; + } + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + hash_val += (uint32_t)2478261866; + hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee); + return hash_val; + case ConstPtrSpecialBaseArray: + hash_val += (uint32_t)1764906839; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492; + return hash_val; + case ConstPtrSpecialBaseStruct: + hash_val += (uint32_t)3518317043; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); + return hash_val; + case ConstPtrSpecialHardCodedAddr: + hash_val += (uint32_t)4048518294; + hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); + return hash_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(); +} + static uint32_t hash_const_val(ConstExprValue *const_val) { assert(const_val->special == ConstValSpecialStatic); switch (const_val->type->id) { @@ -4646,51 +4692,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { 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; - switch (const_val->data.x_ptr.mut) { - case ConstPtrMutRuntimeVar: - hash_val += (uint32_t)3500721036; - break; - case ConstPtrMutComptimeConst: - hash_val += (uint32_t)4214318515; - break; - case ConstPtrMutComptimeVar: - hash_val += (uint32_t)1103195694; - break; - } - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - hash_val += (uint32_t)2478261866; - hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee); - return hash_val; - case ConstPtrSpecialBaseArray: - hash_val += (uint32_t)1764906839; - hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); - hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); - hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492; - return hash_val; - case ConstPtrSpecialBaseStruct: - hash_val += (uint32_t)3518317043; - hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); - hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); - return hash_val; - case ConstPtrSpecialHardCodedAddr: - hash_val += (uint32_t)4048518294; - hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); - return hash_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(); - } + return hash_const_val_ptr(const_val); case TypeTableEntryIdPromise: // TODO better hashing algorithm return 223048345; @@ -4708,10 +4710,14 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { // TODO better hashing algorithm return 2709806591; case TypeTableEntryIdMaybe: - if (const_val->data.x_maybe) { - return hash_const_val(const_val->data.x_maybe) * 1992916303; + if (get_codegen_ptr_type(const_val->type) != nullptr) { + return hash_const_val(const_val) * 1992916303; } else { - return 4016830364; + if (const_val->data.x_nullable) { + return hash_const_val(const_val->data.x_nullable) * 1992916303; + } else { + return 4016830364; + } } case TypeTableEntryIdErrorUnion: // TODO better hashing algorithm @@ -4812,9 +4818,11 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { return false; case TypeTableEntryIdMaybe: - if (value->data.x_maybe == nullptr) + if (get_codegen_ptr_type(value->type) != nullptr) + return value->data.x_ptr.mut == ConstPtrMutComptimeVar; + if (value->data.x_nullable == nullptr) return false; - return can_mutate_comptime_var_state(value->data.x_maybe); + return can_mutate_comptime_var_state(value->data.x_nullable); case TypeTableEntryIdErrorUnion: if (value->data.x_err_union.err != nullptr) @@ -5340,6 +5348,52 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) { return var->is_comptime->value.data.x_bool; } +bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { + if (a->data.x_ptr.special != b->data.x_ptr.special) + return false; + if (a->data.x_ptr.mut != b->data.x_ptr.mut) + return false; + switch (a->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) + return false; + return true; + case ConstPtrSpecialBaseArray: + if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val && + a->data.x_ptr.data.base_array.array_val->global_refs != + b->data.x_ptr.data.base_array.array_val->global_refs) + { + return false; + } + if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) + return false; + if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr) + return false; + return true; + case ConstPtrSpecialBaseStruct: + if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val && + a->data.x_ptr.data.base_struct.struct_val->global_refs != + b->data.x_ptr.data.base_struct.struct_val->global_refs) + { + return false; + } + if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) + return false; + return true; + case ConstPtrSpecialHardCodedAddr: + if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) + return false; + 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(); +} + bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { assert(a->type->id == b->type->id); assert(a->special == ConstValSpecialStatic); @@ -5391,49 +5445,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { 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) - return false; - switch (a->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) - return false; - return true; - case ConstPtrSpecialBaseArray: - if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val && - a->data.x_ptr.data.base_array.array_val->global_refs != - b->data.x_ptr.data.base_array.array_val->global_refs) - { - return false; - } - if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) - return false; - if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr) - return false; - return true; - case ConstPtrSpecialBaseStruct: - if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val && - a->data.x_ptr.data.base_struct.struct_val->global_refs != - b->data.x_ptr.data.base_struct.struct_val->global_refs) - { - return false; - } - if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) - return false; - return true; - case ConstPtrSpecialHardCodedAddr: - if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) - return false; - 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(); + return const_values_equal_ptr(a, b); case TypeTableEntryIdArray: zig_panic("TODO"); case TypeTableEntryIdStruct: @@ -5449,10 +5461,12 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { case TypeTableEntryIdNull: zig_panic("TODO"); case TypeTableEntryIdMaybe: - if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) { - return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr); + if (get_codegen_ptr_type(a->type) != nullptr) + return const_values_equal_ptr(a, b); + if (a->data.x_nullable == nullptr || b->data.x_nullable == nullptr) { + return (a->data.x_nullable == nullptr && b->data.x_nullable == nullptr); } else { - return const_values_equal(a->data.x_maybe, b->data.x_maybe); + return const_values_equal(a->data.x_nullable, b->data.x_nullable); } case TypeTableEntryIdErrorUnion: zig_panic("TODO"); @@ -5525,6 +5539,41 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * } } +void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeTableEntry *type_entry) { + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + case ConstPtrSpecialBaseStruct: + buf_appendf(buf, "*"); + render_const_value(g, buf, const_ptr_pointee(g, const_val)); + return; + case ConstPtrSpecialBaseArray: + if (const_val->data.x_ptr.data.base_array.is_cstr) { + buf_appendf(buf, "*(c str lit)"); + return; + } else { + buf_appendf(buf, "*"); + render_const_value(g, buf, const_ptr_pointee(g, const_val)); + return; + } + case ConstPtrSpecialHardCodedAddr: + buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name), + const_val->data.x_ptr.data.hard_coded_addr.addr); + return; + 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(); +} + void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -5601,38 +5650,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { return; } case TypeTableEntryIdPointer: - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - case ConstPtrSpecialBaseStruct: - buf_appendf(buf, "&"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); - return; - case ConstPtrSpecialBaseArray: - if (const_val->data.x_ptr.data.base_array.is_cstr) { - buf_appendf(buf, "&(c str lit)"); - return; - } else { - buf_appendf(buf, "&"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); - return; - } - case ConstPtrSpecialHardCodedAddr: - buf_appendf(buf, "(&%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name), - const_val->data.x_ptr.data.hard_coded_addr.addr); - return; - 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(); + return render_const_val_ptr(g, buf, const_val, type_entry); case TypeTableEntryIdBlock: { AstNode *node = const_val->data.x_block->source_node; @@ -5692,8 +5710,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case TypeTableEntryIdMaybe: { - if (const_val->data.x_maybe) { - render_const_value(g, buf, const_val->data.x_maybe); + if (get_codegen_ptr_type(const_val->type) != nullptr) + return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); + if (const_val->data.x_nullable) { + render_const_value(g, buf, const_val->data.x_nullable); } else { buf_appendf(buf, "null"); } diff --git a/src/codegen.cpp b/src/codegen.cpp index fab2ad659e..65b465a519 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5020,6 +5020,79 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef return LLVMTypeOf(val) != type_entry->type_ref; } +static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) { + render_const_val_global(g, const_val, name); + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + { + ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee; + render_const_val(g, pointee, ""); + render_const_val_global(g, pointee, ""); + ConstExprValue *other_val = pointee; + const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + assert(array_const_val->type->id == TypeTableEntryIdArray); + if (array_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, + elem_index); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseStruct: + { + ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; + assert(struct_const_val->type->id == TypeTableEntryIdStruct); + if (struct_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; + size_t gen_field_index = + struct_const_val->type->data.structure.fields[src_field_index].gen_index; + LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, + gen_field_index); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialHardCodedAddr: + { + uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false), + const_val->type->type_ref); + 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(); +} + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { TypeTableEntry *type_entry = const_val->type; assert(!type_entry->zero_bits); @@ -5068,19 +5141,15 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c { TypeTableEntry *child_type = type_entry->data.maybe.child_type; if (child_type->zero_bits) { - return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false); + return LLVMConstInt(LLVMInt1Type(), const_val->data.x_nullable ? 1 : 0, false); } else if (type_is_codegen_pointer(child_type)) { - if (const_val->data.x_maybe) { - return gen_const_val(g, const_val->data.x_maybe, ""); - } else { - return LLVMConstNull(child_type->type_ref); - } + return gen_const_val_ptr(g, const_val, name); } else { LLVMValueRef child_val; LLVMValueRef maybe_val; bool make_unnamed_struct; - if (const_val->data.x_maybe) { - child_val = gen_const_val(g, const_val->data.x_maybe, ""); + if (const_val->data.x_nullable) { + child_val = gen_const_val(g, const_val->data.x_nullable, ""); maybe_val = LLVMConstAllOnes(LLVMInt1Type()); make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val); @@ -5270,78 +5339,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c 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); - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - { - ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - ConstExprValue *other_val = pointee; - const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - assert(array_const_val->type->id == TypeTableEntryIdArray); - if (array_const_val->type->zero_bits) { - // make this a null pointer - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), - const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, - elem_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); - const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); - return ptr_val; - } - case ConstPtrSpecialBaseStruct: - { - ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; - assert(struct_const_val->type->id == TypeTableEntryIdStruct); - if (struct_const_val->type->zero_bits) { - // make this a null pointer - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), - const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; - size_t gen_field_index = - struct_const_val->type->data.structure.fields[src_field_index].gen_index; - LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, - gen_field_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); - const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); - return ptr_val; - } - case ConstPtrSpecialHardCodedAddr: - { - uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false), - const_val->type->type_ref); - 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(); + return gen_const_val_ptr(g, const_val, name); case TypeTableEntryIdErrorUnion: { TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; diff --git a/src/ir.cpp b/src/ir.cpp index e62ec71875..13ecfd4233 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -62,6 +62,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, + ConstCastResultIdNullWrapPtr, }; struct ConstCastErrSetMismatch { @@ -90,6 +91,7 @@ struct ConstCastOnly { ConstCastOnly *error_union_error_set; ConstCastOnly *return_type; ConstCastOnly *async_allocator_type; + ConstCastOnly *null_wrap_ptr_child; ConstCastArg fn_arg; ConstCastArgNoAlias arg_no_alias; } data; @@ -7660,6 +7662,21 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry if (expected_type == actual_type) return result; + // * and [*] can do a const-cast-only to ?* and ?[*], respectively + if (expected_type->id == TypeTableEntryIdMaybe && + expected_type->data.maybe.child_type->id == TypeTableEntryIdPointer && + actual_type->id == TypeTableEntryIdPointer) + { + ConstCastOnly child = types_match_const_cast_only(ira, + expected_type->data.maybe.child_type, actual_type, source_node); + if (child.id != ConstCastResultIdOk) { + result.id = ConstCastResultIdNullWrapPtr; + result.data.null_wrap_ptr_child = allocate_nonzero(1); + *result.data.null_wrap_ptr_child = child; + } + return result; + } + // pointer const if (expected_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer && @@ -8741,7 +8758,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, zig_panic("TODO"); case CastOpNoop: { - copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic); + bool same_global_refs = other_val->special == ConstValSpecialStatic; + copy_const_val(const_val, other_val, same_global_refs); const_val->type = new_type; break; } @@ -9189,9 +9207,13 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); - const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_maybe = val; + if (get_codegen_ptr_type(wanted_type) != nullptr) { + copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); + } else { + const_instruction->base.value.data.x_nullable = val; + } + const_instruction->base.value.type = wanted_type; return &const_instruction->base; } @@ -9346,9 +9368,14 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so assert(val); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); - const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_maybe = nullptr; + if (get_codegen_ptr_type(wanted_type) != nullptr) { + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; + } else { + const_instruction->base.value.data.x_nullable = nullptr; + } + const_instruction->base.value.type = wanted_type; return &const_instruction->base; } @@ -10062,7 +10089,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } - // explicit cast from child type of maybe type to maybe type + // explicit cast from T to ?T + // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism if (wanted_type->id == TypeTableEntryIdMaybe) { TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) { @@ -10113,7 +10141,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // explicit cast from [N]T to %[]const T + // explicit cast from [N]T to E![]const T if (wanted_type->id == TypeTableEntryIdErrorUnion && is_slice(wanted_type->data.error_union.payload_type) && actual_type->id == TypeTableEntryIdArray) @@ -10143,7 +10171,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); } - // explicit cast from T to %?T + // explicit cast from T to E!?T if (wanted_type->id == TypeTableEntryIdErrorUnion && wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && actual_type->id != TypeTableEntryIdMaybe) @@ -10167,7 +10195,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } // explicit cast from number literal to another type - // explicit cast from number literal to &const integer + // explicit cast from number literal to *const integer if (actual_type->id == TypeTableEntryIdComptimeFloat || actual_type->id == TypeTableEntryIdComptimeInt) { @@ -10391,6 +10419,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst); + result->value.type = child_type; return result; } } @@ -10708,6 +10737,16 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { } } +static bool nullable_value_is_null(ConstExprValue *val) { + assert(val->special == ConstValSpecialStatic); + if (get_codegen_ptr_type(val->type) != nullptr) { + return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else { + return val->data.x_nullable == nullptr; + } +} + static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { IrInstruction *op1 = bin_op_instruction->op1->other; IrInstruction *op2 = bin_op_instruction->op2->other; @@ -10737,7 +10776,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp ConstExprValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad); if (!maybe_val) return ira->codegen->builtin_types.entry_invalid; - bool is_null = (maybe_val->data.x_maybe == nullptr); + bool is_null = nullable_value_is_null(maybe_val); ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base); out_val->data.x_bool = (op_id == IrBinOpCmpEq) ? is_null : !is_null; return ira->codegen->builtin_types.entry_bool; @@ -12015,7 +12054,9 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_maybe = nullptr; + assert(get_codegen_ptr_type(nullable_type) != nullptr); + out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + out_val->data.x_ptr.data.hard_coded_addr.addr = 0; return nullable_type; } IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, @@ -14207,6 +14248,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { IrInstruction *ptr = load_ptr_instruction->ptr->other; + if (type_is_invalid(ptr->value.type)) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr); ir_link_new_instruction(result, &load_ptr_instruction->base); assert(result->value.type); @@ -14773,7 +14817,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn return ira->codegen->builtin_types.entry_invalid; ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_bool = (maybe_val->data.x_maybe != nullptr); + out_val->data.x_bool = !nullable_value_is_null(maybe_val); return ira->codegen->builtin_types.entry_bool; } @@ -14837,13 +14881,18 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val); if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - if (!maybe_val->data.x_maybe) { + if (nullable_value_is_null(maybe_val)) { ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null")); return ira->codegen->builtin_types.entry_invalid; } ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base); out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_maybe; + out_val->data.x_ptr.mut = val->data.x_ptr.mut; + if (type_is_codegen_pointer(child_type)) { + out_val->data.x_ptr.data.ref.pointee = maybe_val; + } else { + out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_nullable; + } return result_type; } } @@ -16206,12 +16255,12 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop 0, 0); fn_def_fields[6].type = get_maybe_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) { - fn_def_fields[6].data.x_maybe = create_const_vals(1); + fn_def_fields[6].data.x_nullable = create_const_vals(1); ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name); - init_const_slice(ira->codegen, fn_def_fields[6].data.x_maybe, lib_name, 0, buf_len(fn_node->lib_name), true); + init_const_slice(ira->codegen, fn_def_fields[6].data.x_nullable, lib_name, 0, buf_len(fn_node->lib_name), true); + } else { + fn_def_fields[6].data.x_nullable = nullptr; } - else - fn_def_fields[6].data.x_maybe = nullptr; // return_type: type ensure_field_index(fn_def_val->type, "return_type", 7); fn_def_fields[7].special = ConstValSpecialStatic; @@ -16664,8 +16713,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField"); - for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) - { + for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; ConstExprValue *union_field_val = &union_field_array->data.x_array.s_none.elements[union_field_index]; @@ -16676,12 +16724,11 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].special = ConstValSpecialStatic; inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type); - if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) - inner_fields[1].data.x_maybe = nullptr; - else - { - inner_fields[1].data.x_maybe = create_const_vals(1); - make_enum_field_val(inner_fields[1].data.x_maybe, union_field->enum_field, type_info_enum_field_type); + if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) { + inner_fields[1].data.x_nullable = nullptr; + } else { + inner_fields[1].data.x_nullable = create_const_vals(1); + make_enum_field_val(inner_fields[1].data.x_nullable, union_field->enum_field, type_info_enum_field_type); } inner_fields[2].special = ConstValSpecialStatic; @@ -16737,8 +16784,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); - for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) - { + for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) { TypeStructField *struct_field = &type_entry->data.structure.fields[struct_field_index]; ConstExprValue *struct_field_val = &struct_field_array->data.x_array.s_none.elements[struct_field_index]; @@ -16749,15 +16795,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].special = ConstValSpecialStatic; inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize); - if (!type_has_bits(struct_field->type_entry)) - inner_fields[1].data.x_maybe = nullptr; - else - { + if (!type_has_bits(struct_field->type_entry)) { + inner_fields[1].data.x_nullable = nullptr; + } else { size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index); - inner_fields[1].data.x_maybe = create_const_vals(1); - inner_fields[1].data.x_maybe->special = ConstValSpecialStatic; - inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize; - bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset); + inner_fields[1].data.x_nullable = create_const_vals(1); + inner_fields[1].data.x_nullable->special = ConstValSpecialStatic; + inner_fields[1].data.x_nullable->type = ira->codegen->builtin_types.entry_usize; + bigint_init_unsigned(&inner_fields[1].data.x_nullable->data.x_bigint, byte_offset); } inner_fields[2].special = ConstValSpecialStatic; @@ -19008,9 +19053,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->builtin_types.entry_invalid; - if (target->value.type->id == TypeTableEntryIdMaybe) { - val = val->data.x_maybe; - } if (val->type->id == TypeTableEntryIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope, instruction->base.source_node, usize); @@ -19936,6 +19978,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) { TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); instruction->value.type = instruction_type; + if (instruction->other) { instruction->other->value.type = instruction_type; } else { diff --git a/test/cases/cast.zig b/test/cases/cast.zig index c3ef24cd78..da3cba7d80 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -1,5 +1,6 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; +const std = @import("std"); +const assert = std.debug.assert; +const mem = std.mem; test "int to ptr cast" { const x = usize(13); @@ -400,3 +401,8 @@ fn testCastPtrOfArrayToSliceAndPtr() void { assert(mem.eql(u8, array[0..], "coeu")); } +test "cast *[1][*]const u8 to [*]const ?[*]const u8" { + const window_name = [1][*]const u8{c"window name"}; + const x: [*]const ?[*]const u8 = &window_name; + assert(mem.eql(u8, std.cstr.toSliceConst(??x[0]), "window name")); +}