authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-04 22:11:14-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-06-04 22:11:14-04:00
loge53b683bd3958a7b1c517e2391edce42b9d4e48b
treec9b8aacf92b2140c1cc076e2de280e10657d0a98
parent32e0dfd4f0dab351a024e7680280343db5d7c43e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Pointer Reform: proper slicing and indexing (#1053)

* enable slicing for single-item ptr to arrays * disable slicing for other single-item pointers * enable indexing for single-item ptr to arrays * disable indexing for other single-item pointers see #770 closes #386

21 files changed, 268 insertions(+), 79 deletions(-)

doc/langref.html.in+8-5
...@@ -1565,7 +1565,7 @@ var foo: u8 align(4) = 100;...@@ -1565,7 +1565,7 @@ var foo: u8 align(4) = 100;
1565test "global variable alignment" {1565test "global variable alignment" {
1566 assert(@typeOf(&foo).alignment == 4);1566 assert(@typeOf(&foo).alignment == 4);
1567 assert(@typeOf(&foo) == *align(4) u8);1567 assert(@typeOf(&foo) == *align(4) u8);
1568 const slice = (&foo)[0..1];1568 const slice = (*[1]u8)(&foo)[0..];
1569 assert(@typeOf(slice) == []align(4) u8);1569 assert(@typeOf(slice) == []align(4) u8);
1570}1570}
15711571
...@@ -1671,7 +1671,7 @@ test "using slices for strings" {...@@ -1671,7 +1671,7 @@ test "using slices for strings" {
16711671
1672test "slice pointer" {1672test "slice pointer" {
1673 var array: [10]u8 = undefined;1673 var array: [10]u8 = undefined;
1674 const ptr = &array[0];1674 const ptr = &array;
16751675
1676 // You can use slicing syntax to convert a pointer into a slice:1676 // You can use slicing syntax to convert a pointer into a slice:
1677 const slice = ptr[0..5];1677 const slice = ptr[0..5];
...@@ -6004,9 +6004,12 @@ const c = @cImport({...@@ -6004,9 +6004,12 @@ const c = @cImport({
6004 {#code_begin|syntax#}6004 {#code_begin|syntax#}
6005const base64 = @import("std").base64;6005const base64 = @import("std").base64;
60066006
6007export fn decode_base_64(dest_ptr: *u8, dest_len: usize,6007export fn decode_base_64(
6008 source_ptr: *const u8, source_len: usize) usize6008 dest_ptr: [*]u8,
6009{6009 dest_len: usize,
6010 source_ptr: [*]const u8,
6011 source_len: usize,
6012) usize {
6010 const src = source_ptr[0..source_len];6013 const src = source_ptr[0..source_len];
6011 const dest = dest_ptr[0..dest_len];6014 const dest = dest_ptr[0..dest_len];
6012 const base64_decoder = base64.standard_decoder_unsafe;6015 const base64_decoder = base64.standard_decoder_unsafe;
example/mix_o_files/base64.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const base64 = @import("std").base64;1const base64 = @import("std").base64;
22
3export fn decode_base_64(dest_ptr: *u8, dest_len: usize, source_ptr: *const u8, source_len: usize) usize {3export fn decode_base_64(dest_ptr: [*]u8, dest_len: usize, source_ptr: [*]const u8, source_len: usize) usize {
4 const src = source_ptr[0..source_len];4 const src = source_ptr[0..source_len];
5 const dest = dest_ptr[0..dest_len];5 const dest = dest_ptr[0..dest_len];
6 const base64_decoder = base64.standard_decoder_unsafe;6 const base64_decoder = base64.standard_decoder_unsafe;
src/all_types.hpp+5
...@@ -83,6 +83,7 @@ enum ConstParentId {...@@ -83,6 +83,7 @@ enum ConstParentId {
83 ConstParentIdStruct,83 ConstParentIdStruct,
84 ConstParentIdArray,84 ConstParentIdArray,
85 ConstParentIdUnion,85 ConstParentIdUnion,
86 ConstParentIdScalar,
86};87};
8788
88struct ConstParent {89struct ConstParent {
...@@ -100,6 +101,9 @@ struct ConstParent {...@@ -100,6 +101,9 @@ struct ConstParent {
100 struct {101 struct {
101 ConstExprValue *union_val;102 ConstExprValue *union_val;
102 } p_union;103 } p_union;
104 struct {
105 ConstExprValue *scalar_val;
106 } p_scalar;
103 } data;107 } data;
104};108};
105109
...@@ -578,6 +582,7 @@ enum CastOp {...@@ -578,6 +582,7 @@ enum CastOp {
578 CastOpBytesToSlice,582 CastOpBytesToSlice,
579 CastOpNumLitToConcrete,583 CastOpNumLitToConcrete,
580 CastOpErrSet,584 CastOpErrSet,
585 CastOpBitCast,
581};586};
582587
583struct AstNodeFnCallExpr {588struct AstNodeFnCallExpr {
src/analyze.cpp+9-5
...@@ -5158,7 +5158,8 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr...@@ -5158,7 +5158,8 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
5158 const_val->type = get_slice_type(g, ptr_type);5158 const_val->type = get_slice_type(g, ptr_type);
5159 const_val->data.x_struct.fields = create_const_vals(2);5159 const_val->data.x_struct.fields = create_const_vals(2);
51605160
5161 init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const);5161 init_const_ptr_array(g, &const_val->data.x_struct.fields[slice_ptr_index], array_val, start, is_const,
5162 PtrLenUnknown);
5162 init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);5163 init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);
5163}5164}
51645165
...@@ -5169,21 +5170,24 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t...@@ -5169,21 +5170,24 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t
5169}5170}
51705171
5171void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,5172void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
5172 size_t elem_index, bool is_const)5173 size_t elem_index, bool is_const, PtrLen ptr_len)
5173{5174{
5174 assert(array_val->type->id == TypeTableEntryIdArray);5175 assert(array_val->type->id == TypeTableEntryIdArray);
5175 TypeTableEntry *child_type = array_val->type->data.array.child_type;5176 TypeTableEntry *child_type = array_val->type->data.array.child_type;
51765177
5177 const_val->special = ConstValSpecialStatic;5178 const_val->special = ConstValSpecialStatic;
5178 const_val->type = get_pointer_to_type(g, child_type, is_const);5179 const_val->type = get_pointer_to_type_extra(g, child_type, is_const, false,
5180 ptr_len, get_abi_alignment(g, child_type), 0, 0);
5179 const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;5181 const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
5180 const_val->data.x_ptr.data.base_array.array_val = array_val;5182 const_val->data.x_ptr.data.base_array.array_val = array_val;
5181 const_val->data.x_ptr.data.base_array.elem_index = elem_index;5183 const_val->data.x_ptr.data.base_array.elem_index = elem_index;
5182}5184}
51835185
5184ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const) {5186ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const,
5187 PtrLen ptr_len)
5188{
5185 ConstExprValue *const_val = create_const_vals(1);5189 ConstExprValue *const_val = create_const_vals(1);
5186 init_const_ptr_array(g, const_val, array_val, elem_index, is_const);5190 init_const_ptr_array(g, const_val, array_val, elem_index, is_const, ptr_len);
5187 return const_val;5191 return const_val;
5188}5192}
51895193
src/analyze.hpp+3-2
...@@ -152,8 +152,9 @@ ConstExprValue *create_const_ptr_hard_coded_addr(CodeGen *g, TypeTableEntry *poi...@@ -152,8 +152,9 @@ ConstExprValue *create_const_ptr_hard_coded_addr(CodeGen *g, TypeTableEntry *poi
152 size_t addr, bool is_const);152 size_t addr, bool is_const);
153153
154void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,154void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
155 size_t elem_index, bool is_const);155 size_t elem_index, bool is_const, PtrLen ptr_len);
156ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const);156ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index,
157 bool is_const, PtrLen ptr_len);
157158
158void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,159void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
159 size_t start, size_t len, bool is_const);160 size_t start, size_t len, bool is_const);
src/codegen.cpp+23-4
...@@ -2574,6 +2574,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,...@@ -2574,6 +2574,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
2574 add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);2574 add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
2575 }2575 }
2576 return expr_val;2576 return expr_val;
2577 case CastOpBitCast:
2578 return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
2577 }2579 }
2578 zig_unreachable();2580 zig_unreachable();
2579}2581}
...@@ -2884,7 +2886,13 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI...@@ -2884,7 +2886,13 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
28842886
2885 bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on;2887 bool safety_check_on = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on;
28862888
2887 if (array_type->id == TypeTableEntryIdArray) {2889 if (array_type->id == TypeTableEntryIdArray ||
2890 (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
2891 {
2892 if (array_type->id == TypeTableEntryIdPointer) {
2893 assert(array_type->data.pointer.child_type->id == TypeTableEntryIdArray);
2894 array_type = array_type->data.pointer.child_type;
2895 }
2888 if (safety_check_on) {2896 if (safety_check_on) {
2889 LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,2897 LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
2890 array_type->data.array.len, false);2898 array_type->data.array.len, false);
...@@ -3794,7 +3802,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst...@@ -3794,7 +3802,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
37943802
3795 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);3803 bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base);
37963804
3797 if (array_type->id == TypeTableEntryIdArray) {3805 if (array_type->id == TypeTableEntryIdArray ||
3806 (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
3807 {
3808 if (array_type->id == TypeTableEntryIdPointer) {
3809 array_type = array_type->data.pointer.child_type;
3810 }
3798 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);3811 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
3799 LLVMValueRef end_val;3812 LLVMValueRef end_val;
3800 if (instruction->end) {3813 if (instruction->end) {
...@@ -3835,6 +3848,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst...@@ -3835,6 +3848,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
38353848
3836 return tmp_struct_ptr;3849 return tmp_struct_ptr;
3837 } else if (array_type->id == TypeTableEntryIdPointer) {3850 } else if (array_type->id == TypeTableEntryIdPointer) {
3851 assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
3838 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);3852 LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
3839 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);3853 LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
38403854
...@@ -4812,7 +4826,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {...@@ -4812,7 +4826,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
48124826
4813static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);4827static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
4814static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);4828static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
4815static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);4829static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
48164830
4817static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {4831static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
4818 switch (parent->id) {4832 switch (parent->id) {
...@@ -4828,6 +4842,10 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent...@@ -4828,6 +4842,10 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
4828 parent->data.p_array.elem_index);4842 parent->data.p_array.elem_index);
4829 case ConstParentIdUnion:4843 case ConstParentIdUnion:
4830 return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);4844 return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val);
4845 case ConstParentIdScalar:
4846 render_const_val(g, parent->data.p_scalar.scalar_val, "");
4847 render_const_val_global(g, parent->data.p_scalar.scalar_val, "");
4848 return parent->data.p_scalar.scalar_val->global_refs->llvm_global;
4831 }4849 }
4832 zig_unreachable();4850 zig_unreachable();
4833}4851}
...@@ -4853,7 +4871,8 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar...@@ -4853,7 +4871,8 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
4853 };4871 };
4854 return LLVMConstInBoundsGEP(base_ptr, indices, 2);4872 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
4855 } else {4873 } else {
4856 zig_unreachable();4874 assert(parent->id == ConstParentIdScalar);
4875 return base_ptr;
4857 }4876 }
4858}4877}
48594878
src/ir.cpp+135-22
...@@ -107,6 +107,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_...@@ -107,6 +107,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
107static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var);107static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var);
108static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);108static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
109static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);109static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
110static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
110111
111ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {112ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
112 assert(const_val->type->id == TypeTableEntryIdPointer);113 assert(const_val->type->id == TypeTableEntryIdPointer);
...@@ -6849,7 +6850,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6849,7 +6850,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6849 IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);6850 IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
6850 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);6851 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6851 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);6852 IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle);
6852 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type, coro_mem_ptr_maybe);6853 IrInstruction *u8_ptr_type_unknown_len = ir_build_const_type(irb, scope, node,
6854 get_pointer_to_type_extra(irb->codegen, irb->codegen->builtin_types.entry_u8,
6855 false, false, PtrLenUnknown, get_abi_alignment(irb->codegen, irb->codegen->builtin_types.entry_u8),
6856 0, 0));
6857 IrInstruction *coro_mem_ptr = ir_build_ptr_cast(irb, scope, node, u8_ptr_type_unknown_len, coro_mem_ptr_maybe);
6853 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);6858 IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
6854 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);6859 IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
6855 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);6860 IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr);
...@@ -8729,6 +8734,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,...@@ -8729,6 +8734,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op,
8729 case CastOpNoCast:8734 case CastOpNoCast:
8730 zig_unreachable();8735 zig_unreachable();
8731 case CastOpErrSet:8736 case CastOpErrSet:
8737 case CastOpBitCast:
8732 zig_panic("TODO");8738 zig_panic("TODO");
8733 case CastOpNoop:8739 case CastOpNoop:
8734 {8740 {
...@@ -9750,6 +9756,49 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc...@@ -9750,6 +9756,49 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
9750 return result;9756 return result;
9751}9757}
97529758
9759static IrInstruction *ir_analyze_ptr_to_array(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target,
9760 TypeTableEntry *wanted_type)
9761{
9762 assert(wanted_type->id == TypeTableEntryIdPointer);
9763 wanted_type = adjust_ptr_align(ira->codegen, wanted_type, target->value.type->data.pointer.alignment);
9764 TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
9765 assert(array_type->id == TypeTableEntryIdArray);
9766 assert(array_type->data.array.len == 1);
9767
9768 if (instr_is_comptime(target)) {
9769 ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
9770 if (!val)
9771 return ira->codegen->invalid_instruction;
9772
9773 assert(val->type->id == TypeTableEntryIdPointer);
9774 ConstExprValue *pointee = const_ptr_pointee(ira->codegen, val);
9775 if (pointee->special != ConstValSpecialRuntime) {
9776 ConstExprValue *array_val = create_const_vals(1);
9777 array_val->special = ConstValSpecialStatic;
9778 array_val->type = array_type;
9779 array_val->data.x_array.special = ConstArraySpecialNone;
9780 array_val->data.x_array.s_none.elements = pointee;
9781 array_val->data.x_array.s_none.parent.id = ConstParentIdScalar;
9782 array_val->data.x_array.s_none.parent.data.p_scalar.scalar_val = pointee;
9783
9784 IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb,
9785 source_instr->scope, source_instr->source_node);
9786 const_instruction->base.value.type = wanted_type;
9787 const_instruction->base.value.special = ConstValSpecialStatic;
9788 const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialRef;
9789 const_instruction->base.value.data.x_ptr.data.ref.pointee = array_val;
9790 const_instruction->base.value.data.x_ptr.mut = val->data.x_ptr.mut;
9791 return &const_instruction->base;
9792 }
9793 }
9794
9795 // pointer to array and pointer to single item are represented the same way at runtime
9796 IrInstruction *result = ir_build_cast(&ira->new_irb, target->scope, target->source_node,
9797 wanted_type, target, CastOpBitCast);
9798 result->value.type = wanted_type;
9799 return result;
9800}
9801
9753static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,9802static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
9754 TypeTableEntry *wanted_type, IrInstruction *value)9803 TypeTableEntry *wanted_type, IrInstruction *value)
9755{9804{
...@@ -10156,6 +10205,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst...@@ -10156,6 +10205,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
10156 }10205 }
10157 }10206 }
1015810207
10208 // explicit cast from *T to *[1]T
10209 if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
10210 actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
10211 {
10212 TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
10213 if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 &&
10214 types_match_const_cast_only(ira, array_type->data.array.child_type,
10215 actual_type->data.pointer.child_type, source_node).id == ConstCastResultIdOk)
10216 {
10217 if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
10218 ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
10219 add_error_note(ira->codegen, msg, value->source_node,
10220 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name),
10221 actual_type->data.pointer.alignment));
10222 add_error_note(ira->codegen, msg, source_instr->source_node,
10223 buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name),
10224 wanted_type->data.pointer.alignment));
10225 return ira->codegen->invalid_instruction;
10226 }
10227 return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type);
10228 }
10229 }
10230
10231
10159 // explicit cast from undefined to anything10232 // explicit cast from undefined to anything
10160 if (actual_type->id == TypeTableEntryIdUndefLit) {10233 if (actual_type->id == TypeTableEntryIdUndefLit) {
10161 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);10234 return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
...@@ -13162,11 +13235,13 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -13162,11 +13235,13 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
13162 if (type_is_invalid(array_ptr->value.type))13235 if (type_is_invalid(array_ptr->value.type))
13163 return ira->codegen->builtin_types.entry_invalid;13236 return ira->codegen->builtin_types.entry_invalid;
1316413237
13238 ConstExprValue *orig_array_ptr_val = &array_ptr->value;
13239
13165 IrInstruction *elem_index = elem_ptr_instruction->elem_index->other;13240 IrInstruction *elem_index = elem_ptr_instruction->elem_index->other;
13166 if (type_is_invalid(elem_index->value.type))13241 if (type_is_invalid(elem_index->value.type))
13167 return ira->codegen->builtin_types.entry_invalid;13242 return ira->codegen->builtin_types.entry_invalid;
1316813243
13169 TypeTableEntry *ptr_type = array_ptr->value.type;13244 TypeTableEntry *ptr_type = orig_array_ptr_val->type;
13170 assert(ptr_type->id == TypeTableEntryIdPointer);13245 assert(ptr_type->id == TypeTableEntryIdPointer);
1317113246
13172 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;13247 TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
...@@ -13177,7 +13252,18 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -13177,7 +13252,18 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1317713252
13178 if (type_is_invalid(array_type)) {13253 if (type_is_invalid(array_type)) {
13179 return array_type;13254 return array_type;
13180 } else if (array_type->id == TypeTableEntryIdArray) {13255 } else if (array_type->id == TypeTableEntryIdArray ||
13256 (array_type->id == TypeTableEntryIdPointer &&
13257 array_type->data.pointer.ptr_len == PtrLenSingle &&
13258 array_type->data.pointer.child_type->id == TypeTableEntryIdArray))
13259 {
13260 if (array_type->id == TypeTableEntryIdPointer) {
13261 array_type = array_type->data.pointer.child_type;
13262 ptr_type = ptr_type->data.pointer.child_type;
13263 if (orig_array_ptr_val->special != ConstValSpecialRuntime) {
13264 orig_array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val);
13265 }
13266 }
13181 if (array_type->data.array.len == 0) {13267 if (array_type->data.array.len == 0) {
13182 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,13268 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
13183 buf_sprintf("index 0 outside array of size 0"));13269 buf_sprintf("index 0 outside array of size 0"));
...@@ -13205,7 +13291,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -13205,7 +13291,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
13205 } else if (array_type->id == TypeTableEntryIdPointer) {13291 } else if (array_type->id == TypeTableEntryIdPointer) {
13206 if (array_type->data.pointer.ptr_len == PtrLenSingle) {13292 if (array_type->data.pointer.ptr_len == PtrLenSingle) {
13207 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,13293 ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
13208 buf_sprintf("indexing not allowed on pointer to single item"));13294 buf_sprintf("index of single-item pointer"));
13209 return ira->codegen->builtin_types.entry_invalid;13295 return ira->codegen->builtin_types.entry_invalid;
13210 }13296 }
13211 return_type = adjust_ptr_len(ira->codegen, array_type, elem_ptr_instruction->ptr_len);13297 return_type = adjust_ptr_len(ira->codegen, array_type, elem_ptr_instruction->ptr_len);
...@@ -13294,9 +13380,9 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -13294,9 +13380,9 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
13294 }13380 }
1329513381
13296 ConstExprValue *array_ptr_val;13382 ConstExprValue *array_ptr_val;
13297 if (array_ptr->value.special != ConstValSpecialRuntime &&13383 if (orig_array_ptr_val->special != ConstValSpecialRuntime &&
13298 (array_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&13384 (orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
13299 (array_ptr_val = const_ptr_pointee(ira->codegen, &array_ptr->value)) &&13385 (array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val)) &&
13300 array_ptr_val->special != ConstValSpecialRuntime &&13386 array_ptr_val->special != ConstValSpecialRuntime &&
13301 (array_type->id != TypeTableEntryIdPointer ||13387 (array_type->id != TypeTableEntryIdPointer ||
13302 array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))13388 array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
...@@ -13401,7 +13487,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc...@@ -13401,7 +13487,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
13401 } else if (array_type->id == TypeTableEntryIdArray) {13487 } else if (array_type->id == TypeTableEntryIdArray) {
13402 ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);13488 ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
13403 out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;13489 out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
13404 out_val->data.x_ptr.mut = array_ptr->value.data.x_ptr.mut;13490 out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut;
13405 out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;13491 out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;
13406 out_val->data.x_ptr.data.base_array.elem_index = index;13492 out_val->data.x_ptr.data.base_array.elem_index = index;
13407 return return_type;13493 return return_type;
...@@ -17406,14 +17492,29 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -17406,14 +17492,29 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
17406 byte_alignment, 0, 0);17492 byte_alignment, 0, 0);
17407 return_type = get_slice_type(ira->codegen, slice_ptr_type);17493 return_type = get_slice_type(ira->codegen, slice_ptr_type);
17408 } else if (array_type->id == TypeTableEntryIdPointer) {17494 } else if (array_type->id == TypeTableEntryIdPointer) {
17409 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,17495 if (array_type->data.pointer.ptr_len == PtrLenSingle) {
17410 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,17496 TypeTableEntry *main_type = array_type->data.pointer.child_type;
17411 PtrLenUnknown,17497 if (main_type->id == TypeTableEntryIdArray) {
17412 array_type->data.pointer.alignment, 0, 0);17498 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
17413 return_type = get_slice_type(ira->codegen, slice_ptr_type);17499 main_type->data.pointer.child_type,
17414 if (!end) {17500 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
17415 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));17501 PtrLenUnknown,
17416 return ira->codegen->builtin_types.entry_invalid;17502 array_type->data.pointer.alignment, 0, 0);
17503 return_type = get_slice_type(ira->codegen, slice_ptr_type);
17504 } else {
17505 ir_add_error(ira, &instruction->base, buf_sprintf("slice of single-item pointer"));
17506 return ira->codegen->builtin_types.entry_invalid;
17507 }
17508 } else {
17509 TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
17510 array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
17511 PtrLenUnknown,
17512 array_type->data.pointer.alignment, 0, 0);
17513 return_type = get_slice_type(ira->codegen, slice_ptr_type);
17514 if (!end) {
17515 ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
17516 return ira->codegen->builtin_types.entry_invalid;
17517 }
17417 }17518 }
17418 } else if (is_slice(array_type)) {17519 } else if (is_slice(array_type)) {
17419 TypeTableEntry *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;17520 TypeTableEntry *ptr_type = array_type->data.structure.fields[slice_ptr_index].type_entry;
...@@ -17433,12 +17534,24 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -17433,12 +17534,24 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
17433 size_t abs_offset;17534 size_t abs_offset;
17434 size_t rel_end;17535 size_t rel_end;
17435 bool ptr_is_undef = false;17536 bool ptr_is_undef = false;
17436 if (array_type->id == TypeTableEntryIdArray) {17537 if (array_type->id == TypeTableEntryIdArray ||
17437 array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);17538 (array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
17438 abs_offset = 0;17539 {
17439 rel_end = array_type->data.array.len;17540 if (array_type->id == TypeTableEntryIdPointer) {
17440 parent_ptr = nullptr;17541 TypeTableEntry *child_array_type = array_type->data.pointer.child_type;
17542 assert(child_array_type->id == TypeTableEntryIdArray);
17543 parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
17544 array_val = const_ptr_pointee(ira->codegen, parent_ptr);
17545 rel_end = child_array_type->data.array.len;
17546 abs_offset = 0;
17547 } else {
17548 array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
17549 rel_end = array_type->data.array.len;
17550 parent_ptr = nullptr;
17551 abs_offset = 0;
17552 }
17441 } else if (array_type->id == TypeTableEntryIdPointer) {17553 } else if (array_type->id == TypeTableEntryIdPointer) {
17554 assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
17442 parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);17555 parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
17443 if (parent_ptr->special == ConstValSpecialUndef) {17556 if (parent_ptr->special == ConstValSpecialUndef) {
17444 array_val = nullptr;17557 array_val = nullptr;
...@@ -17537,7 +17650,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -17537,7 +17650,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
17537 if (array_val) {17650 if (array_val) {
17538 size_t index = abs_offset + start_scalar;17651 size_t index = abs_offset + start_scalar;
17539 bool is_const = slice_is_const(return_type);17652 bool is_const = slice_is_const(return_type);
17540 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const);17653 init_const_ptr_array(ira->codegen, ptr_val, array_val, index, is_const, PtrLenUnknown);
17541 if (array_type->id == TypeTableEntryIdArray) {17654 if (array_type->id == TypeTableEntryIdArray) {
17542 ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;17655 ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
17543 } else if (is_slice(array_type)) {17656 } else if (is_slice(array_type)) {
std/fmt/errol/index.zig+1-1
...@@ -59,7 +59,7 @@ pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: Ro...@@ -59,7 +59,7 @@ pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: Ro
59 float_decimal.exp += 1;59 float_decimal.exp += 1;
6060
61 // Re-size the buffer to use the reserved leading byte.61 // Re-size the buffer to use the reserved leading byte.
62 const one_before = @intToPtr(*u8, @ptrToInt(&float_decimal.digits[0]) - 1);62 const one_before = @intToPtr([*]u8, @ptrToInt(&float_decimal.digits[0]) - 1);
63 float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];63 float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
64 float_decimal.digits[0] = '1';64 float_decimal.digits[0] = '1';
65 return;65 return;
std/fmt/index.zig+4-4
...@@ -278,7 +278,7 @@ pub fn formatAsciiChar(...@@ -278,7 +278,7 @@ pub fn formatAsciiChar(
278 comptime Errors: type,278 comptime Errors: type,
279 output: fn (@typeOf(context), []const u8) Errors!void,279 output: fn (@typeOf(context), []const u8) Errors!void,
280) Errors!void {280) Errors!void {
281 return output(context, (&c)[0..1]);281 return output(context, (*[1]u8)(&c)[0..]);
282}282}
283283
284pub fn formatBuf(284pub fn formatBuf(
...@@ -603,7 +603,7 @@ fn formatIntSigned(...@@ -603,7 +603,7 @@ fn formatIntSigned(
603 const uint = @IntType(false, @typeOf(value).bit_count);603 const uint = @IntType(false, @typeOf(value).bit_count);
604 if (value < 0) {604 if (value < 0) {
605 const minus_sign: u8 = '-';605 const minus_sign: u8 = '-';
606 try output(context, (&minus_sign)[0..1]);606 try output(context, (*[1]u8)(&minus_sign)[0..]);
607 const new_value = uint(-(value + 1)) + 1;607 const new_value = uint(-(value + 1)) + 1;
608 const new_width = if (width == 0) 0 else (width - 1);608 const new_width = if (width == 0) 0 else (width - 1);
609 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);609 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
...@@ -611,7 +611,7 @@ fn formatIntSigned(...@@ -611,7 +611,7 @@ fn formatIntSigned(
611 return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output);611 return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output);
612 } else {612 } else {
613 const plus_sign: u8 = '+';613 const plus_sign: u8 = '+';
614 try output(context, (&plus_sign)[0..1]);614 try output(context, (*[1]u8)(&plus_sign)[0..]);
615 const new_value = uint(value);615 const new_value = uint(value);
616 const new_width = if (width == 0) 0 else (width - 1);616 const new_width = if (width == 0) 0 else (width - 1);
617 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);617 return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
...@@ -648,7 +648,7 @@ fn formatIntUnsigned(...@@ -648,7 +648,7 @@ fn formatIntUnsigned(
648 const zero_byte: u8 = '0';648 const zero_byte: u8 = '0';
649 var leftover_padding = padding - index;649 var leftover_padding = padding - index;
650 while (true) {650 while (true) {
651 try output(context, (&zero_byte)[0..1]);651 try output(context, (*[1]u8)(&zero_byte)[0..]);
652 leftover_padding -= 1;652 leftover_padding -= 1;
653 if (leftover_padding == 0) break;653 if (leftover_padding == 0) break;
654 }654 }
std/heap.zig+1-1
...@@ -24,7 +24,7 @@ fn cAlloc(self: *Allocator, n: usize, alignment: u29) ![]u8 {...@@ -24,7 +24,7 @@ fn cAlloc(self: *Allocator, n: usize, alignment: u29) ![]u8 {
24fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {24fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
25 const old_ptr = @ptrCast([*]c_void, old_mem.ptr);25 const old_ptr = @ptrCast([*]c_void, old_mem.ptr);
26 if (c.realloc(old_ptr, new_size)) |buf| {26 if (c.realloc(old_ptr, new_size)) |buf| {
27 return @ptrCast(*u8, buf)[0..new_size];27 return @ptrCast([*]u8, buf)[0..new_size];
28 } else if (new_size <= old_mem.len) {28 } else if (new_size <= old_mem.len) {
29 return old_mem[0..new_size];29 return old_mem[0..new_size];
30 } else {30 } else {
std/io.zig+2-2
...@@ -219,12 +219,12 @@ pub fn OutStream(comptime WriteError: type) type {...@@ -219,12 +219,12 @@ pub fn OutStream(comptime WriteError: type) type {
219 }219 }
220220
221 pub fn writeByte(self: *Self, byte: u8) !void {221 pub fn writeByte(self: *Self, byte: u8) !void {
222 const slice = (&byte)[0..1];222 const slice = (*[1]u8)(&byte)[0..];
223 return self.writeFn(self, slice);223 return self.writeFn(self, slice);
224 }224 }
225225
226 pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) !void {226 pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) !void {
227 const slice = (&byte)[0..1];227 const slice = (*[1]u8)(&byte)[0..];
228 var i: usize = 0;228 var i: usize = 0;
229 while (i < n) : (i += 1) {229 while (i < n) : (i += 1) {
230 try self.writeFn(self, slice);230 try self.writeFn(self, slice);
std/macho.zig+1-1
...@@ -164,7 +164,7 @@ fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {...@@ -164,7 +164,7 @@ fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
164 return in.stream.readNoEof(([]u8)(result));164 return in.stream.readNoEof(([]u8)(result));
165}165}
166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {166fn readOneNoEof(in: *io.FileInStream, comptime T: type, result: *T) !void {
167 return readNoEof(in, T, result[0..1]);167 return readNoEof(in, T, (*[1]T)(result)[0..]);
168}168}
169169
170fn isSymbol(sym: *const Nlist64) bool {170fn isSymbol(sym: *const Nlist64) bool {
std/mem.zig+19-15
...@@ -31,14 +31,16 @@ pub const Allocator = struct {...@@ -31,14 +31,16 @@ pub const Allocator = struct {
31 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`31 /// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
32 freeFn: fn (self: *Allocator, old_mem: []u8) void,32 freeFn: fn (self: *Allocator, old_mem: []u8) void,
3333
34 fn create(self: *Allocator, comptime T: type) !*T {34 /// Call destroy with the result
35 pub fn create(self: *Allocator, comptime T: type) !*T {
35 if (@sizeOf(T) == 0) return *{};36 if (@sizeOf(T) == 0) return *{};
36 const slice = try self.alloc(T, 1);37 const slice = try self.alloc(T, 1);
37 return &slice[0];38 return &slice[0];
38 }39 }
3940
40 // TODO once #733 is solved, this will replace create41 /// Call destroy with the result
41 fn construct(self: *Allocator, init: var) t: {42 /// TODO once #733 is solved, this will replace create
43 pub fn construct(self: *Allocator, init: var) t: {
42 // TODO this is a workaround for type getting parsed as Error!&const T44 // TODO this is a workaround for type getting parsed as Error!&const T
43 const T = @typeOf(init).Child;45 const T = @typeOf(init).Child;
44 break :t Error!*T;46 break :t Error!*T;
...@@ -51,17 +53,19 @@ pub const Allocator = struct {...@@ -51,17 +53,19 @@ pub const Allocator = struct {
51 return ptr;53 return ptr;
52 }54 }
5355
54 fn destroy(self: *Allocator, ptr: var) void {56 /// `ptr` should be the return value of `construct` or `create`
55 self.free(ptr[0..1]);57 pub fn destroy(self: *Allocator, ptr: var) void {
58 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
59 self.freeFn(self, non_const_ptr[0..@sizeOf(@typeOf(ptr).Child)]);
56 }60 }
5761
58 fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {62 pub fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {
59 return self.alignedAlloc(T, @alignOf(T), n);63 return self.alignedAlloc(T, @alignOf(T), n);
60 }64 }
6165
62 fn alignedAlloc(self: *Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {66 pub fn alignedAlloc(self: *Allocator, comptime T: type, comptime alignment: u29, n: usize) ![]align(alignment) T {
63 if (n == 0) {67 if (n == 0) {
64 return (*align(alignment) T)(undefined)[0..0];68 return ([*]align(alignment) T)(undefined)[0..0];
65 }69 }
66 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;70 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
67 const byte_slice = try self.allocFn(self, byte_count, alignment);71 const byte_slice = try self.allocFn(self, byte_count, alignment);
...@@ -73,17 +77,17 @@ pub const Allocator = struct {...@@ -73,17 +77,17 @@ pub const Allocator = struct {
73 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));77 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
74 }78 }
7579
76 fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {80 pub fn realloc(self: *Allocator, comptime T: type, old_mem: []T, n: usize) ![]T {
77 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);81 return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
78 }82 }
7983
80 fn alignedRealloc(self: *Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {84 pub fn alignedRealloc(self: *Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) ![]align(alignment) T {
81 if (old_mem.len == 0) {85 if (old_mem.len == 0) {
82 return self.alloc(T, n);86 return self.alloc(T, n);
83 }87 }
84 if (n == 0) {88 if (n == 0) {
85 self.free(old_mem);89 self.free(old_mem);
86 return (*align(alignment) T)(undefined)[0..0];90 return ([*]align(alignment) T)(undefined)[0..0];
87 }91 }
8892
89 const old_byte_slice = ([]u8)(old_mem);93 const old_byte_slice = ([]u8)(old_mem);
...@@ -102,11 +106,11 @@ pub const Allocator = struct {...@@ -102,11 +106,11 @@ pub const Allocator = struct {
102 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.106 /// Reallocate, but `n` must be less than or equal to `old_mem.len`.
103 /// Unlike `realloc`, this function cannot fail.107 /// Unlike `realloc`, this function cannot fail.
104 /// Shrinking to 0 is the same as calling `free`.108 /// Shrinking to 0 is the same as calling `free`.
105 fn shrink(self: *Allocator, comptime T: type, old_mem: []T, n: usize) []T {109 pub fn shrink(self: *Allocator, comptime T: type, old_mem: []T, n: usize) []T {
106 return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);110 return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
107 }111 }
108112
109 fn alignedShrink(self: *Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {113 pub fn alignedShrink(self: *Allocator, comptime T: type, comptime alignment: u29, old_mem: []align(alignment) T, n: usize) []align(alignment) T {
110 if (n == 0) {114 if (n == 0) {
111 self.free(old_mem);115 self.free(old_mem);
112 return old_mem[0..0];116 return old_mem[0..0];
...@@ -123,10 +127,10 @@ pub const Allocator = struct {...@@ -123,10 +127,10 @@ pub const Allocator = struct {
123 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));127 return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
124 }128 }
125129
126 fn free(self: *Allocator, memory: var) void {130 pub fn free(self: *Allocator, memory: var) void {
127 const bytes = ([]const u8)(memory);131 const bytes = ([]const u8)(memory);
128 if (bytes.len == 0) return;132 if (bytes.len == 0) return;
129 const non_const_ptr = @intToPtr(*u8, @ptrToInt(bytes.ptr));133 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(bytes.ptr));
130 self.freeFn(self, non_const_ptr[0..bytes.len]);134 self.freeFn(self, non_const_ptr[0..bytes.len]);
131 }135 }
132};136};
std/net.zig+1-1
...@@ -68,7 +68,7 @@ pub const Address = struct {...@@ -68,7 +68,7 @@ pub const Address = struct {
6868
69pub fn parseIp4(buf: []const u8) !u32 {69pub fn parseIp4(buf: []const u8) !u32 {
70 var result: u32 = undefined;70 var result: u32 = undefined;
71 const out_ptr = ([]u8)((&result)[0..1]);71 const out_ptr = ([]u8)((*[1]u32)(&result)[0..]);
7272
73 var x: u8 = 0;73 var x: u8 = 0;
74 var index: u8 = 0;74 var index: u8 = 0;
std/os/index.zig+2-2
...@@ -1240,7 +1240,7 @@ pub const Dir = struct {...@@ -1240,7 +1240,7 @@ pub const Dir = struct {
1240 const next_index = self.index + darwin_entry.d_reclen;1240 const next_index = self.index + darwin_entry.d_reclen;
1241 self.index = next_index;1241 self.index = next_index;
12421242
1243 const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen];1243 const name = @ptrCast([*]u8, &darwin_entry.d_name)[0..darwin_entry.d_namlen];
12441244
1245 // skip . and .. entries1245 // skip . and .. entries
1246 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {1246 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
...@@ -1704,7 +1704,7 @@ pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {...@@ -1704,7 +1704,7 @@ pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void {
1704 for (args_alloc) |arg| {1704 for (args_alloc) |arg| {
1705 total_bytes += @sizeOf([]u8) + arg.len;1705 total_bytes += @sizeOf([]u8) + arg.len;
1706 }1706 }
1707 const unaligned_allocated_buf = @ptrCast(*const u8, args_alloc.ptr)[0..total_bytes];1707 const unaligned_allocated_buf = @ptrCast([*]const u8, args_alloc.ptr)[0..total_bytes];
1708 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);1708 const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
1709 return allocator.free(aligned_allocated_buf);1709 return allocator.free(aligned_allocated_buf);
1710}1710}
test/cases/align.zig+2-2
...@@ -6,7 +6,7 @@ var foo: u8 align(4) = 100;...@@ -6,7 +6,7 @@ var foo: u8 align(4) = 100;
6test "global variable alignment" {6test "global variable alignment" {
7 assert(@typeOf(&foo).alignment == 4);7 assert(@typeOf(&foo).alignment == 4);
8 assert(@typeOf(&foo) == *align(4) u8);8 assert(@typeOf(&foo) == *align(4) u8);
9 const slice = (&foo)[0..1];9 const slice = (*[1]u8)(&foo)[0..];
10 assert(@typeOf(slice) == []align(4) u8);10 assert(@typeOf(slice) == []align(4) u8);
11}11}
1212
...@@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {...@@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
60test "implicitly decreasing slice alignment" {60test "implicitly decreasing slice alignment" {
61 const a: u32 align(4) = 3;61 const a: u32 align(4) = 3;
62 const b: u32 align(8) = 4;62 const b: u32 align(8) = 4;
63 assert(addUnalignedSlice((&a)[0..1], (&b)[0..1]) == 7);63 assert(addUnalignedSlice((*[1]u32)(&a)[0..], (*[1]u32)(&b)[0..]) == 7);
64}64}
65fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {65fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
66 return a[0] + b[0];66 return a[0] + b[0];
test/cases/array.zig+29
...@@ -115,3 +115,32 @@ test "array len property" {...@@ -115,3 +115,32 @@ test "array len property" {
115 var x: [5]i32 = undefined;115 var x: [5]i32 = undefined;
116 assert(@typeOf(x).len == 5);116 assert(@typeOf(x).len == 5);
117}117}
118
119test "single-item pointer to array indexing and slicing" {
120 testSingleItemPtrArrayIndexSlice();
121 comptime testSingleItemPtrArrayIndexSlice();
122}
123
124fn testSingleItemPtrArrayIndexSlice() void {
125 var array = "aaaa";
126 doSomeMangling(&array);
127 assert(mem.eql(u8, "azya", array));
128}
129
130fn doSomeMangling(array: *[4]u8) void {
131 array[1] = 'z';
132 array[2..3][0] = 'y';
133}
134
135test "implicit cast single-item pointer" {
136 testImplicitCastSingleItemPtr();
137 comptime testImplicitCastSingleItemPtr();
138}
139
140fn testImplicitCastSingleItemPtr() void {
141 var byte: u8 = 100;
142 const slice = (*[1]u8)(&byte)[0..];
143 slice[0] += 1;
144 assert(byte == 101);
145}
146
test/cases/eval.zig+3-3
...@@ -418,9 +418,9 @@ test "string literal used as comptime slice is memoized" {...@@ -418,9 +418,9 @@ test "string literal used as comptime slice is memoized" {
418}418}
419419
420test "comptime slice of undefined pointer of length 0" {420test "comptime slice of undefined pointer of length 0" {
421 const slice1 = (*i32)(undefined)[0..0];421 const slice1 = ([*]i32)(undefined)[0..0];
422 assert(slice1.len == 0);422 assert(slice1.len == 0);
423 const slice2 = (*i32)(undefined)[100..100];423 const slice2 = ([*]i32)(undefined)[100..100];
424 assert(slice2.len == 0);424 assert(slice2.len == 0);
425}425}
426426
...@@ -508,7 +508,7 @@ test "comptime slice of slice preserves comptime var" {...@@ -508,7 +508,7 @@ test "comptime slice of slice preserves comptime var" {
508test "comptime slice of pointer preserves comptime var" {508test "comptime slice of pointer preserves comptime var" {
509 comptime {509 comptime {
510 var buff: [10]u8 = undefined;510 var buff: [10]u8 = undefined;
511 var a = &buff[0];511 var a = buff[0..].ptr;
512 a[0..1][0] = 1;512 a[0..1][0] = 1;
513 assert(buff[0..][0..][0] == 1);513 assert(buff[0..][0..][0] == 1);
514 }514 }
test/cases/misc.zig+2-2
...@@ -274,7 +274,7 @@ test "generic malloc free" {...@@ -274,7 +274,7 @@ test "generic malloc free" {
274}274}
275var some_mem: [100]u8 = undefined;275var some_mem: [100]u8 = undefined;
276fn memAlloc(comptime T: type, n: usize) error![]T {276fn memAlloc(comptime T: type, n: usize) error![]T {
277 return @ptrCast(*T, &some_mem[0])[0..n];277 return @ptrCast([*]T, &some_mem[0])[0..n];
278}278}
279fn memFree(comptime T: type, memory: []T) void {}279fn memFree(comptime T: type, memory: []T) void {}
280280
...@@ -588,7 +588,7 @@ var global_ptr = &gdt[0];...@@ -588,7 +588,7 @@ var global_ptr = &gdt[0];
588588
589// can't really run this test but we can make sure it has no compile error589// can't really run this test but we can make sure it has no compile error
590// and generates code590// and generates code
591const vram = @intToPtr(*volatile u8, 0x20000000)[0..0x8000];591const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000];
592export fn writeToVRam() void {592export fn writeToVRam() void {
593 vram[0] = 'X';593 vram[0] = 'X';
594}594}
test/cases/slice.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const assert = @import("std").debug.assert;1const assert = @import("std").debug.assert;
2const mem = @import("std").mem;2const mem = @import("std").mem;
33
4const x = @intToPtr(*i32, 0x1000)[0..0x500];4const x = @intToPtr([*]i32, 0x1000)[0..0x500];
5const y = x[0x100..];5const y = x[0x100..];
6test "compile time slice of pointer to hard coded address" {6test "compile time slice of pointer to hard coded address" {
7 assert(@ptrToInt(x.ptr) == 0x1000);7 assert(@ptrToInt(x.ptr) == 0x1000);
test/compile_errors.zig+16-5
...@@ -1,13 +1,22 @@...@@ -1,13 +1,22 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "slicing single-item pointer",
6 \\export fn entry(ptr: *i32) void {
7 \\ const slice = ptr[0..2];
8 \\}
9 ,
10 ".tmp_source.zig:2:22: error: slice of single-item pointer",
11 );
12
4 cases.add(13 cases.add(
5 "indexing single-item pointer",14 "indexing single-item pointer",
6 \\export fn entry(ptr: *i32) i32 {15 \\export fn entry(ptr: *i32) i32 {
7 \\ return ptr[1];16 \\ return ptr[1];
8 \\}17 \\}
9 ,18 ,
10 ".tmp_source.zig:2:15: error: indexing not allowed on pointer to single item",19 ".tmp_source.zig:2:15: error: index of single-item pointer",
11 );20 );
1221
13 cases.add(22 cases.add(
...@@ -144,10 +153,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -144,10 +153,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
144 cases.add(153 cases.add(
145 "comptime slice of undefined pointer non-zero len",154 "comptime slice of undefined pointer non-zero len",
146 \\export fn entry() void {155 \\export fn entry() void {
147 \\ const slice = (*i32)(undefined)[0..1];156 \\ const slice = ([*]i32)(undefined)[0..1];
148 \\}157 \\}
149 ,158 ,
150 ".tmp_source.zig:2:36: error: non-zero length slice of undefined pointer",159 ".tmp_source.zig:2:38: error: non-zero length slice of undefined pointer",
151 );160 );
152161
153 cases.add(162 cases.add(
...@@ -3129,14 +3138,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {...@@ -3129,14 +3138,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
3129 \\export fn entry() void {3138 \\export fn entry() void {
3130 \\ var foo = Foo { .a = 1, .b = 10 };3139 \\ var foo = Foo { .a = 1, .b = 10 };
3131 \\ foo.b += 1;3140 \\ foo.b += 1;
3132 \\ bar((&foo.b)[0..1]);3141 \\ bar((*[1]u32)(&foo.b)[0..]);
3133 \\}3142 \\}
3134 \\3143 \\
3135 \\fn bar(x: []u32) void {3144 \\fn bar(x: []u32) void {
3136 \\ x[0] += 1;3145 \\ x[0] += 1;
3137 \\}3146 \\}
3138 ,3147 ,
3139 ".tmp_source.zig:9:17: error: expected type '[]u32', found '[]align(1) u32'",3148 ".tmp_source.zig:9:18: error: cast increases pointer alignment",
3149 ".tmp_source.zig:9:23: note: '*align(1) u32' has alignment 1",
3150 ".tmp_source.zig:9:18: note: '*[1]u32' has alignment 4",
3140 );3151 );
31413152
3142 cases.add(3153 cases.add(