Skip to content

Commit e53b683

Browse files
authoredJun 5, 2018
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
·
0.15.20.3.0
1 parent 32e0dfd commit e53b683

File tree

21 files changed

+268
-79
lines changed

21 files changed

+268
-79
lines changed
 

‎doc/langref.html.in‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1565,7 +1565,7 @@ var foo: u8 align(4) = 100;
15651565
test "global variable alignment" {
15661566
assert(@typeOf(&foo).alignment == 4);
15671567
assert(@typeOf(&foo) == *align(4) u8);
1568-
const slice = (&foo)[0..1];
1568+
const slice = (*[1]u8)(&foo)[0..];
15691569
assert(@typeOf(slice) == []align(4) u8);
15701570
}
15711571

@@ -1671,7 +1671,7 @@ test "using slices for strings" {
16711671

16721672
test "slice pointer" {
16731673
var array: [10]u8 = undefined;
1674-
const ptr = &array[0];
1674+
const ptr = &array;
16751675

16761676
// You can use slicing syntax to convert a pointer into a slice:
16771677
const slice = ptr[0..5];
@@ -6004,9 +6004,12 @@ const c = @cImport({
60046004
{#code_begin|syntax#}
60056005
const base64 = @import("std").base64;
60066006

6007-
export fn decode_base_64(dest_ptr: *u8, dest_len: usize,
6008-
source_ptr: *const u8, source_len: usize) usize
6009-
{
6007+
export fn decode_base_64(
6008+
dest_ptr: [*]u8,
6009+
dest_len: usize,
6010+
source_ptr: [*]const u8,
6011+
source_len: usize,
6012+
) usize {
60106013
const src = source_ptr[0..source_len];
60116014
const dest = dest_ptr[0..dest_len];
60126015
const base64_decoder = base64.standard_decoder_unsafe;

‎example/mix_o_files/base64.zig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const base64 = @import("std").base64;
22

3-
export fn decode_base_64(dest_ptr: *u8, dest_len: usize, source_ptr: *const u8, source_len: usize) usize {
3+
export fn decode_base_64(dest_ptr: [*]u8, dest_len: usize, source_ptr: [*]const u8, source_len: usize) usize {
44
const src = source_ptr[0..source_len];
55
const dest = dest_ptr[0..dest_len];
66
const base64_decoder = base64.standard_decoder_unsafe;

‎src/all_types.hpp‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ enum ConstParentId {
8383
ConstParentIdStruct,
8484
ConstParentIdArray,
8585
ConstParentIdUnion,
86+
ConstParentIdScalar,
8687
};
8788

8889
struct ConstParent {
@@ -100,6 +101,9 @@ struct ConstParent {
100101
struct {
101102
ConstExprValue *union_val;
102103
} p_union;
104+
struct {
105+
ConstExprValue *scalar_val;
106+
} p_scalar;
103107
} data;
104108
};
105109

@@ -578,6 +582,7 @@ enum CastOp {
578582
CastOpBytesToSlice,
579583
CastOpNumLitToConcrete,
580584
CastOpErrSet,
585+
CastOpBitCast,
581586
};
582587

583588
struct AstNodeFnCallExpr {

‎src/analyze.cpp‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5158,7 +5158,8 @@ void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *arr
51585158
const_val->type = get_slice_type(g, ptr_type);
51595159
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);
51625163
init_const_usize(g, &const_val->data.x_struct.fields[slice_len_index], len);
51635164
}
51645165

@@ -5169,21 +5170,24 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t
51695170
}
51705171

51715172
void 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)
51735174
{
51745175
assert(array_val->type->id == TypeTableEntryIdArray);
51755176
TypeTableEntry *child_type = array_val->type->data.array.child_type;
51765177

51775178
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);
51795181
const_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
51805182
const_val->data.x_ptr.data.base_array.array_val = array_val;
51815183
const_val->data.x_ptr.data.base_array.elem_index = elem_index;
51825184
}
51835185

5184-
ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const) {
5186+
ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const,
5187+
PtrLen ptr_len)
5188+
{
51855189
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);
51875191
return const_val;
51885192
}
51895193

‎src/analyze.hpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,9 @@ ConstExprValue *create_const_ptr_hard_coded_addr(CodeGen *g, TypeTableEntry *poi
152152
size_t addr, bool is_const);
153153

154154
void init_const_ptr_array(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
155-
size_t elem_index, bool is_const);
156-
ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index, bool is_const);
155+
size_t elem_index, bool is_const, PtrLen ptr_len);
156+
ConstExprValue *create_const_ptr_array(CodeGen *g, ConstExprValue *array_val, size_t elem_index,
157+
bool is_const, PtrLen ptr_len);
157158

158159
void init_const_slice(CodeGen *g, ConstExprValue *const_val, ConstExprValue *array_val,
159160
size_t start, size_t len, bool is_const);

‎src/codegen.cpp‎

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2574,6 +2574,8 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
25742574
add_error_range_check(g, wanted_type, g->err_tag_type, expr_val);
25752575
}
25762576
return expr_val;
2577+
case CastOpBitCast:
2578+
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
25772579
}
25782580
zig_unreachable();
25792581
}
@@ -2884,7 +2886,13 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
28842886

28852887
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+
}
28882896
if (safety_check_on) {
28892897
LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
28902898
array_type->data.array.len, false);
@@ -3794,7 +3802,12 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
37943802

37953803
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+
}
37983811
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
37993812
LLVMValueRef end_val;
38003813
if (instruction->end) {
@@ -3835,6 +3848,7 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst
38353848

38363849
return tmp_struct_ptr;
38373850
} else if (array_type->id == TypeTableEntryIdPointer) {
3851+
assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
38383852
LLVMValueRef start_val = ir_llvm_value(g, instruction->start);
38393853
LLVMValueRef end_val = ir_llvm_value(g, instruction->end);
38403854

@@ -4812,7 +4826,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) {
48124826

48134827
static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
48144828
static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
4815-
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
4829+
static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val);
48164830

48174831
static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {
48184832
switch (parent->id) {
@@ -4828,6 +4842,10 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent
48284842
parent->data.p_array.elem_index);
48294843
case ConstParentIdUnion:
48304844
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;
48314849
}
48324850
zig_unreachable();
48334851
}
@@ -4853,7 +4871,8 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
48534871
};
48544872
return LLVMConstInBoundsGEP(base_ptr, indices, 2);
48554873
} else {
4856-
zig_unreachable();
4874+
assert(parent->id == ConstParentIdScalar);
4875+
return base_ptr;
48574876
}
48584877
}
48594878

‎src/ir.cpp‎

Lines changed: 135 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_
107107
static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var);
108108
static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op);
109109
static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval);
110+
static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align);
110111

111112
ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) {
112113
assert(const_val->type->id == TypeTableEntryIdPointer);
@@ -6849,7 +6850,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
68496850
IrInstruction *free_fn = ir_build_load_ptr(irb, scope, node, free_fn_ptr);
68506851
IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
68516852
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);
68536858
IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false);
68546859
IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var);
68556860
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,
87298734
case CastOpNoCast:
87308735
zig_unreachable();
87318736
case CastOpErrSet:
8737+
case CastOpBitCast:
87328738
zig_panic("TODO");
87338739
case CastOpNoop:
87348740
{
@@ -9750,6 +9756,49 @@ static IrInstruction *ir_analyze_err_to_int(IrAnalyze *ira, IrInstruction *sourc
97509756
return result;
97519757
}
97529758

9759+
static 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+
97539802
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
97549803
TypeTableEntry *wanted_type, IrInstruction *value)
97559804
{
@@ -10156,6 +10205,30 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
1015610205
}
1015710206
}
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+
1015910232
// explicit cast from undefined to anything
1016010233
if (actual_type->id == TypeTableEntryIdUndefLit) {
1016110234
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
1316213235
if (type_is_invalid(array_ptr->value.type))
1316313236
return ira->codegen->builtin_types.entry_invalid;
1316413237

13238+
ConstExprValue *orig_array_ptr_val = &array_ptr->value;
13239+
1316513240
IrInstruction *elem_index = elem_ptr_instruction->elem_index->other;
1316613241
if (type_is_invalid(elem_index->value.type))
1316713242
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;
1317013245
assert(ptr_type->id == TypeTableEntryIdPointer);
1317113246

1317213247
TypeTableEntry *array_type = ptr_type->data.pointer.child_type;
@@ -13177,7 +13252,18 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1317713252

1317813253
if (type_is_invalid(array_type)) {
1317913254
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+
}
1318113267
if (array_type->data.array.len == 0) {
1318213268
ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
1318313269
buf_sprintf("index 0 outside array of size 0"));
@@ -13205,7 +13291,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1320513291
} else if (array_type->id == TypeTableEntryIdPointer) {
1320613292
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
1320713293
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"));
1320913295
return ira->codegen->builtin_types.entry_invalid;
1321013296
}
1321113297
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
1329413380
}
1329513381

1329613382
ConstExprValue *array_ptr_val;
13297-
if (array_ptr->value.special != ConstValSpecialRuntime &&
13298-
(array_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
13299-
(array_ptr_val = const_ptr_pointee(ira->codegen, &array_ptr->value)) &&
13383+
if (orig_array_ptr_val->special != ConstValSpecialRuntime &&
13384+
(orig_array_ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar || array_type->id == TypeTableEntryIdArray) &&
13385+
(array_ptr_val = const_ptr_pointee(ira->codegen, orig_array_ptr_val)) &&
1330013386
array_ptr_val->special != ConstValSpecialRuntime &&
1330113387
(array_type->id != TypeTableEntryIdPointer ||
1330213388
array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr))
@@ -13401,7 +13487,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc
1340113487
} else if (array_type->id == TypeTableEntryIdArray) {
1340213488
ConstExprValue *out_val = ir_build_const_from(ira, &elem_ptr_instruction->base);
1340313489
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;
1340513491
out_val->data.x_ptr.data.base_array.array_val = array_ptr_val;
1340613492
out_val->data.x_ptr.data.base_array.elem_index = index;
1340713493
return return_type;
@@ -17406,14 +17492,29 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1740617492
byte_alignment, 0, 0);
1740717493
return_type = get_slice_type(ira->codegen, slice_ptr_type);
1740817494
} else if (array_type->id == TypeTableEntryIdPointer) {
17409-
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, array_type->data.pointer.child_type,
17410-
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
17411-
PtrLenUnknown,
17412-
array_type->data.pointer.alignment, 0, 0);
17413-
return_type = get_slice_type(ira->codegen, slice_ptr_type);
17414-
if (!end) {
17415-
ir_add_error(ira, &instruction->base, buf_sprintf("slice of pointer must include end value"));
17416-
return ira->codegen->builtin_types.entry_invalid;
17495+
if (array_type->data.pointer.ptr_len == PtrLenSingle) {
17496+
TypeTableEntry *main_type = array_type->data.pointer.child_type;
17497+
if (main_type->id == TypeTableEntryIdArray) {
17498+
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen,
17499+
main_type->data.pointer.child_type,
17500+
array_type->data.pointer.is_const, array_type->data.pointer.is_volatile,
17501+
PtrLenUnknown,
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+
}
1741717518
}
1741817519
} else if (is_slice(array_type)) {
1741917520
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
1743317534
size_t abs_offset;
1743417535
size_t rel_end;
1743517536
bool ptr_is_undef = false;
17436-
if (array_type->id == TypeTableEntryIdArray) {
17437-
array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
17438-
abs_offset = 0;
17439-
rel_end = array_type->data.array.len;
17440-
parent_ptr = nullptr;
17537+
if (array_type->id == TypeTableEntryIdArray ||
17538+
(array_type->id == TypeTableEntryIdPointer && array_type->data.pointer.ptr_len == PtrLenSingle))
17539+
{
17540+
if (array_type->id == TypeTableEntryIdPointer) {
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+
}
1744117553
} else if (array_type->id == TypeTableEntryIdPointer) {
17554+
assert(array_type->data.pointer.ptr_len == PtrLenUnknown);
1744217555
parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
1744317556
if (parent_ptr->special == ConstValSpecialUndef) {
1744417557
array_val = nullptr;
@@ -17537,7 +17650,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1753717650
if (array_val) {
1753817651
size_t index = abs_offset + start_scalar;
1753917652
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);
1754117654
if (array_type->id == TypeTableEntryIdArray) {
1754217655
ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
1754317656
} else if (is_slice(array_type)) {

‎std/fmt/errol/index.zig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ pub fn roundToPrecision(float_decimal: *FloatDecimal, precision: usize, mode: Ro
5959
float_decimal.exp += 1;
6060

6161
// 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);
6363
float_decimal.digits = one_before[0 .. float_decimal.digits.len + 1];
6464
float_decimal.digits[0] = '1';
6565
return;

‎std/fmt/index.zig‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ pub fn formatAsciiChar(
278278
comptime Errors: type,
279279
output: fn (@typeOf(context), []const u8) Errors!void,
280280
) Errors!void {
281-
return output(context, (&c)[0..1]);
281+
return output(context, (*[1]u8)(&c)[0..]);
282282
}
283283

284284
pub fn formatBuf(
@@ -603,15 +603,15 @@ fn formatIntSigned(
603603
const uint = @IntType(false, @typeOf(value).bit_count);
604604
if (value < 0) {
605605
const minus_sign: u8 = '-';
606-
try output(context, (&minus_sign)[0..1]);
606+
try output(context, (*[1]u8)(&minus_sign)[0..]);
607607
const new_value = uint(-(value + 1)) + 1;
608608
const new_width = if (width == 0) 0 else (width - 1);
609609
return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
610610
} else if (width == 0) {
611611
return formatIntUnsigned(uint(value), base, uppercase, width, context, Errors, output);
612612
} else {
613613
const plus_sign: u8 = '+';
614-
try output(context, (&plus_sign)[0..1]);
614+
try output(context, (*[1]u8)(&plus_sign)[0..]);
615615
const new_value = uint(value);
616616
const new_width = if (width == 0) 0 else (width - 1);
617617
return formatIntUnsigned(new_value, base, uppercase, new_width, context, Errors, output);
@@ -648,7 +648,7 @@ fn formatIntUnsigned(
648648
const zero_byte: u8 = '0';
649649
var leftover_padding = padding - index;
650650
while (true) {
651-
try output(context, (&zero_byte)[0..1]);
651+
try output(context, (*[1]u8)(&zero_byte)[0..]);
652652
leftover_padding -= 1;
653653
if (leftover_padding == 0) break;
654654
}

‎std/heap.zig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ fn cAlloc(self: *Allocator, n: usize, alignment: u29) ![]u8 {
2424
fn cRealloc(self: *Allocator, old_mem: []u8, new_size: usize, alignment: u29) ![]u8 {
2525
const old_ptr = @ptrCast([*]c_void, old_mem.ptr);
2626
if (c.realloc(old_ptr, new_size)) |buf| {
27-
return @ptrCast(*u8, buf)[0..new_size];
27+
return @ptrCast([*]u8, buf)[0..new_size];
2828
} else if (new_size <= old_mem.len) {
2929
return old_mem[0..new_size];
3030
} else {

‎std/io.zig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,12 @@ pub fn OutStream(comptime WriteError: type) type {
219219
}
220220

221221
pub fn writeByte(self: *Self, byte: u8) !void {
222-
const slice = (&byte)[0..1];
222+
const slice = (*[1]u8)(&byte)[0..];
223223
return self.writeFn(self, slice);
224224
}
225225

226226
pub fn writeByteNTimes(self: *Self, byte: u8, n: usize) !void {
227-
const slice = (&byte)[0..1];
227+
const slice = (*[1]u8)(&byte)[0..];
228228
var i: usize = 0;
229229
while (i < n) : (i += 1) {
230230
try self.writeFn(self, slice);

‎std/macho.zig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ fn readNoEof(in: *io.FileInStream, comptime T: type, result: []T) !void {
164164
return in.stream.readNoEof(([]u8)(result));
165165
}
166166
fn 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..]);
168168
}
169169

170170
fn isSymbol(sym: *const Nlist64) bool {

‎std/mem.zig‎

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,16 @@ pub const Allocator = struct {
3131
/// Guaranteed: `old_mem.len` is the same as what was returned from `allocFn` or `reallocFn`
3232
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 {
3536
if (@sizeOf(T) == 0) return *{};
3637
const slice = try self.alloc(T, 1);
3738
return &slice[0];
3839
}
3940

40-
// TODO once #733 is solved, this will replace create
41-
fn construct(self: *Allocator, init: var) t: {
41+
/// Call destroy with the result
42+
/// TODO once #733 is solved, this will replace create
43+
pub fn construct(self: *Allocator, init: var) t: {
4244
// TODO this is a workaround for type getting parsed as Error!&const T
4345
const T = @typeOf(init).Child;
4446
break :t Error!*T;
@@ -51,17 +53,19 @@ pub const Allocator = struct {
5153
return ptr;
5254
}
5355

54-
fn destroy(self: *Allocator, ptr: var) void {
55-
self.free(ptr[0..1]);
56+
/// `ptr` should be the return value of `construct` or `create`
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)]);
5660
}
5761

58-
fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {
62+
pub fn alloc(self: *Allocator, comptime T: type, n: usize) ![]T {
5963
return self.alignedAlloc(T, @alignOf(T), n);
6064
}
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 {
6367
if (n == 0) {
64-
return (*align(alignment) T)(undefined)[0..0];
68+
return ([*]align(alignment) T)(undefined)[0..0];
6569
}
6670
const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
6771
const byte_slice = try self.allocFn(self, byte_count, alignment);
@@ -73,17 +77,17 @@ pub const Allocator = struct {
7377
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
7478
}
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 {
7781
return self.alignedRealloc(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
7882
}
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 {
8185
if (old_mem.len == 0) {
8286
return self.alloc(T, n);
8387
}
8488
if (n == 0) {
8589
self.free(old_mem);
86-
return (*align(alignment) T)(undefined)[0..0];
90+
return ([*]align(alignment) T)(undefined)[0..0];
8791
}
8892

8993
const old_byte_slice = ([]u8)(old_mem);
@@ -102,11 +106,11 @@ pub const Allocator = struct {
102106
/// Reallocate, but `n` must be less than or equal to `old_mem.len`.
103107
/// Unlike `realloc`, this function cannot fail.
104108
/// 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 {
106110
return self.alignedShrink(T, @alignOf(T), @alignCast(@alignOf(T), old_mem), n);
107111
}
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 {
110114
if (n == 0) {
111115
self.free(old_mem);
112116
return old_mem[0..0];
@@ -123,10 +127,10 @@ pub const Allocator = struct {
123127
return ([]align(alignment) T)(@alignCast(alignment, byte_slice));
124128
}
125129

126-
fn free(self: *Allocator, memory: var) void {
130+
pub fn free(self: *Allocator, memory: var) void {
127131
const bytes = ([]const u8)(memory);
128132
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));
130134
self.freeFn(self, non_const_ptr[0..bytes.len]);
131135
}
132136
};

‎std/net.zig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ pub const Address = struct {
6868

6969
pub fn parseIp4(buf: []const u8) !u32 {
7070
var result: u32 = undefined;
71-
const out_ptr = ([]u8)((&result)[0..1]);
71+
const out_ptr = ([]u8)((*[1]u32)(&result)[0..]);
7272

7373
var x: u8 = 0;
7474
var index: u8 = 0;

‎std/os/index.zig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,7 @@ pub const Dir = struct {
12401240
const next_index = self.index + darwin_entry.d_reclen;
12411241
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

12451245
// skip . and .. entries
12461246
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 {
17041704
for (args_alloc) |arg| {
17051705
total_bytes += @sizeOf([]u8) + arg.len;
17061706
}
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];
17081708
const aligned_allocated_buf = @alignCast(@alignOf([]u8), unaligned_allocated_buf);
17091709
return allocator.free(aligned_allocated_buf);
17101710
}

‎test/cases/align.zig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var foo: u8 align(4) = 100;
66
test "global variable alignment" {
77
assert(@typeOf(&foo).alignment == 4);
88
assert(@typeOf(&foo) == *align(4) u8);
9-
const slice = (&foo)[0..1];
9+
const slice = (*[1]u8)(&foo)[0..];
1010
assert(@typeOf(slice) == []align(4) u8);
1111
}
1212

@@ -60,7 +60,7 @@ fn addUnaligned(a: *align(1) const u32, b: *align(1) const u32) u32 {
6060
test "implicitly decreasing slice alignment" {
6161
const a: u32 align(4) = 3;
6262
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);
6464
}
6565
fn addUnalignedSlice(a: []align(1) const u32, b: []align(1) const u32) u32 {
6666
return a[0] + b[0];

‎test/cases/array.zig‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,32 @@ test "array len property" {
115115
var x: [5]i32 = undefined;
116116
assert(@typeOf(x).len == 5);
117117
}
118+
119+
test "single-item pointer to array indexing and slicing" {
120+
testSingleItemPtrArrayIndexSlice();
121+
comptime testSingleItemPtrArrayIndexSlice();
122+
}
123+
124+
fn testSingleItemPtrArrayIndexSlice() void {
125+
var array = "aaaa";
126+
doSomeMangling(&array);
127+
assert(mem.eql(u8, "azya", array));
128+
}
129+
130+
fn doSomeMangling(array: *[4]u8) void {
131+
array[1] = 'z';
132+
array[2..3][0] = 'y';
133+
}
134+
135+
test "implicit cast single-item pointer" {
136+
testImplicitCastSingleItemPtr();
137+
comptime testImplicitCastSingleItemPtr();
138+
}
139+
140+
fn 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‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,9 @@ test "string literal used as comptime slice is memoized" {
418418
}
419419

420420
test "comptime slice of undefined pointer of length 0" {
421-
const slice1 = (*i32)(undefined)[0..0];
421+
const slice1 = ([*]i32)(undefined)[0..0];
422422
assert(slice1.len == 0);
423-
const slice2 = (*i32)(undefined)[100..100];
423+
const slice2 = ([*]i32)(undefined)[100..100];
424424
assert(slice2.len == 0);
425425
}
426426

@@ -508,7 +508,7 @@ test "comptime slice of slice preserves comptime var" {
508508
test "comptime slice of pointer preserves comptime var" {
509509
comptime {
510510
var buff: [10]u8 = undefined;
511-
var a = &buff[0];
511+
var a = buff[0..].ptr;
512512
a[0..1][0] = 1;
513513
assert(buff[0..][0..][0] == 1);
514514
}

‎test/cases/misc.zig‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ test "generic malloc free" {
274274
}
275275
var some_mem: [100]u8 = undefined;
276276
fn 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];
278278
}
279279
fn memFree(comptime T: type, memory: []T) void {}
280280

@@ -588,7 +588,7 @@ var global_ptr = &gdt[0];
588588

589589
// can't really run this test but we can make sure it has no compile error
590590
// and generates code
591-
const vram = @intToPtr(*volatile u8, 0x20000000)[0..0x8000];
591+
const vram = @intToPtr([*]volatile u8, 0x20000000)[0..0x8000];
592592
export fn writeToVRam() void {
593593
vram[0] = 'X';
594594
}

‎test/cases/slice.zig‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const assert = @import("std").debug.assert;
22
const mem = @import("std").mem;
33

4-
const x = @intToPtr(*i32, 0x1000)[0..0x500];
4+
const x = @intToPtr([*]i32, 0x1000)[0..0x500];
55
const y = x[0x100..];
66
test "compile time slice of pointer to hard coded address" {
77
assert(@ptrToInt(x.ptr) == 0x1000);

‎test/compile_errors.zig‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
const tests = @import("tests.zig");
22

33
pub 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+
413
cases.add(
514
"indexing single-item pointer",
615
\\export fn entry(ptr: *i32) i32 {
716
\\ return ptr[1];
817
\\}
918
,
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",
1120
);
1221

1322
cases.add(
@@ -144,10 +153,10 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
144153
cases.add(
145154
"comptime slice of undefined pointer non-zero len",
146155
\\export fn entry() void {
147-
\\ const slice = (*i32)(undefined)[0..1];
156+
\\ const slice = ([*]i32)(undefined)[0..1];
148157
\\}
149158
,
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",
151160
);
152161

153162
cases.add(
@@ -3129,14 +3138,16 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
31293138
\\export fn entry() void {
31303139
\\ var foo = Foo { .a = 1, .b = 10 };
31313140
\\ foo.b += 1;
3132-
\\ bar((&foo.b)[0..1]);
3141+
\\ bar((*[1]u32)(&foo.b)[0..]);
31333142
\\}
31343143
\\
31353144
\\fn bar(x: []u32) void {
31363145
\\ x[0] += 1;
31373146
\\}
31383147
,
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",
31403151
);
31413152

31423153
cases.add(

0 commit comments

Comments
 (0)
Please sign in to comment.