Commit 72ca2b214d

Andrew Kelley <superjoe30@gmail.com>
2018-02-16 21:22:29
ability to slice an undefined pointer at compile time if the len is 0
1 parent cbbd6cf
Changed files (5)
src/codegen.cpp
@@ -4201,6 +4201,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c
                             continue;
                         }
                         ConstExprValue *field_val = &const_val->data.x_struct.fields[i];
+                        assert(field_val->type != nullptr);
                         LLVMValueRef val = gen_const_val(g, field_val, "");
                         fields[type_struct_field->gen_index] = val;
                         make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(field_val->type, val);
src/ir.cpp
@@ -8183,7 +8183,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi
     }
 
     if (instr_is_comptime(value)) {
-        ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
+        ConstExprValue *val = ir_resolve_const(ira, value, UndefOk);
         if (!val)
             return ira->codegen->invalid_instruction;
         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
         ConstExprValue *parent_ptr;
         size_t abs_offset;
         size_t rel_end;
+        bool ptr_is_undef = false;
         if (array_type->id == TypeTableEntryIdArray) {
             array_val = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
             abs_offset = 0;
@@ -14938,7 +14939,12 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
             parent_ptr = nullptr;
         } else if (array_type->id == TypeTableEntryIdPointer) {
             parent_ptr = const_ptr_pointee(ira->codegen, &ptr_ptr->value);
-            switch (parent_ptr->data.x_ptr.special) {
+            if (parent_ptr->special == ConstValSpecialUndef) {
+                array_val = nullptr;
+                abs_offset = 0;
+                rel_end = SIZE_MAX;
+                ptr_is_undef = true;
+            } else switch (parent_ptr->data.x_ptr.special) {
                 case ConstPtrSpecialInvalid:
                 case ConstPtrSpecialDiscard:
                     zig_unreachable();
@@ -14992,7 +14998,7 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
         }
 
         uint64_t start_scalar = bigint_as_unsigned(&casted_start->value.data.x_bigint);
-        if (start_scalar > rel_end) {
+        if (!ptr_is_undef && start_scalar > rel_end) {
             ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
             return ira->codegen->builtin_types.entry_invalid;
         }
@@ -15003,12 +15009,18 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
         } else {
             end_scalar = rel_end;
         }
-        if (end_scalar > rel_end) {
-            ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
-            return ira->codegen->builtin_types.entry_invalid;
+        if (!ptr_is_undef) {
+            if (end_scalar > rel_end) {
+                ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice"));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
+            if (start_scalar > end_scalar) {
+                ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end"));
+                return ira->codegen->builtin_types.entry_invalid;
+            }
         }
-        if (start_scalar > end_scalar) {
-            ir_add_error(ira, &instruction->base, buf_sprintf("slice start is greater than end"));
+        if (ptr_is_undef && start_scalar != end_scalar) {
+            ir_add_error(ira, &instruction->base, buf_sprintf("non-zero length slice of undefined pointer"));
             return ira->codegen->builtin_types.entry_invalid;
         }
 
@@ -15024,25 +15036,27 @@ static TypeTableEntry *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructio
             if (array_type->id == TypeTableEntryIdArray) {
                 ptr_val->data.x_ptr.mut = ptr_ptr->value.data.x_ptr.mut;
             }
-        } else {
-            switch (parent_ptr->data.x_ptr.special) {
-                case ConstPtrSpecialInvalid:
-                case ConstPtrSpecialDiscard:
-                    zig_unreachable();
-                case ConstPtrSpecialRef:
-                    init_const_ptr_ref(ira->codegen, ptr_val,
-                            parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));
-                    break;
-                case ConstPtrSpecialBaseArray:
-                    zig_unreachable();
-                case ConstPtrSpecialBaseStruct:
-                    zig_panic("TODO");
-                case ConstPtrSpecialHardCodedAddr:
-                    init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
-                        parent_ptr->type->data.pointer.child_type,
-                        parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
-                        slice_is_const(return_type));
-            }
+        } else if (ptr_is_undef) {
+            ptr_val->type = get_pointer_to_type(ira->codegen, parent_ptr->type->data.pointer.child_type,
+                    slice_is_const(return_type));
+            ptr_val->special = ConstValSpecialUndef;
+        } else switch (parent_ptr->data.x_ptr.special) {
+            case ConstPtrSpecialInvalid:
+            case ConstPtrSpecialDiscard:
+                zig_unreachable();
+            case ConstPtrSpecialRef:
+                init_const_ptr_ref(ira->codegen, ptr_val,
+                        parent_ptr->data.x_ptr.data.ref.pointee, slice_is_const(return_type));
+                break;
+            case ConstPtrSpecialBaseArray:
+                zig_unreachable();
+            case ConstPtrSpecialBaseStruct:
+                zig_panic("TODO");
+            case ConstPtrSpecialHardCodedAddr:
+                init_const_ptr_hard_coded_addr(ira->codegen, ptr_val,
+                    parent_ptr->type->data.pointer.child_type,
+                    parent_ptr->data.x_ptr.data.hard_coded_addr.addr + start_scalar,
+                    slice_is_const(return_type));
         }
 
         ConstExprValue *len_val = &out_val->data.x_struct.fields[slice_len_index];
std/mem.zig
@@ -42,6 +42,9 @@ pub const Allocator = struct {
     fn alignedAlloc(self: &Allocator, comptime T: type, comptime alignment: u29,
         n: usize) ![]align(alignment) T
     {
+        if (n == 0) {
+            return (&align(alignment) T)(undefined)[0..0];
+        }
         const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
         const byte_slice = try self.allocFn(self, byte_count, alignment);
         assert(byte_slice.len == byte_count);
@@ -62,6 +65,10 @@ pub const Allocator = struct {
         if (old_mem.len == 0) {
             return self.alloc(T, n);
         }
+        if (n == 0) {
+            self.free(old_mem);
+            return (&align(alignment) T)(undefined)[0..0];
+        }
 
         const old_byte_slice = ([]u8)(old_mem);
         const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
test/cases/eval.zig
@@ -388,3 +388,10 @@ test "string literal used as comptime slice is memoized" {
     comptime assert(TypeWithCompTimeSlice(a).Node == TypeWithCompTimeSlice(b).Node);
     comptime assert(TypeWithCompTimeSlice("link").Node == TypeWithCompTimeSlice("link").Node);
 }
+
+test "comptime slice of undefined pointer of length 0" {
+    const slice1 = (&i32)(undefined)[0..0];
+    assert(slice1.len == 0);
+    const slice2 = (&i32)(undefined)[100..100];
+    assert(slice2.len == 0);
+}
test/compile_errors.zig
@@ -1,6 +1,13 @@
 const tests = @import("tests.zig");
 
 pub fn addCases(cases: &tests.CompileErrorContext) void {
+    cases.add("comptime slice of undefined pointer non-zero len",
+        \\export fn entry() void {
+        \\    const slice = (&i32)(undefined)[0..1];
+        \\}
+    ,
+        ".tmp_source.zig:2:36: error: non-zero length slice of undefined pointer");
+
     cases.add("type checking function pointers",
         \\fn a(b: fn (&const u8) void) void {
         \\    b('a');