diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-12-21 14:11:16 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-12-21 14:11:16 -0500 |
| commit | bc95c63cf227226861d7fbf63fa6c779fed8abf8 (patch) | |
| tree | 1e004f521047ead2fb52855da7bc4fa819020548 /src/ir.cpp | |
| parent | 51cbd968203f348051b8c2bdc005ca5294a79ceb (diff) | |
| parent | 290dc5d95b986464a5be91bb3fd0ada2dd0840ae (diff) | |
| download | zig-bc95c63cf227226861d7fbf63fa6c779fed8abf8.tar.gz zig-bc95c63cf227226861d7fbf63fa6c779fed8abf8.zip | |
Merge pull request #3940 from ziglang/sentinel-slicing
fix std.mem.addNullByte and implement sentinel slicing
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 112 |
1 files changed, 100 insertions, 12 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index 3000269ad3..d60fe9ea70 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2967,18 +2967,21 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou } static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, ResultLoc *result_loc) + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, IrInstruction *sentinel, + bool safety_check_on, ResultLoc *result_loc) { IrInstructionSliceSrc *instruction = ir_build_instruction<IrInstructionSliceSrc>(irb, scope, source_node); instruction->ptr = ptr; instruction->start = start; instruction->end = end; + instruction->sentinel = sentinel; instruction->safety_check_on = safety_check_on; instruction->result_loc = result_loc; ir_ref_instruction(ptr, irb->current_basic_block); ir_ref_instruction(start, irb->current_basic_block); if (end) ir_ref_instruction(end, irb->current_basic_block); + if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); return &instruction->base; } @@ -8483,6 +8486,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, AstNode *array_node = slice_expr->array_ref_expr; AstNode *start_node = slice_expr->start; AstNode *end_node = slice_expr->end; + AstNode *sentinel_node = slice_expr->sentinel; IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); if (ptr_value == irb->codegen->invalid_instruction) @@ -8501,7 +8505,17 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, end_value = nullptr; } - IrInstruction *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, true, result_loc); + IrInstruction *sentinel_value; + if (sentinel_node) { + sentinel_value = ir_gen_node(irb, sentinel_node, scope); + if (sentinel_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + } else { + sentinel_value = nullptr; + } + + IrInstruction *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, + sentinel_value, true, result_loc); return ir_lval_wrap(irb, scope, slice, lval, result_loc); } @@ -10533,6 +10547,18 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.id = ConstCastResultIdInvalid; return result; } + bool ok_sentinels = + wanted_ptr_type->data.pointer.sentinel == nullptr || + (actual_ptr_type->data.pointer.sentinel != nullptr && + const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, + actual_ptr_type->data.pointer.sentinel)); + if (!ok_sentinels) { + result.id = ConstCastResultIdPtrSentinel; + result.data.bad_ptr_sentinel = allocate_nonzero<ConstCastPtrSentinel>(1); + result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; + result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; + return result; + } if ((!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && @@ -14441,6 +14467,32 @@ static bool optional_value_is_null(ZigValue *val) { } } +static void set_optional_value_to_null(ZigValue *val) { + assert(val->special == ConstValSpecialStatic); + if (val->type->id == ZigTypeIdNull) return; // nothing to do + assert(val->type->id == ZigTypeIdOptional); + if (get_codegen_ptr_type(val->type) != nullptr) { + val->data.x_ptr.special = ConstPtrSpecialNull; + } else if (is_opt_err_set(val->type)) { + val->data.x_err_set = nullptr; + } else { + val->data.x_optional = nullptr; + } +} + +static void set_optional_payload(ZigValue *opt_val, ZigValue *payload) { + assert(opt_val->special == ConstValSpecialStatic); + assert(opt_val->type->id == ZigTypeIdOptional); + if (payload == nullptr) { + set_optional_value_to_null(opt_val); + } else if (is_opt_err_set(opt_val->type)) { + assert(payload->type->id == ZigTypeIdErrorSet); + opt_val->data.x_err_set = payload->data.x_err_set; + } else { + opt_val->data.x_optional = payload; + } +} + static IrInstruction *ir_evaluate_bin_op_cmp(IrAnalyze *ira, ZigType *resolved_type, ZigValue *op1_val, ZigValue *op2_val, IrInstructionBinOp *bin_op_instruction, IrBinOp op_id, bool one_possible_value) { @@ -19313,6 +19365,20 @@ static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_ali ptr_type->data.pointer.sentinel); } +static ZigType *adjust_ptr_sentinel(CodeGen *g, ZigType *ptr_type, ZigValue *new_sentinel) { + assert(ptr_type->id == ZigTypeIdPointer); + return get_pointer_to_type_extra2(g, + ptr_type->data.pointer.child_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, + ptr_type->data.pointer.ptr_len, + ptr_type->data.pointer.explicit_alignment, + ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes, + ptr_type->data.pointer.allow_zero, + ptr_type->data.pointer.vector_index, + ptr_type->data.pointer.inferred_struct_field, + new_sentinel); +} + static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) { assert(is_slice(slice_type)); ZigType *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index]->type_entry, @@ -22691,7 +22757,7 @@ static ZigValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_type_ent fields[6]->special = ConstValSpecialStatic; if (attrs_type->data.pointer.child_type->id != ZigTypeIdOpaque) { fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type); - fields[6]->data.x_optional = attrs_type->data.pointer.sentinel; + set_optional_payload(fields[6], attrs_type->data.pointer.sentinel); } else { fields[6]->type = ira->codegen->builtin_types.entry_null; } @@ -25051,50 +25117,72 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction end = nullptr; } - ZigType *return_type; + ZigType *non_sentinel_slice_ptr_type; + ZigType *elem_type; if (array_type->id == ZigTypeIdArray) { + elem_type = array_type->data.array.child_type; bool is_comptime_const = ptr_ptr->value->special == ConstValSpecialStatic && ptr_ptr->value->data.x_ptr.mut == ConstPtrMutComptimeConst; - ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.array.child_type, + non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, ptr_ptr_type->data.pointer.is_const || is_comptime_const, ptr_ptr_type->data.pointer.is_volatile, PtrLenUnknown, ptr_ptr_type->data.pointer.explicit_alignment, 0, 0, false); - return_type = get_slice_type(ira->codegen, slice_ptr_type); } else if (array_type->id == ZigTypeIdPointer) { if (array_type->data.pointer.ptr_len == PtrLenSingle) { ZigType *main_type = array_type->data.pointer.child_type; if (main_type->id == ZigTypeIdArray) { - ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, - main_type->data.pointer.child_type, + elem_type = main_type->data.pointer.child_type; + non_sentinel_slice_ptr_type = get_pointer_to_type_extra(ira->codegen, + elem_type, array_type->data.pointer.is_const, array_type->data.pointer.is_volatile, PtrLenUnknown, array_type->data.pointer.explicit_alignment, 0, 0, false); - return_type = get_slice_type(ira->codegen, slice_ptr_type); } else { ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer")); return ira->codegen->invalid_instruction; } } else { + elem_type = array_type->data.pointer.child_type; if (array_type->data.pointer.ptr_len == PtrLenC) { array_type = adjust_ptr_len(ira->codegen, array_type, PtrLenUnknown); } - return_type = get_slice_type(ira->codegen, array_type); + ZigType *maybe_sentineled_slice_ptr_type = array_type; + non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); if (!end) { ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value")); return ira->codegen->invalid_instruction; } } } else if (is_slice(array_type)) { - ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; - return_type = get_slice_type(ira->codegen, ptr_type); + ZigType *maybe_sentineled_slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry; + non_sentinel_slice_ptr_type = adjust_ptr_sentinel(ira->codegen, maybe_sentineled_slice_ptr_type, nullptr); + elem_type = non_sentinel_slice_ptr_type->data.pointer.child_type; } else { ir_add_error(ira, &instruction->base, buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name))); return ira->codegen->invalid_instruction; } + ZigType *return_type; + ZigValue *sentinel_val = nullptr; + if (instruction->sentinel) { + IrInstruction *uncasted_sentinel = instruction->sentinel->child; + if (type_is_invalid(uncasted_sentinel->value->type)) + return ira->codegen->invalid_instruction; + IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, elem_type); + if (type_is_invalid(sentinel->value->type)) + return ira->codegen->invalid_instruction; + sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); + if (sentinel_val == nullptr) + return ira->codegen->invalid_instruction; + ZigType *slice_ptr_type = adjust_ptr_sentinel(ira->codegen, non_sentinel_slice_ptr_type, sentinel_val); + return_type = get_slice_type(ira->codegen, slice_ptr_type); + } else { + return_type = get_slice_type(ira->codegen, non_sentinel_slice_ptr_type); + } + if (instr_is_comptime(ptr_ptr) && value_is_comptime(casted_start->value) && (!end || value_is_comptime(end->value))) |
