| ... | ... | @@ -398,6 +398,7 @@ TypeTableEntry *get_pointer_to_type_extra(CodeGen *g, TypeTableEntry *child_type |
| 398 | 398 | |
| 399 | 399 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); |
| 400 | 400 | entry->is_copyable = true; |
| 401 | entry->can_mutate_state_through_it = is_const ? child_type->can_mutate_state_through_it : true; |
| 401 | 402 | |
| 402 | 403 | const char *const_str = is_const ? "const " : ""; |
| 403 | 404 | const char *volatile_str = is_volatile ? "volatile " : ""; |
| ... | ... | @@ -482,6 +483,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 482 | 483 | assert(child_type->type_ref || child_type->zero_bits); |
| 483 | 484 | assert(child_type->di_type); |
| 484 | 485 | entry->is_copyable = type_is_copyable(g, child_type); |
| 486 | entry->can_mutate_state_through_it = child_type->can_mutate_state_through_it; |
| 485 | 487 | |
| 486 | 488 | buf_resize(&entry->name, 0); |
| 487 | 489 | buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); |
| ... | ... | @@ -572,6 +574,7 @@ TypeTableEntry *get_error_union_type(CodeGen *g, TypeTableEntry *err_set_type, T |
| 572 | 574 | entry->is_copyable = true; |
| 573 | 575 | assert(payload_type->di_type); |
| 574 | 576 | ensure_complete_type(g, payload_type); |
| 577 | entry->can_mutate_state_through_it = payload_type->can_mutate_state_through_it; |
| 575 | 578 | |
| 576 | 579 | buf_resize(&entry->name, 0); |
| 577 | 580 | buf_appendf(&entry->name, "%s!%s", buf_ptr(&err_set_type->name), buf_ptr(&payload_type->name)); |
| ... | ... | @@ -730,6 +733,7 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *ptr_type) { |
| 730 | 733 | |
| 731 | 734 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); |
| 732 | 735 | entry->is_copyable = true; |
| 736 | entry->can_mutate_state_through_it = ptr_type->can_mutate_state_through_it; |
| 733 | 737 | |
| 734 | 738 | // replace the & with [] to go from a ptr type name to a slice type name |
| 735 | 739 | buf_resize(&entry->name, 0); |
| ... | ... | @@ -1735,6 +1739,8 @@ TypeTableEntry *get_struct_type(CodeGen *g, const char *type_name, const char *f |
| 1735 | 1739 | struct_type->data.structure.gen_field_count += 1; |
| 1736 | 1740 | } else { |
| 1737 | 1741 | field->gen_index = SIZE_MAX; |
| 1742 | struct_type->can_mutate_state_through_it = struct_type->can_mutate_state_through_it || |
| 1743 | field->type_entry->can_mutate_state_through_it; |
| 1738 | 1744 | } |
| 1739 | 1745 | |
| 1740 | 1746 | auto prev_entry = struct_type->data.structure.fields_by_name.put_unique(field->name, field); |
| ... | ... | @@ -2475,6 +2481,9 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 2475 | 2481 | if (!type_has_bits(field_type)) |
| 2476 | 2482 | continue; |
| 2477 | 2483 | |
| 2484 | struct_type->can_mutate_state_through_it = struct_type->can_mutate_state_through_it || |
| 2485 | field_type->can_mutate_state_through_it; |
| 2486 | |
| 2478 | 2487 | if (gen_field_index == 0) { |
| 2479 | 2488 | if (struct_type->data.structure.layout == ContainerLayoutPacked) { |
| 2480 | 2489 | struct_type->data.structure.abi_alignment = 1; |
| ... | ... | @@ -2662,6 +2671,8 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2662 | 2671 | } |
| 2663 | 2672 | } |
| 2664 | 2673 | union_field->type_entry = field_type; |
| 2674 | union_type->can_mutate_state_through_it = union_type->can_mutate_state_through_it || |
| 2675 | field_type->can_mutate_state_through_it; |
| 2665 | 2676 | |
| 2666 | 2677 | if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { |
| 2667 | 2678 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, |
| ... | ... | @@ -4565,6 +4576,23 @@ bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { |
| 4565 | 4576 | return true; |
| 4566 | 4577 | } |
| 4567 | 4578 | |
| 4579 | bool fn_eval_cacheable(Scope *scope) { |
| 4580 | while (scope) { |
| 4581 | if (scope->id == ScopeIdVarDecl) { |
| 4582 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; |
| 4583 | if (var_scope->var->value->type->can_mutate_state_through_it) |
| 4584 | return false; |
| 4585 | } else if (scope->id == ScopeIdFnDef) { |
| 4586 | return true; |
| 4587 | } else { |
| 4588 | zig_unreachable(); |
| 4589 | } |
| 4590 | |
| 4591 | scope = scope->parent; |
| 4592 | } |
| 4593 | zig_unreachable(); |
| 4594 | } |
| 4595 | |
| 4568 | 4596 | uint32_t fn_eval_hash(Scope* scope) { |
| 4569 | 4597 | uint32_t result = 0; |
| 4570 | 4598 | while (scope) { |