mirror of
https://github.com/ziglang/zig.git
synced 2026-01-05 04:53:17 +00:00
don't memoize comptime fn calls that access comptime mutable state
closes #827
This commit is contained in:
parent
1bf2810f33
commit
5834ff0cc5
@ -1174,13 +1174,6 @@ struct TypeTableEntry {
|
||||
bool is_copyable;
|
||||
bool gen_h_loop_flag;
|
||||
|
||||
// This is denormalized data. The simplest type that has this
|
||||
// flag set to true is a mutable pointer. A const pointer has
|
||||
// the same value for this flag as the child type.
|
||||
// If a struct has any fields that have this flag true, then
|
||||
// the flag is true for the struct.
|
||||
bool can_mutate_state_through_it;
|
||||
|
||||
union {
|
||||
TypeTableEntryPointer pointer;
|
||||
TypeTableEntryInt integral;
|
||||
|
||||
@ -398,7 +398,6 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer);
|
||||
entry->is_copyable = true;
|
||||
entry->can_mutate_state_through_it = is_const ? child_type->can_mutate_state_through_it : true;
|
||||
|
||||
const char *const_str = is_const ? "const " : "";
|
||||
const char *volatile_str = is_volatile ? "volatile " : "";
|
||||
@ -483,7 +482,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
|
||||
assert(child_type->type_ref || child_type->zero_bits);
|
||||
assert(child_type->di_type);
|
||||
entry->is_copyable = type_is_copyable(g, child_type);
|
||||
entry->can_mutate_state_through_it = child_type->can_mutate_state_through_it;
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
|
||||
@ -574,7 +572,6 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T
|
||||
entry->is_copyable = true;
|
||||
assert(payload_type->di_type);
|
||||
ensure_complete_type(g, payload_type);
|
||||
entry->can_mutate_state_through_it = payload_type->can_mutate_state_through_it;
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name));
|
||||
@ -733,7 +730,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) {
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct);
|
||||
entry->is_copyable = true;
|
||||
entry->can_mutate_state_through_it = ptr_type->can_mutate_state_through_it;
|
||||
|
||||
// replace the & with [] to go from a ptr type name to a slice type name
|
||||
buf_resize(&entry->name, 0);
|
||||
@ -1739,8 +1735,6 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f
|
||||
struct_type->data.structure.gen_field_count += 1;
|
||||
} else {
|
||||
field->gen_index = SIZE_MAX;
|
||||
struct_type->can_mutate_state_through_it = struct_type->can_mutate_state_through_it ||
|
||||
field->type_entry->can_mutate_state_through_it;
|
||||
}
|
||||
|
||||
auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field);
|
||||
@ -2481,9 +2475,6 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
struct_type->can_mutate_state_through_it = struct_type->can_mutate_state_through_it ||
|
||||
field_type->can_mutate_state_through_it;
|
||||
|
||||
if (gen_field_index == 0) {
|
||||
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
|
||||
struct_type->data.structure.abi_alignment = 1;
|
||||
@ -2671,8 +2662,6 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
}
|
||||
}
|
||||
union_field->type_entry = field_type;
|
||||
union_type->can_mutate_state_through_it = union_type->can_mutate_state_through_it ||
|
||||
field_type->can_mutate_state_through_it;
|
||||
|
||||
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
|
||||
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
|
||||
@ -4576,11 +4565,77 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool can_mutate_comptime_var_state(ConstExprValue *value) {
|
||||
assert(value != nullptr);
|
||||
switch (value->type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdOpaque:
|
||||
case TypeTableEntryIdPromise:
|
||||
case TypeTableEntryIdErrorSet:
|
||||
case TypeTableEntryIdEnum:
|
||||
return false;
|
||||
|
||||
case TypeTableEntryIdPointer:
|
||||
return value->data.x_ptr.mut == ConstPtrMutComptimeVar;
|
||||
|
||||
case TypeTableEntryIdArray:
|
||||
if (value->type->data.array.len == 0)
|
||||
return false;
|
||||
if (value->data.x_array.special == ConstArraySpecialUndef)
|
||||
return false;
|
||||
for (uint32_t i = 0; i < value->type->data.array.len; i += 1) {
|
||||
if (can_mutate_comptime_var_state(&value->data.x_array.s_none.elements[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case TypeTableEntryIdStruct:
|
||||
for (uint32_t i = 0; i < value->type->data.structure.src_field_count; i += 1) {
|
||||
if (can_mutate_comptime_var_state(&value->data.x_struct.fields[i]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case TypeTableEntryIdMaybe:
|
||||
if (value->data.x_maybe == nullptr)
|
||||
return false;
|
||||
return can_mutate_comptime_var_state(value->data.x_maybe);
|
||||
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
if (value->data.x_err_union.err != nullptr)
|
||||
return false;
|
||||
assert(value->data.x_err_union.payload != nullptr);
|
||||
return can_mutate_comptime_var_state(value->data.x_err_union.payload);
|
||||
|
||||
case TypeTableEntryIdUnion:
|
||||
return can_mutate_comptime_var_state(value->data.x_union.payload);
|
||||
|
||||
case TypeTableEntryIdArgTuple:
|
||||
zig_panic("TODO var args at comptime is currently not supported");
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool fn_eval_cacheable(Scope *scope) {
|
||||
while (scope) {
|
||||
if (scope->id == ScopeIdVarDecl) {
|
||||
ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
|
||||
if (var_scope->var->value->type->can_mutate_state_through_it)
|
||||
if (can_mutate_comptime_var_state(var_scope->var->value))
|
||||
return false;
|
||||
} else if (scope->id == ScopeIdFnDef) {
|
||||
return true;
|
||||
|
||||
@ -486,3 +486,20 @@ test "comptime slice of pointer preserves comptime var" {
|
||||
assert(buff[0..][0..][0] == 1);
|
||||
}
|
||||
}
|
||||
|
||||
const SingleFieldStruct = struct {
|
||||
x: i32,
|
||||
|
||||
fn read_x(self: &const SingleFieldStruct) i32 {
|
||||
return self.x;
|
||||
}
|
||||
};
|
||||
test "const ptr to comptime mutable data is not memoized" {
|
||||
|
||||
comptime {
|
||||
var foo = SingleFieldStruct {.x = 1};
|
||||
assert(foo.read_x() == 1);
|
||||
foo.x = 2;
|
||||
assert(foo.read_x() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user