From 54c065797dd70a621a130c2efa177869c9930105 Mon Sep 17 00:00:00 2001 From: Jonathan Marler Date: Sat, 30 Nov 2019 20:46:19 -0700 Subject: [PATCH] Support sentinel in @Type --- src/all_types.hpp | 2 + src/analyze.cpp | 38 +++++++++------ src/codegen.cpp | 34 +++++++++---- src/ir.cpp | 90 +++++++++++++++++++++++------------ src/ir.hpp | 2 + src/memory_profiling.cpp | 1 + src/memory_profiling.hpp | 1 + test/stage1/behavior/type.zig | 26 ++++++++++ 8 files changed, 142 insertions(+), 52 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index cc11741870a2..83a6510c81a2 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2023,12 +2023,14 @@ struct CodeGen { ZigValue x_null; ZigValue x_unreachable; ZigValue zero_byte; + ZigValue optional_zero_byte; ZigValue *for_undefined(); ZigValue *for_void(); ZigValue *for_null(); ZigValue *for_unreachable(); ZigValue *for_zero_byte(); + ZigValue *for_optional_zero_byte(); } intern; ZigType *align_amt_type; diff --git a/src/analyze.cpp b/src/analyze.cpp index dece277c0329..fe313327706c 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -533,9 +533,10 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con TypeId type_id = {}; ZigType **parent_pointer = nullptr; + ZigValue *sentinel_unwrapped = get_sentinel_value(sentinel); if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr || - sentinel != nullptr) + sentinel_unwrapped != nullptr) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.codegen = g; @@ -577,13 +578,13 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con buf_appendf(&entry->name, "[*"); break; case PtrLenC: - assert(sentinel == nullptr); + assert(sentinel_unwrapped == nullptr); buf_appendf(&entry->name, "[*c]"); break; } - if (sentinel != nullptr) { + if (sentinel_unwrapped != nullptr) { buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, sentinel); + render_const_value(g, &entry->name, sentinel_unwrapped); } switch (ptr_len) { case PtrLenSingle: @@ -775,12 +776,14 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi assert(type_is_resolved(child_type, ResolveStatusSizeKnown)); ZigType *entry = new_type_table_entry(ZigTypeIdArray); + ZigValue *sentinel_unwrapped = get_sentinel_value(sentinel); buf_resize(&entry->name, 0); buf_appendf(&entry->name, "[%" ZIG_PRI_u64, array_size); - if (sentinel != nullptr) { + if (sentinel_unwrapped != nullptr) { + assert(sentinel_unwrapped->type == child_type); buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, sentinel); + render_const_value(g, &entry->name, sentinel_unwrapped); } buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); @@ -788,7 +791,7 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, Zi if (array_size == 0) { full_array_size = 0; } else { - full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); + full_array_size = array_size + ((sentinel_unwrapped != nullptr) ? 1 : 0); } entry->size_in_bits = child_type->size_in_bits * full_array_size; @@ -816,9 +819,12 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { buf_resize(&entry->name, 0); buf_appendf(&entry->name, "["); - if (ptr_type->data.pointer.sentinel != nullptr) { - buf_appendf(&entry->name, ":"); - render_const_value(g, &entry->name, ptr_type->data.pointer.sentinel); + { + ZigValue *sentinel = get_sentinel_value(ptr_type->data.pointer.sentinel); + if (sentinel != nullptr) { + buf_appendf(&entry->name, ":"); + render_const_value(g, &entry->name, sentinel); + } } buf_appendf(&entry->name, "]"); append_ptr_type_attrs(&entry->name, ptr_type); @@ -5660,7 +5666,7 @@ void init_const_str_lit(CodeGen *g, ZigValue *const_val, Buf *str) { // first we build the underlying array ZigValue *array_val = create_const_vals(1); array_val->special = ConstValSpecialStatic; - array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), g->intern.for_zero_byte()); + array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), g->intern.for_optional_zero_byte()); array_val->data.x_array.special = ConstArraySpecialBuf; array_val->data.x_array.data.s_buf = str; @@ -7067,11 +7073,13 @@ uint32_t type_id_hash(TypeId x) { (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) + (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881) * - (x.data.pointer.sentinel ? hash_const_val(x.data.pointer.sentinel) : (uint32_t)2955491856); + (get_sentinel_value(x.data.pointer.sentinel) ? + hash_const_val(get_sentinel_value(x.data.pointer.sentinel)) : (uint32_t)2955491856); case ZigTypeIdArray: return hash_ptr(x.data.array.child_type) * ((uint32_t)x.data.array.size ^ (uint32_t)2122979968) * - (x.data.array.sentinel ? hash_const_val(x.data.array.sentinel) : (uint32_t)1927201585); + (get_sentinel_value(x.data.array.sentinel) ? + hash_const_val(get_sentinel_value(x.data.array.sentinel)) : (uint32_t)1927201585); case ZigTypeIdInt: return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); @@ -8687,7 +8695,9 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) { ZigType *elem_type = type->data.array.child_type; - uint64_t extra_len_from_sentinel = (type->data.array.sentinel != nullptr) ? 1 : 0; + // TODO: should this size be 1 or sizeof sentinel? + ZigValue *sentinel = get_sentinel_value(type->data.array.sentinel); + uint64_t extra_len_from_sentinel = (sentinel != nullptr) ? 1 : 0; uint64_t full_len = type->data.array.len + extra_len_from_sentinel; // TODO https://github.com/ziglang/zig/issues/1424 type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)full_len); diff --git a/src/codegen.cpp b/src/codegen.cpp index 06834a7e4b85..cbd0ecfac818 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3707,7 +3707,9 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI array_type = array_type->data.pointer.child_type; } if (safety_check_on) { - uint64_t extra_len_from_sentinel = (array_type->data.array.sentinel != nullptr) ? 1 : 0; + ZigValue *sentinel = get_sentinel_value(array_type->data.array.sentinel); + // TODO: should this size be 1 or the size of the child element? + uint64_t extra_len_from_sentinel = (sentinel != nullptr) ? 1 : 0; uint64_t full_len = array_type->data.array.len + extra_len_from_sentinel; LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, full_len, false); add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end); @@ -3769,7 +3771,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI assert(len_index != SIZE_MAX); LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, ""); LLVMValueRef len = gen_load_untyped(g, len_ptr, 0, false, ""); - LLVMIntPredicate upper_op = (ptr_type->data.pointer.sentinel != nullptr) ? LLVMIntULE : LLVMIntULT; + LLVMIntPredicate upper_op = (get_sentinel_value(ptr_type->data.pointer.sentinel) != nullptr) ? + LLVMIntULE : LLVMIntULT; add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, upper_op, len); } @@ -6635,8 +6638,8 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ZigValue *const_val, const cha ZigValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; assert(array_const_val->type->id == ZigTypeIdArray); if (!type_has_bits(array_const_val->type)) { - if (array_const_val->type->data.array.sentinel != nullptr) { - ZigValue *pointee = array_const_val->type->data.array.sentinel; + ZigValue *pointee = get_sentinel_value(array_const_val->type->data.array.sentinel); + if (pointee != nullptr) { render_const_val(g, pointee, ""); render_const_val_global(g, pointee, ""); const_val->llvm_value = LLVMConstBitCast(pointee->llvm_global, @@ -6957,7 +6960,9 @@ check: switch (const_val->special) { case ConstArraySpecialUndef: return LLVMGetUndef(get_llvm_type(g, type_entry)); case ConstArraySpecialNone: { - uint64_t extra_len_from_sentinel = (type_entry->data.array.sentinel != nullptr) ? 1 : 0; + ZigValue *sentinel = get_sentinel_value(type_entry->data.array.sentinel); + // TODO: is this supposed to be 1 or sizeof(sentinel)? + uint64_t extra_len_from_sentinel = (sentinel != nullptr) ? 1 : 0; uint64_t full_len = len + extra_len_from_sentinel; LLVMValueRef *values = allocate(full_len); LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type); @@ -6968,8 +6973,8 @@ check: switch (const_val->special) { values[i] = val; make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val); } - if (type_entry->data.array.sentinel != nullptr) { - values[len] = gen_const_val(g, type_entry->data.array.sentinel, ""); + if (sentinel != nullptr) { + values[len] = gen_const_val(g, sentinel, ""); } if (make_unnamed_struct) { return LLVMConstStruct(values, full_len, true); @@ -6980,7 +6985,7 @@ check: switch (const_val->special) { case ConstArraySpecialBuf: { Buf *buf = const_val->data.x_array.data.s_buf; return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), - type_entry->data.array.sentinel == nullptr); + get_sentinel_value(type_entry->data.array.sentinel) == nullptr); } } zig_unreachable(); @@ -8023,6 +8028,12 @@ static void define_intern_values(CodeGen *g) { value.special = ConstValSpecialStatic; bigint_init_unsigned(&value.data.x_bigint, 0); } + { + auto& value = g->intern.optional_zero_byte; + value.type = get_optional_type(g, g->builtin_types.entry_u8); + value.special = ConstValSpecialStatic; + value.data.x_optional = &g->intern.zero_byte; + } } static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name, size_t count) { @@ -10618,3 +10629,10 @@ ZigValue *CodeGen::Intern::for_zero_byte() { #endif return &this->zero_byte; } + +ZigValue *CodeGen::Intern::for_optional_zero_byte() { +#ifdef ZIG_ENABLE_MEM_PROFILE + memprof_intern_count.optional_zero_byte += 1; +#endif + return &this->optional_zero_byte; +} diff --git a/src/ir.cpp b/src/ir.cpp index fbb1f1761eb2..72a0e917c067 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -664,7 +664,7 @@ static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { case ConstPtrSpecialBaseArray: { ZigValue *array_val = const_val->data.x_ptr.data.base_array.array_val; if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) { - result = array_val->type->data.array.sentinel; + result = get_sentinel_value(array_val->type->data.array.sentinel); } else { expand_undef_array(g, array_val); result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; @@ -11904,6 +11904,14 @@ static ZigValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAll return value->value; } +ZigValue *get_sentinel_value(ZigValue *sentinel) +{ + if (sentinel == nullptr) + return nullptr; + assert(sentinel->type->id == ZigTypeIdOptional); + return sentinel->data.x_optional; +} + ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, @@ -13017,12 +13025,15 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa ZigType *actual_type = cast_result->data.bad_ptr_sentinel->actual_type; ZigType *wanted_type = cast_result->data.bad_ptr_sentinel->wanted_type; { + ZigValue *actual_sentinel = get_sentinel_value(actual_type->data.pointer.sentinel); + ZigValue *wanted_sentinel = get_sentinel_value(wanted_type->data.pointer.sentinel); + assert(wanted_sentinel); Buf *txt_msg = buf_sprintf("destination pointer requires a terminating '"); - render_const_value(ira->codegen, txt_msg, wanted_type->data.pointer.sentinel); + render_const_value(ira->codegen, txt_msg, wanted_sentinel); buf_appendf(txt_msg, "' sentinel"); - if (actual_type->data.pointer.sentinel != nullptr) { + if (actual_sentinel != nullptr) { buf_appendf(txt_msg, ", but source pointer has a terminating '"); - render_const_value(ira->codegen, txt_msg, actual_type->data.pointer.sentinel); + render_const_value(ira->codegen, txt_msg, actual_sentinel); buf_appendf(txt_msg, "' sentinel"); } add_error_note(ira->codegen, parent_msg, source_node, txt_msg); @@ -13033,11 +13044,14 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa ZigType *actual_type = cast_result->data.sentinel_arrays->actual_type; ZigType *wanted_type = cast_result->data.sentinel_arrays->wanted_type; Buf *txt_msg = buf_sprintf("destination array requires a terminating '"); - render_const_value(ira->codegen, txt_msg, wanted_type->data.array.sentinel); + ZigValue *actual_sentinel = get_sentinel_value(actual_type->data.array.sentinel); + ZigValue *wanted_sentinel = get_sentinel_value(wanted_type->data.array.sentinel); + assert(wanted_sentinel); + render_const_value(ira->codegen, txt_msg, wanted_sentinel); buf_appendf(txt_msg, "' sentinel"); - if (actual_type->data.array.sentinel != nullptr) { + if (actual_sentinel) { buf_appendf(txt_msg, ", but source array has a terminating '"); - render_const_value(ira->codegen, txt_msg, actual_type->data.array.sentinel); + render_const_value(ira->codegen, txt_msg, actual_sentinel); buf_appendf(txt_msg, "' sentinel"); } add_error_note(ira->codegen, parent_msg, source_node, txt_msg); @@ -13733,7 +13747,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // [:x]T to [*:x]T // [:x]T to [*c]T if (wanted_type->id == ZigTypeIdPointer && is_slice(actual_type) && - ((wanted_type->data.pointer.ptr_len == PtrLenUnknown && wanted_type->data.pointer.sentinel != nullptr) || + ((wanted_type->data.pointer.ptr_len == PtrLenUnknown && get_sentinel_value(wanted_type->data.pointer.sentinel) != nullptr) || wanted_type->data.pointer.ptr_len == PtrLenC)) { ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, @@ -13741,7 +13755,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, slice_ptr_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && - (slice_ptr_type->data.pointer.sentinel != nullptr && + (get_sentinel_value(slice_ptr_type->data.pointer.sentinel) != nullptr && (wanted_type->data.pointer.ptr_len == PtrLenC || const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, slice_ptr_type->data.pointer.sentinel)))) @@ -15492,7 +15506,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i sentinel1 = op1_type->data.array.sentinel; } else if (op1_type->id == ZigTypeIdPointer && op1_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op1_type->data.pointer.sentinel != nullptr && + get_sentinel_value(op1_type->data.pointer.sentinel) != nullptr && op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray) { child_type = op1_type->data.pointer.child_type; @@ -15538,7 +15552,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_end = op2_array_val->type->data.array.len; sentinel2 = op2_type->data.array.sentinel; } else if (op2_type->id == ZigTypeIdPointer && - op2_type->data.pointer.sentinel != nullptr && + get_sentinel_value(op2_type->data.pointer.sentinel) != nullptr && op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray) { op2_type_valid = op2_type->data.pointer.child_type == child_type; @@ -15751,7 +15765,8 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * // TODO optimize the buf case expand_undef_array(ira->codegen, array_val); - size_t extra_null_term = (array_type->data.array.sentinel != nullptr) ? 1 : 0; + // TODO: is this supposed to be 1 or sizeof sentinel value? + size_t extra_null_term = (get_sentinel_value(array_type->data.array.sentinel) != nullptr) ? 1 : 0; out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len + extra_null_term); uint64_t i = 0; @@ -15767,9 +15782,9 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * } assert(i == new_array_len); - if (array_type->data.array.sentinel != nullptr) { + if (get_sentinel_value(array_type->data.array.sentinel) != nullptr) { ZigValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; - copy_const_val(elem_dest_val, array_type->data.array.sentinel); + copy_const_val(elem_dest_val, get_sentinel_value(array_type->data.array.sentinel)); elem_dest_val->parent.id = ConstParentIdArray; elem_dest_val->parent.data.p_array.array_val = out_val; elem_dest_val->parent.data.p_array.elem_index = i; @@ -16687,8 +16702,8 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe // we actually need the result location pointer to *not* have a sentinel. Otherwise the generated // memcpy will write an extra byte to the destination, and THAT'S NO GOOD. ZigType *ptr_elem_type; - if (value_type->id == ZigTypeIdArray && value_type->data.array.sentinel != nullptr && - dest_type->id == ZigTypeIdArray && dest_type->data.array.sentinel == nullptr) + if (value_type->id == ZigTypeIdArray && get_sentinel_value(value_type->data.array.sentinel) != nullptr && + dest_type->id == ZigTypeIdArray && get_sentinel_value(dest_type->data.array.sentinel) == nullptr) { ptr_elem_type = get_array_type(ira->codegen, value_type->data.array.child_type, value_type->data.array.len, nullptr); @@ -18834,10 +18849,10 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct uint64_t index = bigint_as_u64(&casted_elem_index->value->data.x_bigint); if (array_type->id == ZigTypeIdArray) { uint64_t array_len = array_type->data.array.len; - if (index == array_len && array_type->data.array.sentinel != nullptr) { + if (index == array_len && get_sentinel_value(array_type->data.array.sentinel) != nullptr) { ZigType *elem_type = array_type->data.array.child_type; IrInstruction *sentinel_elem = ir_const(ira, &elem_ptr_instruction->base, elem_type); - copy_const_val(sentinel_elem->value, array_type->data.array.sentinel); + copy_const_val(sentinel_elem->value, get_sentinel_value(array_type->data.array.sentinel)); return ir_get_ref(ira, &elem_ptr_instruction->base, sentinel_elem, true, false); } if (index >= array_len) { @@ -18968,7 +18983,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct new_index = index; ZigType *array_type = array_val->type; mem_size = array_type->data.array.len; - if (array_type->data.array.sentinel != nullptr) { + if (get_sentinel_value(array_type->data.array.sentinel) != nullptr) { mem_size += 1; } old_size = mem_size; @@ -18991,7 +19006,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct new_index = offset + index; ZigType *array_type = array_ptr_val->data.x_ptr.data.base_array.array_val->type; mem_size = array_type->data.array.len; - if (array_type->data.array.sentinel != nullptr) { + if (get_sentinel_value(array_type->data.array.sentinel) != nullptr) { mem_size += 1; } old_size = mem_size - offset; @@ -19042,7 +19057,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct ZigType *slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; uint64_t slice_len = bigint_as_u64(&len_field->data.x_bigint); uint64_t full_slice_len = slice_len + - ((slice_ptr_type->data.pointer.sentinel != nullptr) ? 1 : 0); + ((get_sentinel_value(slice_ptr_type->data.pointer.sentinel) != nullptr) ? 1 : 0); if (index >= full_slice_len) { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64, @@ -20200,7 +20215,8 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, IrInstruction *uncasted_sentinel = array_type_instruction->sentinel->child; if (type_is_invalid(uncasted_sentinel->value->type)) return ira->codegen->invalid_instruction; - IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, child_type); + ZigType *sentinel_type = get_optional_type(ira->codegen, child_type); + IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, sentinel_type); if (type_is_invalid(sentinel->value->type)) return ira->codegen->invalid_instruction; sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); @@ -22106,12 +22122,22 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_ent // sentinel: var ensure_field_index(result->type, "sentinel", 6); fields[6]->special = ConstValSpecialStatic; - if (attrs_type->data.pointer.sentinel != nullptr) { - fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type); - fields[6]->data.x_optional = attrs_type->data.pointer.sentinel; + if (attrs_type->data.pointer.sentinel == nullptr) { + if (!type_is_resolved(attrs_type->data.pointer.child_type, ResolveStatusSizeKnown)) { + // HACK working around problem where some types are not resolved, i.e. + // std.debug.Attr and std.elf.SectionHeader + // remove this if branch when fixed + fields[6]->type = ira->codegen->builtin_types.entry_null; + } else { + fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type); + fields[6]->data.x_optional = nullptr; + } } else { - fields[6]->type = ira->codegen->builtin_types.entry_null; - fields[6]->data.x_optional = nullptr; + ZigValue *sentinel = get_sentinel_value(attrs_type->data.pointer.sentinel); + assert(attrs_type->data.pointer.sentinel->type == + get_optional_type(ira->codegen, attrs_type->data.pointer.child_type)); + fields[6]->type = attrs_type->data.pointer.sentinel->type; + fields[6]->data.x_optional = sentinel; } return result; @@ -22235,7 +22261,9 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr fields[1]->data.x_type = type_entry->data.array.child_type; // sentinel: var fields[2]->special = ConstValSpecialStatic; - fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type); + assert(type_entry->data.array.sentinel->type == + get_optional_type(ira->codegen, type_entry->data.array.child_type)); + fields[2]->type = type_entry->data.array.sentinel->type; fields[2]->data.x_optional = type_entry->data.array.sentinel; break; } @@ -28516,7 +28544,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { if (lazy_slice_type->sentinel != nullptr) { if (type_is_invalid(lazy_slice_type->sentinel->value->type)) return ErrorSemanticAnalyzeFail; - IrInstruction *sentinel = ir_implicit_cast(ira, lazy_slice_type->sentinel, elem_type); + ZigType *sentinel_type = get_optional_type(ira->codegen, elem_type); + IrInstruction *sentinel = ir_implicit_cast(ira, lazy_slice_type->sentinel, sentinel_type); if (type_is_invalid(sentinel->value->type)) return ErrorSemanticAnalyzeFail; sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); @@ -28596,7 +28625,8 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ZigValue *val) { if (lazy_ptr_type->sentinel != nullptr) { if (type_is_invalid(lazy_ptr_type->sentinel->value->type)) return ErrorSemanticAnalyzeFail; - IrInstruction *sentinel = ir_implicit_cast(ira, lazy_ptr_type->sentinel, elem_type); + ZigType *sentinel_type = get_optional_type(ira->codegen, elem_type); + IrInstruction *sentinel = ir_implicit_cast(ira, lazy_ptr_type->sentinel, sentinel_type); if (type_is_invalid(sentinel->value->type)) return ErrorSemanticAnalyzeFail; sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); diff --git a/src/ir.hpp b/src/ir.hpp index a20dc2d2321a..d9f7ec75e248 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -18,6 +18,8 @@ enum IrPass { bool ir_gen(CodeGen *g, AstNode *node, Scope *scope, IrExecutable *ir_executable); bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); +ZigValue *get_sentinel_value(ZigValue *sentinel); + ZigValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, diff --git a/src/memory_profiling.cpp b/src/memory_profiling.cpp index 4bd4cea7ba94..388cdeaba570 100644 --- a/src/memory_profiling.cpp +++ b/src/memory_profiling.cpp @@ -145,6 +145,7 @@ void memprof_dump_stats(FILE *file) { fprintf(stderr, "null: interned %zu times\n", memprof_intern_count.x_null); fprintf(stderr, "unreachable: interned %zu times\n", memprof_intern_count.x_unreachable); fprintf(stderr, "zero_byte: interned %zu times\n", memprof_intern_count.zero_byte); + fprintf(stderr, "optional_zero_byte: interned %zu times\n", memprof_intern_count.optional_zero_byte); } #endif diff --git a/src/memory_profiling.hpp b/src/memory_profiling.hpp index 78e77a89f1d1..1dc1e1803fbc 100644 --- a/src/memory_profiling.hpp +++ b/src/memory_profiling.hpp @@ -19,6 +19,7 @@ struct MemprofInternCount { size_t x_null; size_t x_unreachable; size_t zero_byte; + size_t optional_zero_byte; }; extern MemprofInternCount memprof_intern_count; diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index 432a1e0e9454..34952e682f3a 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -72,6 +72,18 @@ test "Type.Pointer" { [*]allowzero volatile u8, [*]allowzero const volatile u8, [*]allowzero align(4) u8, [*]allowzero align(4) const u8, [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, + // The following test cases aren't working + //[*:0]u8, [*:0]const u8, + //[*:0]volatile u8, [*:0]const volatile u8, + //[*:0]align(4) u8, [*:0]align(4) const u8, + //[*:0]align(4) volatile u8, [*:0]align(4) const volatile u8, + //[*:0]align(8) u8, [*:0]align(8) const u8, + //[*:0]align(8) volatile u8, [*:0]align(8) const volatile u8, + //[*:0]allowzero u8, [*:0]allowzero const u8, + //[*:0]allowzero volatile u8, [*:0]allowzero const volatile u8, + //[*:0]allowzero align(4) u8, [*:0]allowzero align(4) const u8, + //[*:0]allowzero align(4) volatile u8, [*:0]allowzero align(4) const volatile u8, + //[*:5]allowzero align(4) volatile u8, [*:5]allowzero align(4) const volatile u8, // Slice Types []u8, []const u8, []volatile u8, []const volatile u8, @@ -83,6 +95,18 @@ test "Type.Pointer" { []allowzero volatile u8, []allowzero const volatile u8, []allowzero align(4) u8, []allowzero align(4) const u8, []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, + // The following test cases aren't working + //[:0]u8, [:0]const u8, + //[:0]volatile u8, [:0]const volatile u8, + //[:0]align(4) u8, [:0]align(4) const u8, + //[:0]align(4) volatile u8, [:0]align(4) const volatile u8, + //[:0]align(8) u8, [:0]align(8) const u8, + //[:0]align(8) volatile u8, [:0]align(8) const volatile u8, + //[:0]allowzero u8, [:0]allowzero const u8, + //[:0]allowzero volatile u8, [:0]allowzero const volatile u8, + //[:0]allowzero align(4) u8, [:0]allowzero align(4) const u8, + //[:0]allowzero align(4) volatile u8, [:0]allowzero align(4) const volatile u8, + //[:4]allowzero align(4) volatile u8, [:4]allowzero align(4) const volatile u8, // C Pointer Types [*c]u8, [*c]const u8, [*c]volatile u8, [*c]const volatile u8, @@ -116,6 +140,8 @@ test "Type.Array" { }, })); testTypes(&[_]type{ [1]u8, [30]usize, [7]bool }); + // these array types with sentinels are not currently working + //testTypes(&[_]type{ [11:0]u8, [4:10]u8 }); } test "Type.ComptimeFloat" {