authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-08 00:59:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-05-08 00:59:21-07:00
log18ed87c695398a1fbe972d0f8d212365a9832883
treea7338cd8326d3ab7876001420884a4723344c3da
parentaed96e35126eb6bb6c280f6517f59b5f17d7e61e

ability to cast u8 slice to bigger slice


4 files changed, 57 insertions(+), 14 deletions(-)

src/analyze.cpp+4-5
......@@ -4240,17 +4240,16 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
42404240 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpToUnknownSizeArray, true);
42414241 }
42424242
4243 // explicit cast from []T to []u8
4244 if (is_slice(wanted_type) &&
4245 is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) &&
4246 is_slice(actual_type) &&
4243 // explicit cast from []T to []u8 or []u8 to []T
4244 if (is_slice(wanted_type) && is_slice(actual_type) &&
4245 (is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) ||
4246 is_u8(actual_type->data.structure.fields[0].type_entry->data.pointer.child_type)) &&
42474247 (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
42484248 !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const))
42494249 {
42504250 return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true);
42514251 }
42524252
4253
42544253 // explicit cast from pointer to another pointer
42554254 if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) &&
42564255 (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn))
src/codegen.cpp+36-9
......@@ -888,6 +888,8 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
888888
889889 TypeTableEntry *actual_pointer_type = actual_type->data.structure.fields[0].type_entry;
890890 TypeTableEntry *actual_child_type = actual_pointer_type->data.pointer.child_type;
891 TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry;
892 TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
891893
892894 set_debug_source_node(g, node);
893895
......@@ -896,15 +898,6 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
896898 int wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
897899 int wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
898900
899 LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, "");
900 LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, "");
901 LLVMValueRef src_size = LLVMConstInt(g->builtin_types.entry_isize->type_ref,
902 type_size(g, actual_child_type), false);
903 LLVMValueRef new_len = LLVMBuildMul(g->builder, src_len, src_size, "");
904 LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
905 wanted_len_index, "");
906 LLVMBuildStore(g->builder, new_len, dest_len_ptr);
907
908901 LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_ptr_index, "");
909902 LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, "");
910903 LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr,
......@@ -913,6 +906,40 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
913906 wanted_ptr_index, "");
914907 LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr);
915908
909 LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, "");
910 LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, "");
911 uint64_t src_size = type_size(g, actual_child_type);
912 uint64_t dest_size = type_size(g, wanted_child_type);
913
914 LLVMValueRef new_len;
915 if (dest_size == 1) {
916 LLVMValueRef src_size_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref, src_size, false);
917 new_len = LLVMBuildMul(g->builder, src_len, src_size_val, "");
918 } else if (src_size == 1) {
919 LLVMValueRef dest_size_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref, dest_size, false);
920 if (want_debug_safety(g, node)) {
921 LLVMValueRef remainder_val = LLVMBuildURem(g->builder, src_len, dest_size_val, "");
922 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_isize->type_ref);
923 LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
924 LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenOk");
925 LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SliceWidenFail");
926 LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
927
928 LLVMPositionBuilderAtEnd(g->builder, fail_block);
929 gen_debug_safety_crash(g);
930
931 LLVMPositionBuilderAtEnd(g->builder, ok_block);
932 }
933 new_len = ZigLLVMBuildExactUDiv(g->builder, src_len, dest_size_val, "");
934 } else {
935 zig_unreachable();
936 }
937
938 LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr,
939 wanted_len_index, "");
940 LLVMBuildStore(g->builder, new_len, dest_len_ptr);
941
942
916943 return cast_expr->tmp_ptr;
917944 }
918945 case CastOpIntToFloat:
test/run_tests.cpp+10
......@@ -1466,6 +1466,16 @@ fn div_exact(a: i32, b: i32) -> i32 {
14661466}
14671467 )SOURCE");
14681468
1469 add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(
1470pub fn main(args: [][]u8) -> %void {
1471 widen_slice([]u8{1, 2, 3, 4, 5});
1472}
1473#static_eval_enable(false)
1474fn widen_slice(slice: []u8) -> []i32 {
1475 ([]i32)(slice)
1476}
1477 )SOURCE");
1478
14691479}
14701480
14711481//////////////////////////////////////////////////////////////////////////////
test/self_hosted.zig+7
......@@ -1593,6 +1593,13 @@ fn cast_slice_to_u8_slice() {
15931593 bytes[6] = 0;
15941594 bytes[7] = 0;
15951595 assert(big_thing_slice[1] == 0);
1596 const big_thing_again = ([]i32)(bytes);
1597 assert(big_thing_again[2] == 3);
1598 big_thing_again[2] = -1;
1599 assert(bytes[8] == @max_value(u8));
1600 assert(bytes[9] == @max_value(u8));
1601 assert(bytes[10] == @max_value(u8));
1602 assert(bytes[11] == @max_value(u8));
15961603}
15971604
15981605#attribute("test")