From b980568c810fda4c014da42be8e5108b4cbadb7c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 30 Mar 2020 13:01:53 -0400 Subject: [PATCH] add peer type resolution for mixed-const []T and *[N]T closes #4766 This commit also fixes the implementation of some utility functions for adjusting properties of pointer types. Previously these functions would incorrectly drop vector, sentinel, and inference metadata. --- src/ir.cpp | 78 +++++++++++++++++++++++++++-------- test/stage1/behavior/cast.zig | 15 +++++++ 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/src/ir.cpp b/src/ir.cpp index 3a5c9737ee..b9a14d0fe1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -231,6 +231,7 @@ static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstGen *op); static IrInstSrc *ir_lval_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *value, LVal lval, ResultLoc *result_loc); static IrInstSrc *ir_expr_wrap(IrBuilderSrc *irb, Scope *scope, IrInstSrc *inst, ResultLoc *result_loc); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); +static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ZigValue *val); static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ZigValue *val); @@ -11844,6 +11845,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT bool any_are_null = (prev_inst->value->type->id == ZigTypeIdNull); bool convert_to_const_slice = false; + bool make_the_slice_const = false; for (; i < instruction_count; i += 1) { IrInstGen *cur_inst = instructions[i]; ZigType *cur_type = cur_inst->value->type; @@ -12357,12 +12359,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ? prev_type->data.error_union.payload_type : prev_type; ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || - !cur_type->data.pointer.is_const) && - types_match_const_cast_only(ira, - slice_ptr_type->data.pointer.child_type, + if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { + bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || + !cur_type->data.pointer.is_const); + if (!const_ok) make_the_slice_const = true; convert_to_const_slice = false; continue; } @@ -12391,12 +12393,12 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT break; } ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || - !prev_type->data.pointer.is_const) && - types_match_const_cast_only(ira, - slice_ptr_type->data.pointer.child_type, + if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { + bool const_ok = (slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || + !prev_type->data.pointer.is_const); + if (!const_ok) make_the_slice_const = true; prev_inst = cur_inst; convert_to_const_slice = false; continue; @@ -12408,8 +12410,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT cur_type->data.pointer.child_type->id == ZigTypeIdArray && prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && prev_type->data.pointer.child_type->id == ZigTypeIdArray && - (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const || - prev_type->data.pointer.child_type->data.array.len == 0) && ( prev_type->data.pointer.child_type->data.array.sentinel == nullptr || (cur_type->data.pointer.child_type->data.array.sentinel != nullptr && @@ -12421,6 +12421,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT prev_type->data.pointer.child_type->data.array.child_type, source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) { + bool const_ok = (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const || + prev_type->data.pointer.child_type->data.array.len == 0); + if (!const_ok) make_the_slice_const = true; prev_inst = cur_inst; convert_to_const_slice = true; continue; @@ -12429,8 +12432,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT prev_type->data.pointer.child_type->id == ZigTypeIdArray && cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && cur_type->data.pointer.child_type->id == ZigTypeIdArray && - (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const || - cur_type->data.pointer.child_type->data.array.len == 0) && ( cur_type->data.pointer.child_type->data.array.sentinel == nullptr || (prev_type->data.pointer.child_type->data.array.sentinel != nullptr && @@ -12442,6 +12443,9 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT cur_type->data.pointer.child_type->data.array.child_type, source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) { + bool const_ok = (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const || + cur_type->data.pointer.child_type->data.array.len == 0); + if (!const_ok) make_the_slice_const = true; convert_to_const_slice = true; continue; } @@ -12486,7 +12490,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT src_assert(array_type->id == ZigTypeIdArray, source_node); ZigType *ptr_type = get_pointer_to_type_extra2( ira->codegen, array_type->data.array.child_type, - prev_inst->value->type->data.pointer.is_const, false, + prev_inst->value->type->data.pointer.is_const || make_the_slice_const, false, PtrLenUnknown, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel); @@ -12537,6 +12541,26 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT return ira->codegen->builtin_types.entry_invalid; return get_optional_type(ira->codegen, prev_inst->value->type); } + } else if (make_the_slice_const) { + ZigType *slice_type; + if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { + slice_type = prev_inst->value->type->data.error_union.payload_type; + } else if (is_slice(prev_inst->value->type)) { + slice_type = prev_inst->value->type; + } else { + zig_unreachable(); + } + ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; + ZigType *adjusted_ptr_type = adjust_ptr_const(ira->codegen, slice_ptr_type, make_the_slice_const); + ZigType *adjusted_slice_type = get_slice_type(ira->codegen, adjusted_ptr_type); + if (prev_inst->value->type->id == ZigTypeIdErrorUnion) { + return get_error_union_type(ira->codegen, prev_inst->value->type->data.error_union.err_set_type, + adjusted_slice_type); + } else if (is_slice(prev_inst->value->type)) { + return adjusted_slice_type; + } else { + zig_unreachable(); + } } else { return prev_inst->value->type; } @@ -20708,24 +20732,44 @@ static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new static ZigType *adjust_ptr_len(CodeGen *g, ZigType *ptr_type, PtrLen ptr_len) { assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra(g, + 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_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.allow_zero, + ptr_type->data.pointer.vector_index, + ptr_type->data.pointer.inferred_struct_field, + ptr_type->data.pointer.sentinel); } static ZigType *adjust_ptr_allow_zero(CodeGen *g, ZigType *ptr_type, bool allow_zero) { assert(ptr_type->id == ZigTypeIdPointer); - return get_pointer_to_type_extra(g, + 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, - allow_zero); + allow_zero, + ptr_type->data.pointer.vector_index, + ptr_type->data.pointer.inferred_struct_field, + ptr_type->data.pointer.sentinel); +} + +static ZigType *adjust_ptr_const(CodeGen *g, ZigType *ptr_type, bool is_const) { + assert(ptr_type->id == ZigTypeIdPointer); + return get_pointer_to_type_extra2(g, + ptr_type->data.pointer.child_type, + 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, + ptr_type->data.pointer.sentinel); } static Error compute_elem_align(IrAnalyze *ira, ZigType *elem_type, uint32_t base_ptr_align, diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index b7bcb92c44..0d4836a5a2 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -790,3 +790,18 @@ test "assignment to optional pointer result loc" { var foo: struct { ptr: ?*c_void } = .{ .ptr = &global_struct }; expect(foo.ptr.? == @ptrCast(*c_void, &global_struct)); } + +test "peer type resolve string lit with sentinel-terminated mutable slice" { + var array: [4:0]u8 = undefined; + array[4] = 0; // TODO remove this when #4372 is solved + var slice: [:0]u8 = array[0..4 :0]; + comptime expect(@TypeOf(slice, "hi") == [:0]const u8); + comptime expect(@TypeOf("hi", slice) == [:0]const u8); +} + +test "peer type resolve array pointers, one of them const" { + var array1: [4]u8 = undefined; + const array2: [5]u8 = undefined; + comptime expect(@TypeOf(&array1, &array2) == []const u8); + comptime expect(@TypeOf(&array2, &array1) == []const u8); +}