authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-16 15:22:29-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-02-16 15:22:29-05:00
log72ca2b214d4ffbaeed4840a806fb63740cf13c05
tree798850ee35ed9e6943aa1eb01a283137d16b6702
parentcbbd6cfa1e85dc5cda38572f7a1d462a678c2adf

ability to slice an undefined pointer at compile time if the len is 0


5 files changed, 63 insertions(+), 27 deletions(-)

src/codegen.cpp+1
...@@ -4201,6 +4201,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c...@@ -4201,6 +4201,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
4201 continue;4201 continue;
4202 }4202 }
4203 ConstExprValue *field_val = &const_val->data.x_struct.fields[i];4203 ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
4204 assert(field_val->type != nullptr);
4204 LLVMValueRef val = gen_const_val(g, field_val, "");4205 LLVMValueRef val = gen_const_val(g, field_val, "");
4205 fields[type_struct_field->gen_index] = val;4206 fields[type_struct_field->gen_index] = val;
4206 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);4207 make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
src/ir.cpp+41-27
...@@ -8183,7 +8183,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi...@@ -8183,7 +8183,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
8183 }8183 }
81848184
8185 if (instr_is_comptime(value)) {8185 if (instr_is_comptime(value)) {
8186 ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);8186 ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);
8187 if (!val)8187 if (!val)
8188 return ira->codegen->invalid_instruction;8188 return ira->codegen->invalid_instruction;
8189 bool final_is_const = (value->value.type->id == TypeTableEntryIdMetaType) ? is_const : true;8189 bool final_is_const = (value->value.type->id == TypeTableEntryIdMetaType) ? is_const : true;
...@@ -14931,6 +14931,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -14931,6 +14931,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
14931 ConstExprValue *parent_ptr;14931 ConstExprValue *parent_ptr;
14932 size_t abs_offset;14932 size_t abs_offset;
14933 size_t rel_end;14933 size_t rel_end;
14934 bool ptr_is_undef = false;
14934 if (array_type->id == TypeTableEntryIdArray) {14935 if (array_type->id == TypeTableEntryIdArray) {
14935 array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);14936 array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
14936 abs_offset = 0;14937 abs_offset = 0;
...@@ -14938,7 +14939,12 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -14938,7 +14939,12 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
14938 parent_ptr = nullptr;14939 parent_ptr = nullptr;
14939 } else if (array_type->id == TypeTableEntryIdPointer) {14940 } else if (array_type->id == TypeTableEntryIdPointer) {
14940 parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);14941 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) {
14942 case ConstPtrSpecialInvalid:14948 case ConstPtrSpecialInvalid:
14943 case ConstPtrSpecialDiscard:14949 case ConstPtrSpecialDiscard:
14944 zig_unreachable();14950 zig_unreachable();
...@@ -14992,7 +14998,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -14992,7 +14998,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
14992 }14998 }
1499314999
14994 uint64_t start_scalar = bigint_as_unsigned(&casted_start->value.data.x_bigint);15000 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) {
14996 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));15002 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
14997 return ira->codegen->builtin_types.entry_invalid;15003 return ira->codegen->builtin_types.entry_invalid;
14998 }15004 }
...@@ -15003,12 +15009,18 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -15003,12 +15009,18 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
15003 } else {15009 } else {
15004 end_scalar = rel_end;15010 end_scalar = rel_end;
15005 }15011 }
15006 if (end_scalar > rel_end) {15012 if (!ptr_is_undef) {
15007 ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));15013 if (end_scalar > rel_end) {
15008 return ira->codegen->builtin_types.entry_invalid;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 }
15009 }15021 }
15010 if (start_scalar > end_scalar) {15022 if (ptr_is_undef && start_scalar != end_scalar) {
15011 ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end"));15023 ir_add_error(ira, &instruction->base, buf_sprintf("non-zero length slice of undefined pointer"));
15012 return ira->codegen->builtin_types.entry_invalid;15024 return ira->codegen->builtin_types.entry_invalid;
15013 }15025 }
1501415026
...@@ -15024,25 +15036,27 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio...@@ -15024,25 +15036,27 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
15024 if (array_type->id == TypeTableEntryIdArray) {15036 if (array_type->id == TypeTableEntryIdArray) {
15025 ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;15037 ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
15026 }15038 }
15027 } else {15039 } else if (ptr_is_undef) {
15028 switch (parent_ptr->data.x_ptr.special) {15040 ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,
15029 case ConstPtrSpecialInvalid:15041 slice_is_const(return_type));
15030 case ConstPtrSpecialDiscard:15042 ptr_val->special = ConstValSpecialUndef;
15031 zig_unreachable();15043 } else switch (parent_ptr->data.x_ptr.special) {
15032 case ConstPtrSpecialRef:15044 case ConstPtrSpecialInvalid:
15033 init_const_ptr_ref(ira->codegen, ptr_val,15045 case ConstPtrSpecialDiscard:
15034 parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));15046 zig_unreachable();
15035 break;15047 case ConstPtrSpecialRef:
15036 case ConstPtrSpecialBaseArray:15048 init_const_ptr_ref(ira->codegen, ptr_val,
15037 zig_unreachable();15049 parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));
15038 case ConstPtrSpecialBaseStruct:15050 break;
15039 zig_panic("TODO");15051 case ConstPtrSpecialBaseArray:
15040 case ConstPtrSpecialHardCodedAddr:15052 zig_unreachable();
15041 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,15053 case ConstPtrSpecialBaseStruct:
15042 parent_ptr->type->data.pointer.child_type,15054 zig_panic("TODO");
15043 parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,15055 case ConstPtrSpecialHardCodedAddr:
15044 slice_is_const(return_type));15056 init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
15045 }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));
15046 }15060 }
1504715061
15048 ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];15062 ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
std/mem.zig+7
...@@ -42,6 +42,9 @@ pub const Allocator = struct {...@@ -42,6 +42,9 @@ pub const Allocator = struct {
42 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,42 fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
43 n: usize) ![]align(alignment) T43 n: usize) ![]align(alignment) T
44 {44 {
45 if (n == 0) {
46 return (&align(alignment) T)(undefined)[0..0];
47 }
45 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;48 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
46 const byte_slice = try self.allocFn(self, byte_count, alignment);49 const byte_slice = try self.allocFn(self, byte_count, alignment);
47 assert(byte_slice.len == byte_count);50 assert(byte_slice.len == byte_count);
...@@ -62,6 +65,10 @@ pub const Allocator = struct {...@@ -62,6 +65,10 @@ pub const Allocator = struct {
62 if (old_mem.len == 0) {65 if (old_mem.len == 0) {
63 return self.alloc(T, n);66 return self.alloc(T, n);
64 }67 }
68 if (n == 0) {
69 self.free(old_mem);
70 return (&align(alignment) T)(undefined)[0..0];
71 }
6572
66 const old_byte_slice = ([]u8)(old_mem);73 const old_byte_slice = ([]u8)(old_mem);
67 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;74 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
test/cases/eval.zig+7
...@@ -388,3 +388,10 @@ test "string literal used as comptime slice is memoized" {...@@ -388,3 +388,10 @@ test "string literal used as comptime slice is memoized" {
388 comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);388 comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
389 comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);389 comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
390}390}
391
392test "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+7
...@@ -1,6 +1,13 @@...@@ -1,6 +1,13 @@
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("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
4 cases.add("type checking function pointers",11 cases.add("type checking function pointers",
5 \\fn a(b: fn (&const u8) void) void {12 \\fn a(b: fn (&const u8) void) void {
6 \\ b('a');13 \\ b('a');