authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-18 17:25:29-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-18 17:25:29-04:00
log1aafbae5be518309b4c2194cdc24e22642514519
tree76146de4441517dbb0125364e3423ce3af12a49e
parent5d705fc6e35e75a604d3dbbb377ab01bf2b2b575

remove []u8 casting syntax. add `@bytesToSlice` and `@sliceToBytes`

See #1061

15 files changed, 277 insertions(+), 96 deletions(-)

doc/langref.html.in+33-12
......@@ -1456,8 +1456,7 @@ test "pointer array access" {
14561456 // Taking an address of an individual element gives a
14571457 // pointer to a single item. This kind of pointer
14581458 // does not support pointer arithmetic.
1459
1460 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1459 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
14611460 const ptr = &array[2];
14621461 assert(@typeOf(ptr) == *u8);
14631462
......@@ -1469,7 +1468,7 @@ test "pointer array access" {
14691468test "pointer slicing" {
14701469 // In Zig, we prefer using slices over null-terminated pointers.
14711470 // You can turn an array into a slice using slice syntax:
1472 var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1471 var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
14731472 const slice = array[2..4];
14741473 assert(slice.len == 2);
14751474
......@@ -1541,13 +1540,13 @@ test "pointer casting" {
15411540 // To convert one pointer type to another, use @ptrCast. This is an unsafe
15421541 // operation that Zig cannot protect you against. Use @ptrCast only when other
15431542 // conversions are not possible.
1544 const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
1543 const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
15451544 const u32_ptr = @ptrCast(*const u32, &bytes[0]);
15461545 assert(u32_ptr.* == 0x12121212);
15471546
15481547 // Even this example is contrived - there are better ways to do the above than
15491548 // pointer casting. For example, using a slice narrowing cast:
1550 const u32_value = ([]const u32)(bytes[0..])[0];
1549 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
15511550 assert(u32_value == 0x12121212);
15521551
15531552 // And even another way, the most straightforward way to do it:
......@@ -1630,13 +1629,13 @@ test "function alignment" {
16301629const assert = @import("std").debug.assert;
16311630
16321631test "pointer alignment safety" {
1633 var array align(4) = []u32{0x11111111, 0x11111111};
1634 const bytes = ([]u8)(array[0..]);
1632 var array align(4) = []u32{ 0x11111111, 0x11111111 };
1633 const bytes = @sliceToBytes(array[0..]);
16351634 assert(foo(bytes) == 0x11111111);
16361635}
16371636fn foo(bytes: []u8) u32 {
16381637 const slice4 = bytes[1..5];
1639 const int_slice = ([]u32)(@alignCast(4, slice4));
1638 const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
16401639 return int_slice[0];
16411640}
16421641 {#code_end#}
......@@ -1728,8 +1727,8 @@ test "slice pointer" {
17281727test "slice widening" {
17291728 // Zig supports slice widening and slice narrowing. Cast a slice of u8
17301729 // to a slice of anything else, and Zig will perform the length conversion.
1731 const array align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
1732 const slice = ([]const u32)(array[0..]);
1730 const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
1731 const slice = @bytesToSlice(u32, array[0..]);
17331732 assert(slice.len == 2);
17341733 assert(slice[0] == 0x12121212);
17351734 assert(slice[1] == 0x13131313);
......@@ -4651,6 +4650,18 @@ comptime {
46514650 </p>
46524651 {#header_close#}
46534652
4653 {#header_open|@bytesToSlice#}
4654 <pre><code class="zig">@bytesToSlice(comptime Element: type, bytes: []u8) []Element</code></pre>
4655 <p>
4656 Converts a slice of bytes or array of bytes into a slice of <code>Element</code>.
4657 The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter.
4658 </p>
4659 <p>
4660 Attempting to convert a number of bytes with a length that does not evenly divide into a slice of
4661 elements results in {#link|Undefined Behavior#}.
4662 </p>
4663 {#header_close#}
4664
46544665 {#header_open|@cDefine#}
46554666 <pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>
46564667 <p>
......@@ -5467,8 +5478,9 @@ pub const FloatMode = enum {
54675478 </p>
54685479 {#see_also|@shlExact|@shlWithOverflow#}
54695480 {#header_close#}
5481
54705482 {#header_open|@sizeOf#}
5471 <pre><code class="zig">@sizeOf(comptime T: type) (number literal)</code></pre>
5483 <pre><code class="zig">@sizeOf(comptime T: type) comptime_int</code></pre>
54725484 <p>
54735485 This function returns the number of bytes it takes to store <code>T</code> in memory.
54745486 </p>
......@@ -5476,6 +5488,15 @@ pub const FloatMode = enum {
54765488 The result is a target-specific compile time constant.
54775489 </p>
54785490 {#header_close#}
5491
5492 {#header_open|@sliceToBytes#}
5493 <pre><code class="zig">@sliceToBytes(value: var) []u8</code></pre>
5494 <p>
5495 Converts a slice or array to a slice of <code>u8</code>. The resulting slice has the same
5496 {#link|pointer|Pointers#} properties as the parameter.
5497 </p>
5498 {#header_close#}
5499
54795500 {#header_open|@sqrt#}
54805501 <pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>
54815502 <p>
......@@ -6810,7 +6831,7 @@ hljs.registerLanguage("zig", function(t) {
68106831 a = t.IR + "\\s*\\(",
68116832 c = {
68126833 keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong resume cancel await async orelse",
6813 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
6834 built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast intCast floatCast intToFloat floatToInt boolToInt bytesToSlice sliceToBytes errSetCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall",
68146835 literal: "true false null undefined"
68156836 },
68166837 n = [e, t.CLCM, t.CBCM, s, r];
src/all_types.hpp+28
......@@ -234,6 +234,16 @@ enum RuntimeHintPtr {
234234 RuntimeHintPtrNonStack,
235235};
236236
237enum RuntimeHintSliceId {
238 RuntimeHintSliceIdUnknown,
239 RuntimeHintSliceIdLen,
240};
241
242struct RuntimeHintSlice {
243 enum RuntimeHintSliceId id;
244 uint64_t len;
245};
246
237247struct ConstGlobalRefs {
238248 LLVMValueRef llvm_value;
239249 LLVMValueRef llvm_global;
......@@ -270,6 +280,7 @@ struct ConstExprValue {
270280 RuntimeHintErrorUnion rh_error_union;
271281 RuntimeHintOptional rh_maybe;
272282 RuntimeHintPtr rh_ptr;
283 RuntimeHintSlice rh_slice;
273284 } data;
274285};
275286
......@@ -1360,6 +1371,8 @@ enum BuiltinFnId {
13601371 BuiltinFnIdIntCast,
13611372 BuiltinFnIdFloatCast,
13621373 BuiltinFnIdErrSetCast,
1374 BuiltinFnIdToBytes,
1375 BuiltinFnIdFromBytes,
13631376 BuiltinFnIdIntToFloat,
13641377 BuiltinFnIdFloatToInt,
13651378 BuiltinFnIdBoolToInt,
......@@ -2123,6 +2136,8 @@ enum IrInstructionId {
21232136 IrInstructionIdMarkErrRetTracePtr,
21242137 IrInstructionIdSqrt,
21252138 IrInstructionIdErrSetCast,
2139 IrInstructionIdToBytes,
2140 IrInstructionIdFromBytes,
21262141};
21272142
21282143struct IrInstruction {
......@@ -2665,6 +2680,19 @@ struct IrInstructionErrSetCast {
26652680 IrInstruction *target;
26662681};
26672682
2683struct IrInstructionToBytes {
2684 IrInstruction base;
2685
2686 IrInstruction *target;
2687};
2688
2689struct IrInstructionFromBytes {
2690 IrInstruction base;
2691
2692 IrInstruction *dest_child_type;
2693 IrInstruction *target;
2694};
2695
26682696struct IrInstructionIntToFloat {
26692697 IrInstruction base;
26702698
src/codegen.cpp+4
......@@ -4728,6 +4728,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
47284728 case IrInstructionIdFloatToInt:
47294729 case IrInstructionIdBoolToInt:
47304730 case IrInstructionIdErrSetCast:
4731 case IrInstructionIdFromBytes:
4732 case IrInstructionIdToBytes:
47314733 zig_unreachable();
47324734
47334735 case IrInstructionIdReturn:
......@@ -6358,6 +6360,8 @@ static void define_builtin_fns(CodeGen *g) {
63586360 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
63596361 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
63606362 create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
6363 create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
6364 create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
63616365}
63626366
63636367static const char *bool_to_str(bool b) {
src/ir.cpp+165-52
......@@ -472,6 +472,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) {
472472 return IrInstructionIdErrSetCast;
473473}
474474
475static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytes *) {
476 return IrInstructionIdToBytes;
477}
478
479static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytes *) {
480 return IrInstructionIdFromBytes;
481}
482
475483static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
476484 return IrInstructionIdIntToFloat;
477485}
......@@ -1956,6 +1964,26 @@ static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNod
19561964 return &instruction->base;
19571965}
19581966
1967static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
1968 IrInstructionToBytes *instruction = ir_build_instruction<IrInstructionToBytes>(irb, scope, source_node);
1969 instruction->target = target;
1970
1971 ir_ref_instruction(target, irb->current_basic_block);
1972
1973 return &instruction->base;
1974}
1975
1976static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) {
1977 IrInstructionFromBytes *instruction = ir_build_instruction<IrInstructionFromBytes>(irb, scope, source_node);
1978 instruction->dest_child_type = dest_child_type;
1979 instruction->target = target;
1980
1981 ir_ref_instruction(dest_child_type, irb->current_basic_block);
1982 ir_ref_instruction(target, irb->current_basic_block);
1983
1984 return &instruction->base;
1985}
1986
19591987static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
19601988 IrInstructionIntToFloat *instruction = ir_build_instruction<IrInstructionIntToFloat>(irb, scope, source_node);
19611989 instruction->dest_type = dest_type;
......@@ -4084,6 +4112,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
40844112 IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value);
40854113 return ir_lval_wrap(irb, scope, result, lval);
40864114 }
4115 case BuiltinFnIdFromBytes:
4116 {
4117 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4118 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4119 if (arg0_value == irb->codegen->invalid_instruction)
4120 return arg0_value;
4121
4122 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4123 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4124 if (arg1_value == irb->codegen->invalid_instruction)
4125 return arg1_value;
4126
4127 IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value);
4128 return ir_lval_wrap(irb, scope, result, lval);
4129 }
4130 case BuiltinFnIdToBytes:
4131 {
4132 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4133 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4134 if (arg0_value == irb->codegen->invalid_instruction)
4135 return arg0_value;
4136
4137 IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value);
4138 return ir_lval_wrap(irb, scope, result, lval);
4139 }
40874140 case BuiltinFnIdIntToFloat:
40884141 {
40894142 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -9103,11 +9156,6 @@ static bool is_container(TypeTableEntry *type) {
91039156 type->id == TypeTableEntryIdUnion;
91049157}
91059158
9106static bool is_u8(TypeTableEntry *type) {
9107 return type->id == TypeTableEntryIdInt &&
9108 !type->data.integral.is_signed && type->data.integral.bit_count == 8;
9109}
9110
91119159static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {
91129160 assert(old_bb);
91139161
......@@ -9661,6 +9709,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
96619709 IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
96629710 source_instr->source_node, array_ptr, start, end, false);
96639711 result->value.type = wanted_type;
9712 result->value.data.rh_slice.id = RuntimeHintSliceIdLen;
9713 result->value.data.rh_slice.len = array_type->data.array.len;
96649714 ir_add_alloca(ira, result, result->value.type);
96659715
96669716 return result;
......@@ -10103,7 +10153,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1010310153 return ira->codegen->invalid_instruction;
1010410154 }
1010510155
10106 // explicit match or non-const to const
10156 // perfect match or non-const to const
1010710157 if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false).id == ConstCastResultIdOk) {
1010810158 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
1010910159 }
......@@ -10214,52 +10264,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1021410264 }
1021510265 }
1021610266
10217 // explicit cast from []T to []u8 or []u8 to []T
10218 if (is_slice(wanted_type) && is_slice(actual_type)) {
10219 TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
10220 TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
10221 if ((is_u8(wanted_ptr_type->data.pointer.child_type) || is_u8(actual_ptr_type->data.pointer.child_type)) &&
10222 (wanted_ptr_type->data.pointer.is_const || !actual_ptr_type->data.pointer.is_const))
10223 {
10224 uint32_t src_align_bytes = get_ptr_align(actual_ptr_type);
10225 uint32_t dest_align_bytes = get_ptr_align(wanted_ptr_type);
10226
10227 if (dest_align_bytes > src_align_bytes) {
10228 ErrorMsg *msg = ir_add_error(ira, source_instr,
10229 buf_sprintf("cast increases pointer alignment"));
10230 add_error_note(ira->codegen, msg, source_instr->source_node,
10231 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), src_align_bytes));
10232 add_error_note(ira->codegen, msg, source_instr->source_node,
10233 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), dest_align_bytes));
10234 return ira->codegen->invalid_instruction;
10235 }
10236
10237 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
10238 return ira->codegen->invalid_instruction;
10239 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
10240 }
10241 }
10242
10243 // explicit cast from [N]u8 to []const T
10244 if (is_slice(wanted_type) &&
10245 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const &&
10246 actual_type->id == TypeTableEntryIdArray &&
10247 is_u8(actual_type->data.array.child_type))
10248 {
10249 if (!ir_emit_global_runtime_side_effect(ira, source_instr))
10250 return ira->codegen->invalid_instruction;
10251 uint64_t child_type_size = type_size(ira->codegen,
10252 wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type);
10253 if (actual_type->data.array.len % child_type_size == 0) {
10254 return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true);
10255 } else {
10256 ir_add_error_node(ira, source_instr->source_node,
10257 buf_sprintf("unable to convert %s to %s: size mismatch",
10258 buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
10259 return ira->codegen->invalid_instruction;
10260 }
10261 }
10262
1026310267 // explicit *[N]T to [*]T
1026410268 if (wanted_type->id == TypeTableEntryIdPointer &&
1026510269 wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
......@@ -17644,6 +17648,109 @@ static TypeTableEntry *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrIns
1764417648 return dest_type;
1764517649}
1764617650
17651static TypeTableEntry *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
17652 TypeTableEntry *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->other);
17653 if (type_is_invalid(dest_child_type))
17654 return ira->codegen->builtin_types.entry_invalid;
17655
17656 IrInstruction *target = instruction->target->other;
17657 if (type_is_invalid(target->value.type))
17658 return ira->codegen->builtin_types.entry_invalid;
17659
17660 bool src_ptr_const;
17661 bool src_ptr_volatile;
17662 uint32_t src_ptr_align;
17663 if (target->value.type->id == TypeTableEntryIdPointer) {
17664 src_ptr_const = target->value.type->data.pointer.is_const;
17665 src_ptr_volatile = target->value.type->data.pointer.is_volatile;
17666 src_ptr_align = target->value.type->data.pointer.alignment;
17667 } else if (is_slice(target->value.type)) {
17668 TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
17669 src_ptr_const = src_ptr_type->data.pointer.is_const;
17670 src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
17671 src_ptr_align = src_ptr_type->data.pointer.alignment;
17672 } else {
17673 src_ptr_const = true;
17674 src_ptr_volatile = false;
17675 src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
17676 }
17677
17678 TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
17679 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
17680 src_ptr_align, 0, 0);
17681 TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
17682
17683 TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
17684 src_ptr_const, src_ptr_volatile, PtrLenUnknown,
17685 src_ptr_align, 0, 0);
17686 TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
17687
17688 IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
17689 if (type_is_invalid(casted_value->value.type))
17690 return ira->codegen->builtin_types.entry_invalid;
17691
17692 bool have_known_len = false;
17693 uint64_t known_len;
17694
17695 if (instr_is_comptime(casted_value)) {
17696 ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
17697 if (!val)
17698 return ira->codegen->builtin_types.entry_invalid;
17699
17700 ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index];
17701 if (value_is_comptime(len_val)) {
17702 known_len = bigint_as_unsigned(&len_val->data.x_bigint);
17703 have_known_len = true;
17704 }
17705 }
17706
17707 if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) {
17708 known_len = casted_value->value.data.rh_slice.len;
17709 have_known_len = true;
17710 }
17711
17712 if (have_known_len) {
17713 uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
17714 uint64_t remainder = known_len % child_type_size;
17715 if (remainder != 0) {
17716 ErrorMsg *msg = ir_add_error(ira, &instruction->base,
17717 buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch",
17718 known_len, buf_ptr(&dest_slice_type->name)));
17719 add_error_note(ira->codegen, msg, instruction->dest_child_type->source_node,
17720 buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64,
17721 buf_ptr(&dest_child_type->name), child_type_size, remainder));
17722 return ira->codegen->builtin_types.entry_invalid;
17723 }
17724 }
17725
17726 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
17727 ir_link_new_instruction(result, &instruction->base);
17728 return dest_slice_type;
17729}
17730
17731static TypeTableEntry *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
17732 IrInstruction *target = instruction->target->other;
17733 if (type_is_invalid(target->value.type))
17734 return ira->codegen->builtin_types.entry_invalid;
17735
17736 if (!is_slice(target->value.type)) {
17737 ir_add_error(ira, instruction->target,
17738 buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name)));
17739 return ira->codegen->builtin_types.entry_invalid;
17740 }
17741
17742 TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
17743
17744 TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
17745 src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
17746 src_ptr_type->data.pointer.alignment, 0, 0);
17747 TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
17748
17749 IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
17750 ir_link_new_instruction(result, &instruction->base);
17751 return dest_slice_type;
17752}
17753
1764717754static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
1764817755 TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
1764917756 if (type_is_invalid(dest_type))
......@@ -20246,6 +20353,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
2024620353 return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);
2024720354 case IrInstructionIdErrSetCast:
2024820355 return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction);
20356 case IrInstructionIdFromBytes:
20357 return ir_analyze_instruction_from_bytes(ira, (IrInstructionFromBytes *)instruction);
20358 case IrInstructionIdToBytes:
20359 return ir_analyze_instruction_to_bytes(ira, (IrInstructionToBytes *)instruction);
2024920360 case IrInstructionIdIntToFloat:
2025020361 return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
2025120362 case IrInstructionIdFloatToInt:
......@@ -20601,6 +20712,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
2060120712 case IrInstructionIdIntToFloat:
2060220713 case IrInstructionIdFloatToInt:
2060320714 case IrInstructionIdBoolToInt:
20715 case IrInstructionIdFromBytes:
20716 case IrInstructionIdToBytes:
2060420717 return false;
2060520718
2060620719 case IrInstructionIdAsm:
src/ir_print.cpp+20
......@@ -672,6 +672,20 @@ static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruc
672672 fprintf(irp->f, ")");
673673}
674674
675static void ir_print_from_bytes(IrPrint *irp, IrInstructionFromBytes *instruction) {
676 fprintf(irp->f, "@bytesToSlice(");
677 ir_print_other_instruction(irp, instruction->dest_child_type);
678 fprintf(irp->f, ", ");
679 ir_print_other_instruction(irp, instruction->target);
680 fprintf(irp->f, ")");
681}
682
683static void ir_print_to_bytes(IrPrint *irp, IrInstructionToBytes *instruction) {
684 fprintf(irp->f, "@sliceToBytes(");
685 ir_print_other_instruction(irp, instruction->target);
686 fprintf(irp->f, ")");
687}
688
675689static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
676690 fprintf(irp->f, "@intToFloat(");
677691 ir_print_other_instruction(irp, instruction->dest_type);
......@@ -1472,6 +1486,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
14721486 case IrInstructionIdErrSetCast:
14731487 ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction);
14741488 break;
1489 case IrInstructionIdFromBytes:
1490 ir_print_from_bytes(irp, (IrInstructionFromBytes *)instruction);
1491 break;
1492 case IrInstructionIdToBytes:
1493 ir_print_to_bytes(irp, (IrInstructionToBytes *)instruction);
1494 break;
14751495 case IrInstructionIdIntToFloat:
14761496 ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
14771497 break;
std/heap.zig+1-1
......@@ -221,7 +221,7 @@ pub const ArenaAllocator = struct {
221221 if (len >= actual_min_size) break;
222222 }
223223 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
224 const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
224 const buf_node_slice = @bytesToSlice(BufNode, buf[0..@sizeOf(BufNode)]);
225225 const buf_node = &buf_node_slice[0];
226226 buf_node.* = BufNode{
227227 .data = buf,
std/macho.zig+1-1
......@@ -161,7 +161,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
161161}
162162
163163fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
164 return in.stream.readNoEof(([]u8)(result));
164 return in.stream.readNoEof(@sliceToBytes(result));
165165}
166166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {
167167 return readNoEof(in, T, (*[1]T)(result)[0..]);
std/mem.zig+6-6
......@@ -70,7 +70,7 @@ pub const Allocator = struct {
7070 for (byte_slice) |*byte| {
7171 byte.* = undefined;
7272 }
73 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
73 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
7474 }
7575
7676 pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
......@@ -86,7 +86,7 @@ pub const Allocator = struct {
8686 return ([*]align(alignment) T)(undefined)[0..0];
8787 }
8888
89 const old_byte_slice = ([]u8)(old_mem);
89 const old_byte_slice = @sliceToBytes(old_mem);
9090 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
9191 const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
9292 assert(byte_slice.len == byte_count);
......@@ -96,7 +96,7 @@ pub const Allocator = struct {
9696 byte.* = undefined;
9797 }
9898 }
99 return ([]T)(@alignCast(alignment, byte_slice));
99 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
100100 }
101101
102102 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
......@@ -118,13 +118,13 @@ pub const Allocator = struct {
118118 // n <= old_mem.len and the multiplication didn't overflow for that operation.
119119 const byte_count = @sizeOf(T) * n;
120120
121 const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable;
121 const byte_slice = self.reallocFn(self, @sliceToBytes(old_mem), byte_count, alignment) catch unreachable;
122122 assert(byte_slice.len == byte_count);
123 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
123 return @bytesToSlice(T, @alignCast(alignment, byte_slice));
124124 }
125125
126126 pub fn free(self: *Allocator, memory: var) void {
127 const bytes = ([]const u8)(memory);
127 const bytes = @sliceToBytes(memory);
128128 if (bytes.len == 0) return;
129129 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
130130 self.freeFn(self, non_const_ptr[0..bytes.len]);
std/net.zig+1-1
......@@ -68,7 +68,7 @@ pub const Address = struct {
6868
6969pub fn parseIp4(buf: []const u8) !u32 {
7070 var result: u32 = undefined;
71 const out_ptr = ([]u8)((*[1]u32)(&result)[0..]);
71 const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
7272
7373 var x: u8 = 0;
7474 var index: u8 = 0;
std/os/windows/util.zig+1-1
......@@ -79,7 +79,7 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
7979
8080 const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
8181 const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
82 const name_wide = ([]u16)(name_bytes);
82 const name_wide = @bytesToSlice(u16, name_bytes);
8383 return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
8484 mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
8585}
test/cases/align.zig+1-1
......@@ -90,7 +90,7 @@ fn testBytesAlignSlice(b: u8) void {
9090 b,
9191 b,
9292 };
93 const slice = ([]u32)(bytes[0..]);
93 const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
9494 assert(slice[0] == 0x33333333);
9595}
9696
test/cases/cast.zig+7-1
......@@ -372,7 +372,7 @@ test "const slice widen cast" {
372372 0x12,
373373 };
374374
375 const u32_value = ([]const u32)(bytes[0..])[0];
375 const u32_value = @bytesToSlice(u32, bytes[0..])[0];
376376 assert(u32_value == 0x12121212);
377377
378378 assert(@bitCast(u32, bytes) == 0x12121212);
......@@ -420,3 +420,9 @@ test "comptime_int @intToFloat" {
420420 assert(@typeOf(result) == f32);
421421 assert(result == 1234.0);
422422}
423
424test "@bytesToSlice keeps pointer alignment" {
425 var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
426 const numbers = @bytesToSlice(u32, bytes[0..]);
427 comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
428}
test/cases/misc.zig+2-2
......@@ -422,14 +422,14 @@ test "cast slice to u8 slice" {
422422 4,
423423 };
424424 const big_thing_slice: []i32 = big_thing_array[0..];
425 const bytes = ([]u8)(big_thing_slice);
425 const bytes = @sliceToBytes(big_thing_slice);
426426 assert(bytes.len == 4 * 4);
427427 bytes[4] = 0;
428428 bytes[5] = 0;
429429 bytes[6] = 0;
430430 bytes[7] = 0;
431431 assert(big_thing_slice[1] == 0);
432 const big_thing_again = ([]align(1) i32)(bytes);
432 const big_thing_again = @bytesToSlice(i32, bytes);
433433 assert(big_thing_again[2] == 3);
434434 big_thing_again[2] = -1;
435435 assert(bytes[8] == @maxValue(u8));
test/cases/struct.zig+2-2
......@@ -302,7 +302,7 @@ test "packed array 24bits" {
302302
303303 var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
304304 bytes[bytes.len - 1] = 0xaa;
305 const ptr = &([]FooArray24Bits)(bytes[0 .. bytes.len - 1])[0];
305 const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
306306 assert(ptr.a == 0);
307307 assert(ptr.b[0].field == 0);
308308 assert(ptr.b[1].field == 0);
......@@ -351,7 +351,7 @@ test "aligned array of packed struct" {
351351 }
352352
353353 var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
354 const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
354 const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
355355
356356 assert(ptr.a[0].a == 0xbb);
357357 assert(ptr.a[0].b == 0xbb);
test/compile_errors.zig+5-16
......@@ -404,10 +404,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
404404 \\const Set2 = error {A, C};
405405 \\comptime {
406406 \\ var x = Set1.B;
407 \\ var y = Set2(x);
407 \\ var y = @errSetCast(Set2, x);
408408 \\}
409409 ,
410 ".tmp_source.zig:5:17: error: error.B not a member of error set 'Set2'",
410 ".tmp_source.zig:5:13: error: error.B not a member of error set 'Set2'",
411411 );
412412
413413 cases.add(
......@@ -2086,10 +2086,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
20862086 "convert fixed size array to slice with invalid size",
20872087 \\export fn f() void {
20882088 \\ var array: [5]u8 = undefined;
2089 \\ var foo = ([]const u32)(array)[0];
2089 \\ var foo = @bytesToSlice(u32, array)[0];
20902090 \\}
20912091 ,
2092 ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch",
2092 ".tmp_source.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
2093 ".tmp_source.zig:3:29: note: u32 has size 4; remaining bytes: 1",
20932094 );
20942095
20952096 cases.add(
......@@ -3239,18 +3240,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
32393240 ".tmp_source.zig:3:26: note: '*u32' has alignment 4",
32403241 );
32413242
3242 cases.add(
3243 "increase pointer alignment in slice resize",
3244 \\export fn entry() u32 {
3245 \\ var bytes = []u8{0x01, 0x02, 0x03, 0x04};
3246 \\ return ([]u32)(bytes[0..])[0];
3247 \\}
3248 ,
3249 ".tmp_source.zig:3:19: error: cast increases pointer alignment",
3250 ".tmp_source.zig:3:19: note: '[]u8' has alignment 1",
3251 ".tmp_source.zig:3:19: note: '[]u32' has alignment 4",
3252 );
3253
32543243 cases.add(
32553244 "@alignCast expects pointer or slice",
32563245 \\export fn entry() void {