Skip to content

Commit 72ca2b2

Browse files
committed
ability to slice an undefined pointer at compile time if the len is 0
1 parent cbbd6cf commit 72ca2b2

File tree

5 files changed

+63
-27
lines changed

5 files changed

+63
-27
lines changed

src/codegen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4201,6 +4201,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
42014201
continue;
42024202
}
42034203
ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
4204+
assert(field_val->type != nullptr);
42044205
LLVMValueRef val = gen_const_val(g, field_val, "");
42054206
fields[type_struct_field->gen_index] = val;
42064207
make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);

src/ir.cpp

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8183,7 +8183,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
81838183
}
81848184

81858185
if (instr_is_comptime(value)) {
8186-
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
8186+
ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);
81878187
if (!val)
81888188
return ira->codegen->invalid_instruction;
81898189
bool final_is_const = (value->value.type->id == TypeTableEntryIdMetaType) ? is_const : true;
@@ -14931,14 +14931,20 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1493114931
ConstExprValue *parent_ptr;
1493214932
size_t abs_offset;
1493314933
size_t rel_end;
14934+
bool ptr_is_undef = false;
1493414935
if (array_type->id == TypeTableEntryIdArray) {
1493514936
array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
1493614937
abs_offset = 0;
1493714938
rel_end = array_type->data.array.len;
1493814939
parent_ptr = nullptr;
1493914940
} else if (array_type->id == TypeTableEntryIdPointer) {
1494014941
parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
14941-
switch (parent_ptr->data.x_ptr.special) {
14942+
if (parent_ptr->special == ConstValSpecialUndef) {
14943+
array_val = nullptr;
14944+
abs_offset = 0;
14945+
rel_end = SIZE_MAX;
14946+
ptr_is_undef = true;
14947+
} else switch (parent_ptr->data.x_ptr.special) {
1494214948
case ConstPtrSpecialInvalid:
1494314949
case ConstPtrSpecialDiscard:
1494414950
zig_unreachable();
@@ -14992,7 +14998,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1499214998
}
1499314999

1499415000
uint64_t start_scalar = bigint_as_unsigned(&casted_start->value.data.x_bigint);
14995-
if (start_scalar > rel_end) {
15001+
if (!ptr_is_undef && start_scalar > rel_end) {
1499615002
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
1499715003
return ira->codegen->builtin_types.entry_invalid;
1499815004
}
@@ -15003,12 +15009,18 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1500315009
} else {
1500415010
end_scalar = rel_end;
1500515011
}
15006-
if (end_scalar > rel_end) {
15007-
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
15008-
return ira->codegen->builtin_types.entry_invalid;
15012+
if (!ptr_is_undef) {
15013+
if (end_scalar > rel_end) {
15014+
ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
15015+
return ira->codegen->builtin_types.entry_invalid;
15016+
}
15017+
if (start_scalar > end_scalar) {
15018+
ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end"));
15019+
return ira->codegen->builtin_types.entry_invalid;
15020+
}
1500915021
}
15010-
if (start_scalar > end_scalar) {
15011-
ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end"));
15022+
if (ptr_is_undef && start_scalar != end_scalar) {
15023+
ir_add_error(ira, &instruction->base, buf_sprintf("non-zero length slice of undefined pointer"));
1501215024
return ira->codegen->builtin_types.entry_invalid;
1501315025
}
1501415026

@@ -15024,25 +15036,27 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
1502415036
if (array_type->id == TypeTableEntryIdArray) {
1502515037
ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
1502615038
}
15027-
} else {
15028-
switch (parent_ptr->data.x_ptr.special) {
15029-
case ConstPtrSpecialInvalid:
15030-
case ConstPtrSpecialDiscard:
15031-
zig_unreachable();
15032-
case ConstPtrSpecialRef:
15033-
init_const_ptr_ref(ira->codegen, ptr_val,
15034-
parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));
15035-
break;
15036-
case ConstPtrSpecialBaseArray:
15037-
zig_unreachable();
15038-
case ConstPtrSpecialBaseStruct:
15039-
zig_panic("TODO");
15040-
case ConstPtrSpecialHardCodedAddr:
15041-
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
15042-
parent_ptr->type->data.pointer.child_type,
15043-
parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
15044-
slice_is_const(return_type));
15045-
}
15039+
} else if (ptr_is_undef) {
15040+
ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,
15041+
slice_is_const(return_type));
15042+
ptr_val->special = ConstValSpecialUndef;
15043+
} else switch (parent_ptr->data.x_ptr.special) {
15044+
case ConstPtrSpecialInvalid:
15045+
case ConstPtrSpecialDiscard:
15046+
zig_unreachable();
15047+
case ConstPtrSpecialRef:
15048+
init_const_ptr_ref(ira->codegen, ptr_val,
15049+
parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));
15050+
break;
15051+
case ConstPtrSpecialBaseArray:
15052+
zig_unreachable();
15053+
case ConstPtrSpecialBaseStruct:
15054+
zig_panic("TODO");
15055+
case ConstPtrSpecialHardCodedAddr:
15056+
init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
15057+
parent_ptr->type->data.pointer.child_type,
15058+
parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
15059+
slice_is_const(return_type));
1504615060
}
1504715061

1504815062
ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];

std/mem.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ pub const Allocator = struct {
4242
fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
4343
n: usize) ![]align(alignment) T
4444
{
45+
if (n == 0) {
46+
return (&align(alignment) T)(undefined)[0..0];
47+
}
4548
const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
4649
const byte_slice = try self.allocFn(self, byte_count, alignment);
4750
assert(byte_slice.len == byte_count);
@@ -62,6 +65,10 @@ pub const Allocator = struct {
6265
if (old_mem.len == 0) {
6366
return self.alloc(T, n);
6467
}
68+
if (n == 0) {
69+
self.free(old_mem);
70+
return (&align(alignment) T)(undefined)[0..0];
71+
}
6572

6673
const old_byte_slice = ([]u8)(old_mem);
6774
const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;

test/cases/eval.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,3 +388,10 @@ test "string literal used as comptime slice is memoized" {
388388
comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
389389
comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
390390
}
391+
392+
test "comptime slice of undefined pointer of length 0" {
393+
const slice1 = (&i32)(undefined)[0..0];
394+
assert(slice1.len == 0);
395+
const slice2 = (&i32)(undefined)[100..100];
396+
assert(slice2.len == 0);
397+
}

test/compile_errors.zig

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

33
pub fn addCases(cases: &tests.CompileErrorContext) void {
4+
cases.add("comptime slice of undefined pointer non-zero len",
5+
\\export fn entry() void {
6+
\\ const slice = (&i32)(undefined)[0..1];
7+
\\}
8+
,
9+
".tmp_source.zig:2:36: error: non-zero length slice of undefined pointer");
10+
411
cases.add("type checking function pointers",
512
\\fn a(b: fn (&const u8) void) void {
613
\\ b('a');

0 commit comments

Comments
 (0)