Commit 6edd81109d
Changed files (5)
test
cases
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;
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");
}
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;
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<ConstCastOnly>(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<IrInstructionConst>(&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<IrInstructionConst>(&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 {
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"));
+}