mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
ability to cast slice to u8 slice
This commit is contained in:
parent
9e0165147e
commit
9d29674711
@ -382,6 +382,7 @@ enum CastOp {
|
||||
CastOpIntToFloat,
|
||||
CastOpFloatToInt,
|
||||
CastOpBoolToInt,
|
||||
CastOpResizeSlice,
|
||||
};
|
||||
|
||||
struct AstNodeFnCallExpr {
|
||||
|
||||
@ -219,6 +219,23 @@ static bool type_is_complete(TypeTableEntry *type_entry) {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
if (type_has_bits(type_entry)) {
|
||||
return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_u8(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdInt &&
|
||||
!type->data.integral.is_signed && type->data.integral.bit_count == 8;
|
||||
}
|
||||
|
||||
static bool is_slice(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice;
|
||||
}
|
||||
|
||||
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
|
||||
return get_int_type(g, false, false, bits_needed_for_unsigned(x));
|
||||
}
|
||||
@ -4215,8 +4232,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
|
||||
}
|
||||
|
||||
// explicit cast from array to slice
|
||||
if (wanted_type->id == TypeTableEntryIdStruct &&
|
||||
wanted_type->data.structure.is_slice &&
|
||||
if (is_slice(wanted_type) &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
types_match_const_cast_only(
|
||||
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
|
||||
@ -4225,6 +4241,17 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
|
||||
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpToUnknownSizeArray, true);
|
||||
}
|
||||
|
||||
// explicit cast from []T to []u8
|
||||
if (is_slice(wanted_type) &&
|
||||
is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) &&
|
||||
is_slice(actual_type) &&
|
||||
(wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
|
||||
!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
|
||||
{
|
||||
return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
|
||||
}
|
||||
|
||||
|
||||
// explicit cast from pointer to another pointer
|
||||
if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
|
||||
(wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
|
||||
@ -4757,12 +4784,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
||||
buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
uint64_t size_in_bytes;
|
||||
if (type_has_bits(type_entry)) {
|
||||
size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref);
|
||||
} else {
|
||||
size_in_bytes = 0;
|
||||
}
|
||||
uint64_t size_in_bytes = type_size(g, type_entry);
|
||||
return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, size_in_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
|
||||
Expr *get_resolved_expr(AstNode *node);
|
||||
bool is_node_void_expr(AstNode *node);
|
||||
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
|
||||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits);
|
||||
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits);
|
||||
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
|
||||
|
||||
@ -860,6 +860,43 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
|
||||
actual_type->data.array.len, false);
|
||||
LLVMBuildStore(g->builder, len_val, len_ptr);
|
||||
|
||||
return cast_expr->tmp_ptr;
|
||||
}
|
||||
case CastOpResizeSlice:
|
||||
{
|
||||
assert(cast_expr->tmp_ptr);
|
||||
assert(wanted_type->id == TypeTableEntryIdStruct);
|
||||
assert(wanted_type->data.structure.is_slice);
|
||||
assert(actual_type->id == TypeTableEntryIdStruct);
|
||||
assert(actual_type->data.structure.is_slice);
|
||||
|
||||
TypeTableEntry *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
|
||||
TypeTableEntry *actual_child_type = actual_pointer_type->data.pointer.child_type;
|
||||
|
||||
set_debug_source_node(g, node);
|
||||
|
||||
int actual_ptr_index = actual_type->data.structure.fields[0].gen_index;
|
||||
int actual_len_index = actual_type->data.structure.fields[1].gen_index;
|
||||
int wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
|
||||
int wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
|
||||
|
||||
LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, "");
|
||||
LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, "");
|
||||
LLVMValueRef src_size = LLVMConstInt(g->builtin_types.entry_isize->type_ref,
|
||||
type_size(g, actual_child_type), false);
|
||||
LLVMValueRef new_len = LLVMBuildMul(g->builder, src_len, src_size, "");
|
||||
LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
|
||||
wanted_len_index, "");
|
||||
LLVMBuildStore(g->builder, new_len, dest_len_ptr);
|
||||
|
||||
LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_ptr_index, "");
|
||||
LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
|
||||
LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
|
||||
wanted_type->data.structure.fields[0].type_entry->type_ref, "");
|
||||
LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
|
||||
wanted_ptr_index, "");
|
||||
LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
|
||||
|
||||
return cast_expr->tmp_ptr;
|
||||
}
|
||||
case CastOpIntToFloat:
|
||||
|
||||
@ -600,6 +600,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
break;
|
||||
case CastOpPtrToInt:
|
||||
case CastOpIntToPtr:
|
||||
case CastOpResizeSlice:
|
||||
// can't do it
|
||||
break;
|
||||
case CastOpToUnknownSizeArray:
|
||||
|
||||
@ -1580,3 +1580,17 @@ struct GenNode(T: type) {
|
||||
next: ?&GenNode(T),
|
||||
fn get_val(n: &const GenNode(T)) -> T { n.value }
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn cast_slice_to_u8_slice() {
|
||||
assert(@sizeof(i32) == 4);
|
||||
var big_thing_array = []i32{1, 2, 3, 4};
|
||||
const big_thing_slice: []i32 = big_thing_array;
|
||||
const bytes = ([]u8)(big_thing_slice);
|
||||
assert(bytes.len == 4 * 4);
|
||||
bytes[4] = 0;
|
||||
bytes[5] = 0;
|
||||
bytes[6] = 0;
|
||||
bytes[7] = 0;
|
||||
assert(big_thing_slice[1] == 0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user