Skip to content

Commit

Permalink
nullable pointers follow const-casting rules
Browse files Browse the repository at this point in the history
any *T -> ?*T cast is allowed implicitly, even
when it occurs deep inside the type, and the cast
is a no-op at runtime.

in order to add this I had to make the comptime value
representation of nullable pointers the same as the
comptime value representation of normal pointers,
so that we don't have to do any recursive transformation
of values when doing this kind of cast.
  • Loading branch information
andrewrk committed Jun 9, 2018
1 parent 1a9d2f3 commit 6edd811
Show file tree
Hide file tree
Showing 5 changed files with 322 additions and 252 deletions.
5 changes: 4 additions & 1 deletion src/all_types.hpp
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down
280 changes: 150 additions & 130 deletions src/analyze.cpp
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand All @@ -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");
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
}
Expand Down

0 comments on commit 6edd811

Please sign in to comment.