mirror of
https://github.com/ziglang/zig.git
synced 2024-11-14 16:13:24 +00:00
remove []u8 casting syntax. add @bytesToSlice
and @sliceToBytes
See #1061
This commit is contained in:
parent
5d705fc6e3
commit
1aafbae5be
@ -1456,8 +1456,7 @@ test "pointer array access" {
|
||||
// Taking an address of an individual element gives a
|
||||
// pointer to a single item. This kind of pointer
|
||||
// does not support pointer arithmetic.
|
||||
|
||||
var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
const ptr = &array[2];
|
||||
assert(@typeOf(ptr) == *u8);
|
||||
|
||||
@ -1469,7 +1468,7 @@ test "pointer array access" {
|
||||
test "pointer slicing" {
|
||||
// In Zig, we prefer using slices over null-terminated pointers.
|
||||
// You can turn an array into a slice using slice syntax:
|
||||
var array = []u8{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
var array = []u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
||||
const slice = array[2..4];
|
||||
assert(slice.len == 2);
|
||||
|
||||
@ -1541,13 +1540,13 @@ test "pointer casting" {
|
||||
// To convert one pointer type to another, use @ptrCast. This is an unsafe
|
||||
// operation that Zig cannot protect you against. Use @ptrCast only when other
|
||||
// conversions are not possible.
|
||||
const bytes align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12};
|
||||
const bytes align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12 };
|
||||
const u32_ptr = @ptrCast(*const u32, &bytes[0]);
|
||||
assert(u32_ptr.* == 0x12121212);
|
||||
|
||||
// Even this example is contrived - there are better ways to do the above than
|
||||
// pointer casting. For example, using a slice narrowing cast:
|
||||
const u32_value = ([]const u32)(bytes[0..])[0];
|
||||
const u32_value = @bytesToSlice(u32, bytes[0..])[0];
|
||||
assert(u32_value == 0x12121212);
|
||||
|
||||
// And even another way, the most straightforward way to do it:
|
||||
@ -1630,13 +1629,13 @@ test "function alignment" {
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
test "pointer alignment safety" {
|
||||
var array align(4) = []u32{0x11111111, 0x11111111};
|
||||
const bytes = ([]u8)(array[0..]);
|
||||
var array align(4) = []u32{ 0x11111111, 0x11111111 };
|
||||
const bytes = @sliceToBytes(array[0..]);
|
||||
assert(foo(bytes) == 0x11111111);
|
||||
}
|
||||
fn foo(bytes: []u8) u32 {
|
||||
const slice4 = bytes[1..5];
|
||||
const int_slice = ([]u32)(@alignCast(4, slice4));
|
||||
const int_slice = @bytesToSlice(u32, @alignCast(4, slice4));
|
||||
return int_slice[0];
|
||||
}
|
||||
{#code_end#}
|
||||
@ -1728,8 +1727,8 @@ test "slice pointer" {
|
||||
test "slice widening" {
|
||||
// Zig supports slice widening and slice narrowing. Cast a slice of u8
|
||||
// to a slice of anything else, and Zig will perform the length conversion.
|
||||
const array align(@alignOf(u32)) = []u8{0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13};
|
||||
const slice = ([]const u32)(array[0..]);
|
||||
const array align(@alignOf(u32)) = []u8{ 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13 };
|
||||
const slice = @bytesToSlice(u32, array[0..]);
|
||||
assert(slice.len == 2);
|
||||
assert(slice[0] == 0x12121212);
|
||||
assert(slice[1] == 0x13131313);
|
||||
@ -4651,6 +4650,18 @@ comptime {
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@bytesToSlice#}
|
||||
<pre><code class="zig">@bytesToSlice(comptime Element: type, bytes: []u8) []Element</code></pre>
|
||||
<p>
|
||||
Converts a slice of bytes or array of bytes into a slice of <code>Element</code>.
|
||||
The resulting slice has the same {#link|pointer|Pointers#} properties as the parameter.
|
||||
</p>
|
||||
<p>
|
||||
Attempting to convert a number of bytes with a length that does not evenly divide into a slice of
|
||||
elements results in {#link|Undefined Behavior#}.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@cDefine#}
|
||||
<pre><code class="zig">@cDefine(comptime name: []u8, value)</code></pre>
|
||||
<p>
|
||||
@ -5467,8 +5478,9 @@ pub const FloatMode = enum {
|
||||
</p>
|
||||
{#see_also|@shlExact|@shlWithOverflow#}
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@sizeOf#}
|
||||
<pre><code class="zig">@sizeOf(comptime T: type) (number literal)</code></pre>
|
||||
<pre><code class="zig">@sizeOf(comptime T: type) comptime_int</code></pre>
|
||||
<p>
|
||||
This function returns the number of bytes it takes to store <code>T</code> in memory.
|
||||
</p>
|
||||
@ -5476,6 +5488,15 @@ pub const FloatMode = enum {
|
||||
The result is a target-specific compile time constant.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@sliceToBytes#}
|
||||
<pre><code class="zig">@sliceToBytes(value: var) []u8</code></pre>
|
||||
<p>
|
||||
Converts a slice or array to a slice of <code>u8</code>. The resulting slice has the same
|
||||
{#link|pointer|Pointers#} properties as the parameter.
|
||||
</p>
|
||||
{#header_close#}
|
||||
|
||||
{#header_open|@sqrt#}
|
||||
<pre><code class="zig">@sqrt(comptime T: type, value: T) T</code></pre>
|
||||
<p>
|
||||
@ -6810,7 +6831,7 @@ hljs.registerLanguage("zig", function(t) {
|
||||
a = t.IR + "\\s*\\(",
|
||||
c = {
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
literal: "true false null undefined"
|
||||
},
|
||||
n = [e, t.CLCM, t.CBCM, s, r];
|
||||
|
@ -234,6 +234,16 @@ enum RuntimeHintPtr {
|
||||
RuntimeHintPtrNonStack,
|
||||
};
|
||||
|
||||
enum RuntimeHintSliceId {
|
||||
RuntimeHintSliceIdUnknown,
|
||||
RuntimeHintSliceIdLen,
|
||||
};
|
||||
|
||||
struct RuntimeHintSlice {
|
||||
enum RuntimeHintSliceId id;
|
||||
uint64_t len;
|
||||
};
|
||||
|
||||
struct ConstGlobalRefs {
|
||||
LLVMValueRef llvm_value;
|
||||
LLVMValueRef llvm_global;
|
||||
@ -270,6 +280,7 @@ struct ConstExprValue {
|
||||
RuntimeHintErrorUnion rh_error_union;
|
||||
RuntimeHintOptional rh_maybe;
|
||||
RuntimeHintPtr rh_ptr;
|
||||
RuntimeHintSlice rh_slice;
|
||||
} data;
|
||||
};
|
||||
|
||||
@ -1360,6 +1371,8 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdIntCast,
|
||||
BuiltinFnIdFloatCast,
|
||||
BuiltinFnIdErrSetCast,
|
||||
BuiltinFnIdToBytes,
|
||||
BuiltinFnIdFromBytes,
|
||||
BuiltinFnIdIntToFloat,
|
||||
BuiltinFnIdFloatToInt,
|
||||
BuiltinFnIdBoolToInt,
|
||||
@ -2123,6 +2136,8 @@ enum IrInstructionId {
|
||||
IrInstructionIdMarkErrRetTracePtr,
|
||||
IrInstructionIdSqrt,
|
||||
IrInstructionIdErrSetCast,
|
||||
IrInstructionIdToBytes,
|
||||
IrInstructionIdFromBytes,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
@ -2665,6 +2680,19 @@ struct IrInstructionErrSetCast {
|
||||
IrInstruction *target;
|
||||
};
|
||||
|
||||
struct IrInstructionToBytes {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *target;
|
||||
};
|
||||
|
||||
struct IrInstructionFromBytes {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *dest_child_type;
|
||||
IrInstruction *target;
|
||||
};
|
||||
|
||||
struct IrInstructionIntToFloat {
|
||||
IrInstruction base;
|
||||
|
||||
|
@ -4728,6 +4728,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdFloatToInt:
|
||||
case IrInstructionIdBoolToInt:
|
||||
case IrInstructionIdErrSetCast:
|
||||
case IrInstructionIdFromBytes:
|
||||
case IrInstructionIdToBytes:
|
||||
zig_unreachable();
|
||||
|
||||
case IrInstructionIdReturn:
|
||||
@ -6358,6 +6360,8 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
|
||||
create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
|
||||
create_builtin_fn(g, BuiltinFnIdErrSetCast, "errSetCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
|
||||
}
|
||||
|
||||
static const char *bool_to_str(bool b) {
|
||||
|
217
src/ir.cpp
217
src/ir.cpp
@ -472,6 +472,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrSetCast *) {
|
||||
return IrInstructionIdErrSetCast;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionToBytes *) {
|
||||
return IrInstructionIdToBytes;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionFromBytes *) {
|
||||
return IrInstructionIdFromBytes;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionIntToFloat *) {
|
||||
return IrInstructionIdIntToFloat;
|
||||
}
|
||||
@ -1956,6 +1964,26 @@ static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNod
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) {
|
||||
IrInstructionToBytes *instruction = ir_build_instruction<IrInstructionToBytes>(irb, scope, source_node);
|
||||
instruction->target = target;
|
||||
|
||||
ir_ref_instruction(target, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) {
|
||||
IrInstructionFromBytes *instruction = ir_build_instruction<IrInstructionFromBytes>(irb, scope, source_node);
|
||||
instruction->dest_child_type = dest_child_type;
|
||||
instruction->target = target;
|
||||
|
||||
ir_ref_instruction(dest_child_type, irb->current_basic_block);
|
||||
ir_ref_instruction(target, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_int_to_float(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_type, IrInstruction *target) {
|
||||
IrInstructionIntToFloat *instruction = ir_build_instruction<IrInstructionIntToFloat>(irb, scope, source_node);
|
||||
instruction->dest_type = dest_type;
|
||||
@ -4084,6 +4112,31 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value);
|
||||
return ir_lval_wrap(irb, scope, result, lval);
|
||||
}
|
||||
case BuiltinFnIdFromBytes:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
|
||||
IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
|
||||
if (arg1_value == irb->codegen->invalid_instruction)
|
||||
return arg1_value;
|
||||
|
||||
IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value);
|
||||
return ir_lval_wrap(irb, scope, result, lval);
|
||||
}
|
||||
case BuiltinFnIdToBytes:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value);
|
||||
return ir_lval_wrap(irb, scope, result, lval);
|
||||
}
|
||||
case BuiltinFnIdIntToFloat:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
@ -9103,11 +9156,6 @@ static bool is_container(TypeTableEntry *type) {
|
||||
type->id == TypeTableEntryIdUnion;
|
||||
}
|
||||
|
||||
static bool is_u8(TypeTableEntry *type) {
|
||||
return type->id == TypeTableEntryIdInt &&
|
||||
!type->data.integral.is_signed && type->data.integral.bit_count == 8;
|
||||
}
|
||||
|
||||
static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) {
|
||||
assert(old_bb);
|
||||
|
||||
@ -9661,6 +9709,8 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s
|
||||
IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, array_ptr, start, end, false);
|
||||
result->value.type = wanted_type;
|
||||
result->value.data.rh_slice.id = RuntimeHintSliceIdLen;
|
||||
result->value.data.rh_slice.len = array_type->data.array.len;
|
||||
ir_add_alloca(ira, result, result->value.type);
|
||||
|
||||
return result;
|
||||
@ -10103,7 +10153,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
// explicit match or non-const to const
|
||||
// perfect match or non-const to const
|
||||
if (types_match_const_cast_only(ira, wanted_type, actual_type, source_node, false).id == ConstCastResultIdOk) {
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
|
||||
}
|
||||
@ -10214,52 +10264,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
}
|
||||
}
|
||||
|
||||
// explicit cast from []T to []u8 or []u8 to []T
|
||||
if (is_slice(wanted_type) && is_slice(actual_type)) {
|
||||
TypeTableEntry *wanted_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
TypeTableEntry *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
if ((is_u8(wanted_ptr_type->data.pointer.child_type) || is_u8(actual_ptr_type->data.pointer.child_type)) &&
|
||||
(wanted_ptr_type->data.pointer.is_const || !actual_ptr_type->data.pointer.is_const))
|
||||
{
|
||||
uint32_t src_align_bytes = get_ptr_align(actual_ptr_type);
|
||||
uint32_t dest_align_bytes = get_ptr_align(wanted_ptr_type);
|
||||
|
||||
if (dest_align_bytes > src_align_bytes) {
|
||||
ErrorMsg *msg = ir_add_error(ira, source_instr,
|
||||
buf_sprintf("cast increases pointer alignment"));
|
||||
add_error_note(ira->codegen, msg, source_instr->source_node,
|
||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), src_align_bytes));
|
||||
add_error_note(ira->codegen, msg, source_instr->source_node,
|
||||
buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), dest_align_bytes));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
if (!ir_emit_global_runtime_side_effect(ira, source_instr))
|
||||
return ira->codegen->invalid_instruction;
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true);
|
||||
}
|
||||
}
|
||||
|
||||
// explicit cast from [N]u8 to []const T
|
||||
if (is_slice(wanted_type) &&
|
||||
wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const &&
|
||||
actual_type->id == TypeTableEntryIdArray &&
|
||||
is_u8(actual_type->data.array.child_type))
|
||||
{
|
||||
if (!ir_emit_global_runtime_side_effect(ira, source_instr))
|
||||
return ira->codegen->invalid_instruction;
|
||||
uint64_t child_type_size = type_size(ira->codegen,
|
||||
wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.child_type);
|
||||
if (actual_type->data.array.len % child_type_size == 0) {
|
||||
return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true);
|
||||
} else {
|
||||
ir_add_error_node(ira, source_instr->source_node,
|
||||
buf_sprintf("unable to convert %s to %s: size mismatch",
|
||||
buf_ptr(&actual_type->name), buf_ptr(&wanted_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
|
||||
// explicit *[N]T to [*]T
|
||||
if (wanted_type->id == TypeTableEntryIdPointer &&
|
||||
wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
|
||||
@ -17644,6 +17648,109 @@ static TypeTableEntry *ir_analyze_instruction_err_set_cast(IrAnalyze *ira, IrIns
|
||||
return dest_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstructionFromBytes *instruction) {
|
||||
TypeTableEntry *dest_child_type = ir_resolve_type(ira, instruction->dest_child_type->other);
|
||||
if (type_is_invalid(dest_child_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *target = instruction->target->other;
|
||||
if (type_is_invalid(target->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
bool src_ptr_const;
|
||||
bool src_ptr_volatile;
|
||||
uint32_t src_ptr_align;
|
||||
if (target->value.type->id == TypeTableEntryIdPointer) {
|
||||
src_ptr_const = target->value.type->data.pointer.is_const;
|
||||
src_ptr_volatile = target->value.type->data.pointer.is_volatile;
|
||||
src_ptr_align = target->value.type->data.pointer.alignment;
|
||||
} else if (is_slice(target->value.type)) {
|
||||
TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
src_ptr_const = src_ptr_type->data.pointer.is_const;
|
||||
src_ptr_volatile = src_ptr_type->data.pointer.is_volatile;
|
||||
src_ptr_align = src_ptr_type->data.pointer.alignment;
|
||||
} else {
|
||||
src_ptr_const = true;
|
||||
src_ptr_volatile = false;
|
||||
src_ptr_align = get_abi_alignment(ira->codegen, target->value.type);
|
||||
}
|
||||
|
||||
TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, dest_child_type,
|
||||
src_ptr_const, src_ptr_volatile, PtrLenUnknown,
|
||||
src_ptr_align, 0, 0);
|
||||
TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
|
||||
|
||||
TypeTableEntry *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
src_ptr_const, src_ptr_volatile, PtrLenUnknown,
|
||||
src_ptr_align, 0, 0);
|
||||
TypeTableEntry *u8_slice = get_slice_type(ira->codegen, u8_ptr);
|
||||
|
||||
IrInstruction *casted_value = ir_implicit_cast(ira, target, u8_slice);
|
||||
if (type_is_invalid(casted_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
bool have_known_len = false;
|
||||
uint64_t known_len;
|
||||
|
||||
if (instr_is_comptime(casted_value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index];
|
||||
if (value_is_comptime(len_val)) {
|
||||
known_len = bigint_as_unsigned(&len_val->data.x_bigint);
|
||||
have_known_len = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) {
|
||||
known_len = casted_value->value.data.rh_slice.len;
|
||||
have_known_len = true;
|
||||
}
|
||||
|
||||
if (have_known_len) {
|
||||
uint64_t child_type_size = type_size(ira->codegen, dest_child_type);
|
||||
uint64_t remainder = known_len % child_type_size;
|
||||
if (remainder != 0) {
|
||||
ErrorMsg *msg = ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("unable to convert [%" ZIG_PRI_u64 "]u8 to %s: size mismatch",
|
||||
known_len, buf_ptr(&dest_slice_type->name)));
|
||||
add_error_note(ira->codegen, msg, instruction->dest_child_type->source_node,
|
||||
buf_sprintf("%s has size %" ZIG_PRI_u64 "; remaining bytes: %" ZIG_PRI_u64,
|
||||
buf_ptr(&dest_child_type->name), child_type_size, remainder));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_resolve_cast(ira, &instruction->base, casted_value, dest_slice_type, CastOpResizeSlice, true);
|
||||
ir_link_new_instruction(result, &instruction->base);
|
||||
return dest_slice_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) {
|
||||
IrInstruction *target = instruction->target->other;
|
||||
if (type_is_invalid(target->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (!is_slice(target->value.type)) {
|
||||
ir_add_error(ira, instruction->target,
|
||||
buf_sprintf("expected slice, found '%s'", buf_ptr(&target->value.type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
TypeTableEntry *src_ptr_type = target->value.type->data.structure.fields[slice_ptr_index].type_entry;
|
||||
|
||||
TypeTableEntry *dest_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8,
|
||||
src_ptr_type->data.pointer.is_const, src_ptr_type->data.pointer.is_volatile, PtrLenUnknown,
|
||||
src_ptr_type->data.pointer.alignment, 0, 0);
|
||||
TypeTableEntry *dest_slice_type = get_slice_type(ira->codegen, dest_ptr_type);
|
||||
|
||||
IrInstruction *result = ir_resolve_cast(ira, &instruction->base, target, dest_slice_type, CastOpResizeSlice, true);
|
||||
ir_link_new_instruction(result, &instruction->base);
|
||||
return dest_slice_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInstructionIntToFloat *instruction) {
|
||||
TypeTableEntry *dest_type = ir_resolve_type(ira, instruction->dest_type->other);
|
||||
if (type_is_invalid(dest_type))
|
||||
@ -20246,6 +20353,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_float_cast(ira, (IrInstructionFloatCast *)instruction);
|
||||
case IrInstructionIdErrSetCast:
|
||||
return ir_analyze_instruction_err_set_cast(ira, (IrInstructionErrSetCast *)instruction);
|
||||
case IrInstructionIdFromBytes:
|
||||
return ir_analyze_instruction_from_bytes(ira, (IrInstructionFromBytes *)instruction);
|
||||
case IrInstructionIdToBytes:
|
||||
return ir_analyze_instruction_to_bytes(ira, (IrInstructionToBytes *)instruction);
|
||||
case IrInstructionIdIntToFloat:
|
||||
return ir_analyze_instruction_int_to_float(ira, (IrInstructionIntToFloat *)instruction);
|
||||
case IrInstructionIdFloatToInt:
|
||||
@ -20601,6 +20712,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdIntToFloat:
|
||||
case IrInstructionIdFloatToInt:
|
||||
case IrInstructionIdBoolToInt:
|
||||
case IrInstructionIdFromBytes:
|
||||
case IrInstructionIdToBytes:
|
||||
return false;
|
||||
|
||||
case IrInstructionIdAsm:
|
||||
|
@ -672,6 +672,20 @@ static void ir_print_err_set_cast(IrPrint *irp, IrInstructionErrSetCast *instruc
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_from_bytes(IrPrint *irp, IrInstructionFromBytes *instruction) {
|
||||
fprintf(irp->f, "@bytesToSlice(");
|
||||
ir_print_other_instruction(irp, instruction->dest_child_type);
|
||||
fprintf(irp->f, ", ");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_to_bytes(IrPrint *irp, IrInstructionToBytes *instruction) {
|
||||
fprintf(irp->f, "@sliceToBytes(");
|
||||
ir_print_other_instruction(irp, instruction->target);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_int_to_float(IrPrint *irp, IrInstructionIntToFloat *instruction) {
|
||||
fprintf(irp->f, "@intToFloat(");
|
||||
ir_print_other_instruction(irp, instruction->dest_type);
|
||||
@ -1472,6 +1486,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdErrSetCast:
|
||||
ir_print_err_set_cast(irp, (IrInstructionErrSetCast *)instruction);
|
||||
break;
|
||||
case IrInstructionIdFromBytes:
|
||||
ir_print_from_bytes(irp, (IrInstructionFromBytes *)instruction);
|
||||
break;
|
||||
case IrInstructionIdToBytes:
|
||||
ir_print_to_bytes(irp, (IrInstructionToBytes *)instruction);
|
||||
break;
|
||||
case IrInstructionIdIntToFloat:
|
||||
ir_print_int_to_float(irp, (IrInstructionIntToFloat *)instruction);
|
||||
break;
|
||||
|
@ -221,7 +221,7 @@ pub const ArenaAllocator = struct {
|
||||
if (len >= actual_min_size) break;
|
||||
}
|
||||
const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
|
||||
const buf_node_slice = ([]BufNode)(buf[0..@sizeOf(BufNode)]);
|
||||
const buf_node_slice = @bytesToSlice(BufNode, buf[0..@sizeOf(BufNode)]);
|
||||
const buf_node = &buf_node_slice[0];
|
||||
buf_node.* = BufNode{
|
||||
.data = buf,
|
||||
|
@ -161,7 +161,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
|
||||
}
|
||||
|
||||
fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
|
||||
return in.stream.readNoEof(([]u8)(result));
|
||||
return in.stream.readNoEof(@sliceToBytes(result));
|
||||
}
|
||||
fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {
|
||||
return readNoEof(in, T, (*[1]T)(result)[0..]);
|
||||
|
12
std/mem.zig
12
std/mem.zig
@ -70,7 +70,7 @@ pub const Allocator = struct {
|
||||
for (byte_slice) |*byte| {
|
||||
byte.* = undefined;
|
||||
}
|
||||
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
|
||||
return @bytesToSlice(T, @alignCast(alignment, byte_slice));
|
||||
}
|
||||
|
||||
pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
|
||||
@ -86,7 +86,7 @@ pub const Allocator = struct {
|
||||
return ([*]align(alignment) T)(undefined)[0..0];
|
||||
}
|
||||
|
||||
const old_byte_slice = ([]u8)(old_mem);
|
||||
const old_byte_slice = @sliceToBytes(old_mem);
|
||||
const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
|
||||
const byte_slice = try self.reallocFn(self, old_byte_slice, byte_count, alignment);
|
||||
assert(byte_slice.len == byte_count);
|
||||
@ -96,7 +96,7 @@ pub const Allocator = struct {
|
||||
byte.* = undefined;
|
||||
}
|
||||
}
|
||||
return ([]T)(@alignCast(alignment, byte_slice));
|
||||
return @bytesToSlice(T, @alignCast(alignment, byte_slice));
|
||||
}
|
||||
|
||||
/// Reallocate, but `n` must be less than or equal to `old_mem.len`.
|
||||
@ -118,13 +118,13 @@ pub const Allocator = struct {
|
||||
// n <= old_mem.len and the multiplication didn't overflow for that operation.
|
||||
const byte_count = @sizeOf(T) * n;
|
||||
|
||||
const byte_slice = self.reallocFn(self, ([]u8)(old_mem), byte_count, alignment) catch unreachable;
|
||||
const byte_slice = self.reallocFn(self, @sliceToBytes(old_mem), byte_count, alignment) catch unreachable;
|
||||
assert(byte_slice.len == byte_count);
|
||||
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
|
||||
return @bytesToSlice(T, @alignCast(alignment, byte_slice));
|
||||
}
|
||||
|
||||
pub fn free(self: *Allocator, memory: var) void {
|
||||
const bytes = ([]const u8)(memory);
|
||||
const bytes = @sliceToBytes(memory);
|
||||
if (bytes.len == 0) return;
|
||||
const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
|
||||
self.freeFn(self, non_const_ptr[0..bytes.len]);
|
||||
|
@ -68,7 +68,7 @@ pub const Address = struct {
|
||||
|
||||
pub fn parseIp4(buf: []const u8) !u32 {
|
||||
var result: u32 = undefined;
|
||||
const out_ptr = ([]u8)((*[1]u32)(&result)[0..]);
|
||||
const out_ptr = @sliceToBytes((*[1]u32)(&result)[0..]);
|
||||
|
||||
var x: u8 = 0;
|
||||
var index: u8 = 0;
|
||||
|
@ -79,7 +79,7 @@ pub fn windowsIsCygwinPty(handle: windows.HANDLE) bool {
|
||||
|
||||
const name_info = @ptrCast(*const windows.FILE_NAME_INFO, &name_info_bytes[0]);
|
||||
const name_bytes = name_info_bytes[size .. size + usize(name_info.FileNameLength)];
|
||||
const name_wide = ([]u16)(name_bytes);
|
||||
const name_wide = @bytesToSlice(u16, name_bytes);
|
||||
return mem.indexOf(u16, name_wide, []u16{ 'm', 's', 'y', 's', '-' }) != null or
|
||||
mem.indexOf(u16, name_wide, []u16{ '-', 'p', 't', 'y' }) != null;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ fn testBytesAlignSlice(b: u8) void {
|
||||
b,
|
||||
b,
|
||||
};
|
||||
const slice = ([]u32)(bytes[0..]);
|
||||
const slice: []u32 = @bytesToSlice(u32, bytes[0..]);
|
||||
assert(slice[0] == 0x33333333);
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ test "const slice widen cast" {
|
||||
0x12,
|
||||
};
|
||||
|
||||
const u32_value = ([]const u32)(bytes[0..])[0];
|
||||
const u32_value = @bytesToSlice(u32, bytes[0..])[0];
|
||||
assert(u32_value == 0x12121212);
|
||||
|
||||
assert(@bitCast(u32, bytes) == 0x12121212);
|
||||
@ -420,3 +420,9 @@ test "comptime_int @intToFloat" {
|
||||
assert(@typeOf(result) == f32);
|
||||
assert(result == 1234.0);
|
||||
}
|
||||
|
||||
test "@bytesToSlice keeps pointer alignment" {
|
||||
var bytes = []u8{ 0x01, 0x02, 0x03, 0x04 };
|
||||
const numbers = @bytesToSlice(u32, bytes[0..]);
|
||||
comptime assert(@typeOf(numbers) == []align(@alignOf(@typeOf(bytes))) u32);
|
||||
}
|
||||
|
@ -422,14 +422,14 @@ test "cast slice to u8 slice" {
|
||||
4,
|
||||
};
|
||||
const big_thing_slice: []i32 = big_thing_array[0..];
|
||||
const bytes = ([]u8)(big_thing_slice);
|
||||
const bytes = @sliceToBytes(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);
|
||||
const big_thing_again = ([]align(1) i32)(bytes);
|
||||
const big_thing_again = @bytesToSlice(i32, bytes);
|
||||
assert(big_thing_again[2] == 3);
|
||||
big_thing_again[2] = -1;
|
||||
assert(bytes[8] == @maxValue(u8));
|
||||
|
@ -302,7 +302,7 @@ test "packed array 24bits" {
|
||||
|
||||
var bytes = []u8{0} ** (@sizeOf(FooArray24Bits) + 1);
|
||||
bytes[bytes.len - 1] = 0xaa;
|
||||
const ptr = &([]FooArray24Bits)(bytes[0 .. bytes.len - 1])[0];
|
||||
const ptr = &@bytesToSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
|
||||
assert(ptr.a == 0);
|
||||
assert(ptr.b[0].field == 0);
|
||||
assert(ptr.b[1].field == 0);
|
||||
@ -351,7 +351,7 @@ test "aligned array of packed struct" {
|
||||
}
|
||||
|
||||
var bytes = []u8{0xbb} ** @sizeOf(FooArrayOfAligned);
|
||||
const ptr = &([]FooArrayOfAligned)(bytes[0..bytes.len])[0];
|
||||
const ptr = &@bytesToSlice(FooArrayOfAligned, bytes[0..bytes.len])[0];
|
||||
|
||||
assert(ptr.a[0].a == 0xbb);
|
||||
assert(ptr.a[0].b == 0xbb);
|
||||
|
@ -404,10 +404,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
\\const Set2 = error {A, C};
|
||||
\\comptime {
|
||||
\\ var x = Set1.B;
|
||||
\\ var y = Set2(x);
|
||||
\\ var y = @errSetCast(Set2, x);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:5:17: error: error.B not a member of error set 'Set2'",
|
||||
".tmp_source.zig:5:13: error: error.B not a member of error set 'Set2'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -2086,10 +2086,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
"convert fixed size array to slice with invalid size",
|
||||
\\export fn f() void {
|
||||
\\ var array: [5]u8 = undefined;
|
||||
\\ var foo = ([]const u32)(array)[0];
|
||||
\\ var foo = @bytesToSlice(u32, array)[0];
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch",
|
||||
".tmp_source.zig:3:15: error: unable to convert [5]u8 to []align(1) const u32: size mismatch",
|
||||
".tmp_source.zig:3:29: note: u32 has size 4; remaining bytes: 1",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
@ -3239,18 +3240,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
".tmp_source.zig:3:26: note: '*u32' has alignment 4",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"increase pointer alignment in slice resize",
|
||||
\\export fn entry() u32 {
|
||||
\\ var bytes = []u8{0x01, 0x02, 0x03, 0x04};
|
||||
\\ return ([]u32)(bytes[0..])[0];
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:3:19: error: cast increases pointer alignment",
|
||||
".tmp_source.zig:3:19: note: '[]u8' has alignment 1",
|
||||
".tmp_source.zig:3:19: note: '[]u32' has alignment 4",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"@alignCast expects pointer or slice",
|
||||
\\export fn entry() void {
|
||||
|
Loading…
Reference in New Issue
Block a user