| author | |
| committer | |
| log | 9d29674711dc4d1b11d4efdad8d0f5a40f56d673 |
| tree | 4f4808cc82e64e2c3696b76b243abb837bf3bc62 |
| parent | 9e0165147e18ffb36bcaf09112c72f4cb397d563 |
6 files changed, 84 insertions(+), 8 deletions(-)
src/all_types.hpp+1| ... | ... | @@ -382,6 +382,7 @@ enum CastOp { |
| 382 | 382 | CastOpIntToFloat, |
| 383 | 383 | CastOpFloatToInt, |
| 384 | 384 | CastOpBoolToInt, |
| 385 | CastOpResizeSlice, | |
| 385 | 386 | }; |
| 386 | 387 | |
| 387 | 388 | struct AstNodeFnCallExpr { |
src/analyze.cpp+30-8| ... | ... | @@ -219,6 +219,23 @@ static bool type_is_complete(TypeTableEntry *type_entry) { |
| 219 | 219 | zig_unreachable(); |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry) { | |
| 223 | if (type_has_bits(type_entry)) { | |
| 224 | return LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); | |
| 225 | } else { | |
| 226 | return 0; | |
| 227 | } | |
| 228 | } | |
| 229 | ||
| 230 | static bool is_u8(TypeTableEntry *type) { | |
| 231 | return type->id == TypeTableEntryIdInt && | |
| 232 | !type->data.integral.is_signed && type->data.integral.bit_count == 8; | |
| 233 | } | |
| 234 | ||
| 235 | static bool is_slice(TypeTableEntry *type) { | |
| 236 | return type->id == TypeTableEntryIdStruct && type->data.structure.is_slice; | |
| 237 | } | |
| 238 | ||
| 222 | 239 | TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 223 | 240 | return get_int_type(g, false, false, bits_needed_for_unsigned(x)); |
| 224 | 241 | } |
| ... | ... | @@ -4215,8 +4232,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 4215 | 4232 | } |
| 4216 | 4233 | |
| 4217 | 4234 | // explicit cast from array to slice |
| 4218 | if (wanted_type->id == TypeTableEntryIdStruct && | |
| 4219 | wanted_type->data.structure.is_slice && | |
| 4235 | if (is_slice(wanted_type) && | |
| 4220 | 4236 | actual_type->id == TypeTableEntryIdArray && |
| 4221 | 4237 | types_match_const_cast_only( |
| 4222 | 4238 | 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 |
| 4225 | 4241 | return resolve_cast(g, context, node, expr_node, wanted_type, CastOpToUnknownSizeArray, true); |
| 4226 | 4242 | } |
| 4227 | 4243 | |
| 4244 | // explicit cast from []T to []u8 | |
| 4245 | if (is_slice(wanted_type) && | |
| 4246 | is_u8(wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type) && | |
| 4247 | is_slice(actual_type) && | |
| 4248 | (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const || | |
| 4249 | !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const)) | |
| 4250 | { | |
| 4251 | return resolve_cast(g, context, node, expr_node, wanted_type, CastOpResizeSlice, true); | |
| 4252 | } | |
| 4253 | ||
| 4254 | ||
| 4228 | 4255 | // explicit cast from pointer to another pointer |
| 4229 | 4256 | if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) && |
| 4230 | 4257 | (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn)) |
| ... | ... | @@ -4757,12 +4784,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4757 | 4784 | buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name))); |
| 4758 | 4785 | return g->builtin_types.entry_invalid; |
| 4759 | 4786 | } else { |
| 4760 | uint64_t size_in_bytes; | |
| 4761 | if (type_has_bits(type_entry)) { | |
| 4762 | size_in_bytes = LLVMStoreSizeOfType(g->target_data_ref, type_entry->type_ref); | |
| 4763 | } else { | |
| 4764 | size_in_bytes = 0; | |
| 4765 | } | |
| 4787 | uint64_t size_in_bytes = type_size(g, type_entry); | |
| 4766 | 4788 | return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, size_in_bytes); |
| 4767 | 4789 | } |
| 4768 | 4790 | } |
src/analyze.hpp+1| ... | ... | @@ -18,6 +18,7 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool |
| 18 | 18 | BlockContext *new_block_context(AstNode *node, BlockContext *parent); |
| 19 | 19 | Expr *get_resolved_expr(AstNode *node); |
| 20 | 20 | bool is_node_void_expr(AstNode *node); |
| 21 | uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry); | |
| 21 | 22 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits); |
| 22 | 23 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits); |
| 23 | 24 | TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); |
src/codegen.cpp+37| ... | ... | @@ -860,6 +860,43 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 860 | 860 | actual_type->data.array.len, false); |
| 861 | 861 | LLVMBuildStore(g->builder, len_val, len_ptr); |
| 862 | 862 | |
| 863 | return cast_expr->tmp_ptr; | |
| 864 | } | |
| 865 | case CastOpResizeSlice: | |
| 866 | { | |
| 867 | assert(cast_expr->tmp_ptr); | |
| 868 | assert(wanted_type->id == TypeTableEntryIdStruct); | |
| 869 | assert(wanted_type->data.structure.is_slice); | |
| 870 | assert(actual_type->id == TypeTableEntryIdStruct); | |
| 871 | assert(actual_type->data.structure.is_slice); | |
| 872 | ||
| 873 | TypeTableEntry *actual_pointer_type = actual_type->data.structure.fields[0].type_entry; | |
| 874 | TypeTableEntry *actual_child_type = actual_pointer_type->data.pointer.child_type; | |
| 875 | ||
| 876 | set_debug_source_node(g, node); | |
| 877 | ||
| 878 | int actual_ptr_index = actual_type->data.structure.fields[0].gen_index; | |
| 879 | int actual_len_index = actual_type->data.structure.fields[1].gen_index; | |
| 880 | int wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index; | |
| 881 | int wanted_len_index = wanted_type->data.structure.fields[1].gen_index; | |
| 882 | ||
| 883 | LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_len_index, ""); | |
| 884 | LLVMValueRef src_len = LLVMBuildLoad(g->builder, src_len_ptr, ""); | |
| 885 | LLVMValueRef src_size = LLVMConstInt(g->builtin_types.entry_isize->type_ref, | |
| 886 | type_size(g, actual_child_type), false); | |
| 887 | LLVMValueRef new_len = LLVMBuildMul(g->builder, src_len, src_size, ""); | |
| 888 | LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, | |
| 889 | wanted_len_index, ""); | |
| 890 | LLVMBuildStore(g->builder, new_len, dest_len_ptr); | |
| 891 | ||
| 892 | LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, expr_val, actual_ptr_index, ""); | |
| 893 | LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); | |
| 894 | LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, | |
| 895 | wanted_type->data.structure.fields[0].type_entry->type_ref, ""); | |
| 896 | LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, | |
| 897 | wanted_ptr_index, ""); | |
| 898 | LLVMBuildStore(g->builder, src_ptr_casted, dest_ptr_ptr); | |
| 899 | ||
| 863 | 900 | return cast_expr->tmp_ptr; |
| 864 | 901 | } |
| 865 | 902 | case CastOpIntToFloat: |
src/eval.cpp+1| ... | ... | @@ -600,6 +600,7 @@ void eval_const_expr_implicit_cast(CastOp cast_op, |
| 600 | 600 | break; |
| 601 | 601 | case CastOpPtrToInt: |
| 602 | 602 | case CastOpIntToPtr: |
| 603 | case CastOpResizeSlice: | |
| 603 | 604 | // can't do it |
| 604 | 605 | break; |
| 605 | 606 | case CastOpToUnknownSizeArray: |
test/self_hosted.zig+14| ... | ... | @@ -1580,3 +1580,17 @@ struct GenNode(T: type) { |
| 1580 | 1580 | next: ?&GenNode(T), |
| 1581 | 1581 | fn get_val(n: &const GenNode(T)) -> T { n.value } |
| 1582 | 1582 | } |
| 1583 | ||
| 1584 | #attribute("test") | |
| 1585 | fn cast_slice_to_u8_slice() { | |
| 1586 | assert(@sizeof(i32) == 4); | |
| 1587 | var big_thing_array = []i32{1, 2, 3, 4}; | |
| 1588 | const big_thing_slice: []i32 = big_thing_array; | |
| 1589 | const bytes = ([]u8)(big_thing_slice); | |
| 1590 | assert(bytes.len == 4 * 4); | |
| 1591 | bytes[4] = 0; | |
| 1592 | bytes[5] = 0; | |
| 1593 | bytes[6] = 0; | |
| 1594 | bytes[7] = 0; | |
| 1595 | assert(big_thing_slice[1] == 0); | |
| 1596 | } |