parent
b65203f573
commit
f0b6dac1f2
@ -583,6 +583,7 @@ enum CastOp {
|
||||
CastOpNumLitToConcrete,
|
||||
CastOpErrSet,
|
||||
CastOpBitCast,
|
||||
CastOpPtrOfArrayToSlice,
|
||||
};
|
||||
|
||||
struct AstNodeFnCallExpr {
|
||||
|
@ -2530,7 +2530,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
assert(wanted_type->data.structure.is_slice);
|
||||
assert(actual_type->id == TypeTableEntryIdArray);
|
||||
|
||||
TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
|
||||
TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
|
||||
|
||||
|
||||
@ -2576,6 +2576,29 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
return expr_val;
|
||||
case CastOpBitCast:
|
||||
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
|
||||
case CastOpPtrOfArrayToSlice: {
|
||||
assert(cast_instruction->tmp_ptr);
|
||||
assert(actual_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *array_type = actual_type->data.pointer.child_type;
|
||||
assert(array_type->id == TypeTableEntryIdArray);
|
||||
|
||||
LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
|
||||
slice_ptr_index, "");
|
||||
LLVMValueRef indices[] = {
|
||||
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
|
||||
LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false),
|
||||
};
|
||||
LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, "");
|
||||
gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false);
|
||||
|
||||
LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
|
||||
slice_len_index, "");
|
||||
LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
|
||||
array_type->data.array.len, false);
|
||||
gen_store_untyped(g, len_value, len_field_ptr, 0, false);
|
||||
|
||||
return cast_instruction->tmp_ptr;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -3815,7 +3838,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
|
||||
} else {
|
||||
end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false);
|
||||
}
|
||||
|
||||
if (want_runtime_safety) {
|
||||
add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val);
|
||||
if (instruction->end) {
|
||||
|
122
src/ir.cpp
122
src/ir.cpp
@ -108,6 +108,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
|
||||
static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
|
||||
static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
|
||||
static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
|
||||
static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align);
|
||||
|
||||
ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
|
||||
assert(const_val->type->id == TypeTableEntryIdPointer);
|
||||
@ -8024,6 +8025,33 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira,
|
||||
}
|
||||
}
|
||||
|
||||
// implicit *[N]T to [*]T
|
||||
if (expected_type->id == TypeTableEntryIdPointer &&
|
||||
expected_type->data.pointer.ptr_len == PtrLenUnknown &&
|
||||
actual_type->id == TypeTableEntryIdPointer &&
|
||||
actual_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
|
||||
types_match_const_cast_only(ira, expected_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
|
||||
// implicit *[N]T to []T
|
||||
if (is_slice(expected_type) &&
|
||||
actual_type->id == TypeTableEntryIdPointer &&
|
||||
actual_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
|
||||
{
|
||||
TypeTableEntry *slice_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(slice_ptr_type->id == TypeTableEntryIdPointer);
|
||||
if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ImplicitCastMatchResultYes;
|
||||
}
|
||||
}
|
||||
|
||||
// implicit [N]T to ?[]const T
|
||||
if (expected_type->id == TypeTableEntryIdMaybe &&
|
||||
is_slice(expected_type->data.maybe.child_type) &&
|
||||
@ -8699,6 +8727,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
zig_unreachable();
|
||||
case CastOpErrSet:
|
||||
case CastOpBitCast:
|
||||
case CastOpPtrOfArrayToSlice:
|
||||
zig_panic("TODO");
|
||||
case CastOpNoop:
|
||||
{
|
||||
@ -8786,6 +8815,63 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *value, TypeTableEntry *wanted_type)
|
||||
{
|
||||
assert(value->value.type->id == TypeTableEntryIdPointer);
|
||||
wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
|
||||
if (pointee->special != ConstValSpecialRuntime) {
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
result->value.type = wanted_type;
|
||||
result->value.data.x_ptr.special = ConstPtrSpecialBaseArray;
|
||||
result->value.data.x_ptr.mut = value->value.data.x_ptr.mut;
|
||||
result->value.data.x_ptr.data.base_array.array_val = pointee;
|
||||
result->value.data.x_ptr.data.base_array.elem_index = 0;
|
||||
result->value.data.x_ptr.data.base_array.is_cstr = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
|
||||
wanted_type, value, CastOpBitCast);
|
||||
result->value.type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *value, TypeTableEntry *wanted_type)
|
||||
{
|
||||
wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment);
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value);
|
||||
if (pointee->special != ConstValSpecialRuntime) {
|
||||
assert(value->value.type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *array_type = value->value.type->data.pointer.child_type;
|
||||
assert(is_slice(wanted_type));
|
||||
bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const;
|
||||
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const);
|
||||
result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut =
|
||||
value->value.data.x_ptr.mut;
|
||||
result->value.type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node,
|
||||
wanted_type, value, CastOpPtrOfArrayToSlice);
|
||||
result->value.type = wanted_type;
|
||||
ir_add_alloca(ira, result, wanted_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool is_container(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdStruct ||
|
||||
type->id == TypeTableEntryIdEnum ||
|
||||
@ -9937,6 +10023,35 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
}
|
||||
}
|
||||
|
||||
// explicit *[N]T to [*]T
|
||||
if (wanted_type->id == TypeTableEntryIdPointer &&
|
||||
wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
|
||||
actual_type->id == TypeTableEntryIdPointer &&
|
||||
actual_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
|
||||
actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
|
||||
types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
|
||||
// explicit *[N]T to []T
|
||||
if (is_slice(wanted_type) &&
|
||||
actual_type->id == TypeTableEntryIdPointer &&
|
||||
actual_type->data.pointer.ptr_len == PtrLenSingle &&
|
||||
actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
|
||||
{
|
||||
TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
assert(slice_ptr_type->id == TypeTableEntryIdPointer);
|
||||
if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
|
||||
actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk)
|
||||
{
|
||||
return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// explicit cast from child type of maybe type to maybe type
|
||||
if (wanted_type->id == TypeTableEntryIdMaybe) {
|
||||
TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
|
||||
@ -13150,6 +13265,13 @@ static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, ui
|
||||
ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count);
|
||||
}
|
||||
|
||||
static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align) {
|
||||
assert(is_slice(slice_type));
|
||||
TypeTableEntry *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry,
|
||||
new_align);
|
||||
return get_slice_type(g, ptr_type);
|
||||
}
|
||||
|
||||
static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrLen ptr_len) {
|
||||
assert(ptr_type->id == TypeTableEntryIdPointer);
|
||||
return get_pointer_to_type_extra(g,
|
||||
|
@ -384,3 +384,19 @@ test "const slice widen cast" {
|
||||
|
||||
assert(@bitCast(u32, bytes) == 0x12121212);
|
||||
}
|
||||
|
||||
test "single-item pointer of array to slice and to unknown length pointer" {
|
||||
testCastPtrOfArrayToSliceAndPtr();
|
||||
comptime testCastPtrOfArrayToSliceAndPtr();
|
||||
}
|
||||
|
||||
fn testCastPtrOfArrayToSliceAndPtr() void {
|
||||
var array = "ao" ++ "eu"; // TODO https://github.com/ziglang/zig/issues/1076
|
||||
const x: [*]u8 = &array;
|
||||
x[0] += 1;
|
||||
assert(mem.eql(u8, array[0..], "boeu"));
|
||||
const y: []u8 = &array;
|
||||
y[0] += 1;
|
||||
assert(mem.eql(u8, array[0..], "coeu"));
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user