Commit 4c7b52503b

Andrew Kelley <andrew@ziglang.org>
2019-11-24 08:14:21
all tests passing
1 parent 2dd20aa
doc/docgen.zig
@@ -954,8 +954,6 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: var, source_token: Tok
             .AngleBracketAngleBracketRight,
             .AngleBracketAngleBracketRightEqual,
             .Tilde,
-            .BracketStarBracket,
-            .BracketStarCBracket,
             => try writeEscaped(out, src[token.start..token.end]),
 
             .Invalid, .Invalid_ampersands => return parseError(
doc/langref.html.in
@@ -563,7 +563,7 @@ const mem = @import("std").mem;
 
 test "string literals" {
     const bytes = "hello";
-    assert(@typeOf(bytes) == *const [5]null u8);
+    assert(@typeOf(bytes) == *const [5:0]u8);
     assert(bytes.len == 5);
     assert(bytes[1] == 'e');
     assert(bytes[5] == 0);
@@ -1795,7 +1795,7 @@ test "null terminated array" {
 
     assert(@typeOf(array) == [4:0]u8);
     assert(array.len == 4);
-    assert(slice[4] == 0);
+    assert(array[4] == 0);
 }
       {#code_end#}
       {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Slices#}
@@ -4863,7 +4863,7 @@ const assert = std.debug.assert;
 const mem = std.mem;
 
 test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
-    const window_name = [1][*]const u8{c"window name"};
+    const window_name = [1][*]const u8{"window name"};
     const x: [*]const ?[*]const u8 = &window_name;
     assert(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name"));
 }
@@ -4905,7 +4905,7 @@ test "float widening" {
       {#code_end#}
       {#header_close#}
       {#header_open|Type Coercion: Arrays and Pointers#}
-      {#code_begin|test#}
+      {#code_begin|test|coerce_arrays_and_ptrs#}
 const std = @import("std");
 const assert = std.debug.assert;
 
@@ -4944,7 +4944,7 @@ test "[N]T to ?[]const T" {
 
 // In this cast, the array length becomes the slice length.
 test "*[N]T to []T" {
-    var buf: [5]u8 = "hello";
+    var buf: [5]u8 = "hello".*;
     const x: []u8 = &buf;
     assert(std.mem.eql(u8, x, "hello"));
 
@@ -4956,7 +4956,7 @@ test "*[N]T to []T" {
 // Single-item pointers to arrays can be coerced to
 // unknown length pointers.
 test "*[N]T to [*]T" {
-    var buf: [5]u8 = "hello";
+    var buf: [5]u8 = "hello".*;
     const x: [*]u8 = &buf;
     assert(x[4] == 'o');
     // x[5] would be an uncaught out of bounds pointer dereference!
@@ -4964,7 +4964,7 @@ test "*[N]T to [*]T" {
 
 // Likewise, it works when the destination type is an optional.
 test "*[N]T to ?[*]T" {
-    var buf: [5]u8 = "hello";
+    var buf: [5]u8 = "hello".*;
     const x: ?[*]u8 = &buf;
     assert(x.?[4] == 'o');
 }
@@ -5135,7 +5135,7 @@ test "coercion of zero bit types" {
       This kind of type resolution chooses a type that all peer types can coerce into. Here are
       some examples:
       </p>
-      {#code_begin|test#}
+      {#code_begin|test|peer_type_resolution#}
 const std = @import("std");
 const assert = std.debug.assert;
 const mem = std.mem;
@@ -5202,13 +5202,13 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
 }
 test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" {
     {
-        var data = "hi";
+        var data = "hi".*;
         const slice = data[0..];
         assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
         assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
     }
     comptime {
-        var data = "hi";
+        var data = "hi".*;
         const slice = data[0..];
         assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
         assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
@@ -8673,7 +8673,7 @@ pub fn main() void {
       <p>At compile-time:</p>
       {#code_begin|test_err|index 5 outside array of size 5#}
 comptime {
-    const array = "hello";
+    const array: [5]u8 = "hello".*;
     const garbage = array[5];
 }
       {#code_end#}
@@ -9649,22 +9649,6 @@ test "assert in release fast mode" {
       </ul>
       {#see_also|Primitive Types#}
       {#header_close#}
-      {#header_open|C String Literals#}
-      {#code_begin|exe#}
-      {#link_libc#}
-extern fn puts([*]const u8) void;
-
-pub fn main() void {
-    puts(c"this has a null terminator");
-    puts(
-        c\\and so
-        c\\does this
-        c\\multiline C string literal
-    );
-}
-      {#code_end#}
-      {#see_also|String Literals and Character Literals#}
-      {#header_close#}
 
       {#header_open|Import from C Header File#}
       <p>
@@ -9679,7 +9663,7 @@ const c = @cImport({
     @cInclude("stdio.h");
 });
 pub fn main() void {
-    _ = c.printf(c"hello\n");
+    _ = c.printf("hello\n");
 }
       {#code_end#}
       <p>
src/analyze.cpp
@@ -496,7 +496,7 @@ static void append_ptr_type_attrs(Buf *type_name, ZigType *ptr_type) {
         } else if (ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) {
             buf_appendf(type_name, ":%" PRIu32, ptr_type->data.pointer.vector_index);
         }
-        buf_appendf(type_name, ")");
+        buf_appendf(type_name, ") ");
     }
     buf_appendf(type_name, "%s%s%s", const_str, volatile_str, allow_zero_str);
     if (ptr_type->data.pointer.inferred_struct_field != nullptr) {
@@ -861,22 +861,6 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) {
         entry->data.structure.fields[slice_len_index]->gen_index = 0;
     }
 
-    ZigType *child_type = ptr_type->data.pointer.child_type;
-    if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile ||
-        ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero)
-    {
-        ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false,
-                PtrLenUnknown, 0, 0, 0, false);
-        ZigType *peer_slice_type = get_slice_type(g, peer_ptr_type);
-
-        entry->size_in_bits = peer_slice_type->size_in_bits;
-        entry->abi_size = peer_slice_type->abi_size;
-        entry->abi_align = peer_slice_type->abi_align;
-
-        *parent_pointer = entry;
-        return entry;
-    }
-
     if (type_has_bits(ptr_type)) {
         entry->size_in_bits = ptr_type->size_in_bits + g->builtin_types.entry_usize->size_in_bits;
         entry->abi_size = ptr_type->abi_size + g->builtin_types.entry_usize->abi_size;
src/codegen.cpp
@@ -3752,7 +3752,7 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
         LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type);
         assert(array_type->data.structure.is_slice);
 
-        ZigType *ptr_type = instruction->base.value.type;
+        ZigType *ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
         if (!type_has_bits(ptr_type)) {
             if (safety_check_on) {
                 assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMIntegerTypeKind);
@@ -3769,7 +3769,8 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI
             assert(len_index != SIZE_MAX);
             LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, (unsigned)len_index, "");
             LLVMValueRef len = gen_load_untyped(g, len_ptr, 0, false, "");
-            add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, len);
+            LLVMIntPredicate upper_op = (ptr_type->data.pointer.sentinel != nullptr) ? LLVMIntULE : LLVMIntULT;
+            add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, upper_op, len);
         }
 
         size_t ptr_index = array_type->data.structure.fields[slice_ptr_index]->gen_index;
src/ir.cpp
@@ -18244,13 +18244,16 @@ static IrInstruction *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructi
 
 static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) {
     assert(ptr_type->id == ZigTypeIdPointer);
-    return get_pointer_to_type_extra(g,
+    return get_pointer_to_type_extra2(g,
             ptr_type->data.pointer.child_type,
             ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile,
             ptr_type->data.pointer.ptr_len,
             new_align,
             ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes,
-            ptr_type->data.pointer.allow_zero);
+            ptr_type->data.pointer.allow_zero,
+            ptr_type->data.pointer.vector_index,
+            ptr_type->data.pointer.inferred_struct_field,
+            ptr_type->data.pointer.sentinel);
 }
 
 static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align) {
@@ -18595,8 +18598,11 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
                     ConstExprValue *len_field = array_ptr_val->data.x_struct.fields[slice_len_index];
                     IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type);
                     ConstExprValue *out_val = &result->value;
+                    ZigType *slice_ptr_type = array_type->data.structure.fields[slice_ptr_index]->type_entry;
                     uint64_t slice_len = bigint_as_u64(&len_field->data.x_bigint);
-                    if (index >= slice_len) {
+                    uint64_t full_slice_len = slice_len +
+                        ((slice_ptr_type->data.pointer.sentinel != nullptr) ? 1 : 0);
+                    if (index >= full_slice_len) {
                         ir_add_error_node(ira, elem_ptr_instruction->base.source_node,
                             buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64,
                                 index, slice_len));
@@ -18615,8 +18621,13 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct
                             {
                                 size_t offset = ptr_field->data.x_ptr.data.base_array.elem_index;
                                 uint64_t new_index = offset + index;
-                                ir_assert(new_index < ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len,
+                                if (ptr_field->data.x_ptr.data.base_array.array_val->data.x_array.special != 
+                                        ConstArraySpecialBuf)
+                                {
+                                    ir_assert(new_index <
+                                            ptr_field->data.x_ptr.data.base_array.array_val->type->data.array.len,
                                         &elem_ptr_instruction->base);
+                                }
                                 out_val->data.x_ptr.special = ConstPtrSpecialBaseArray;
                                 out_val->data.x_ptr.data.base_array.array_val =
                                     ptr_field->data.x_ptr.data.base_array.array_val;
test/stage1/behavior/slice.zig
@@ -65,3 +65,16 @@ test "slice type with custom alignment" {
     slice[1].anything = 42;
     expect(array[1].anything == 42);
 }
+
+test "access len index of sentinel-terminated slice" {
+    const S = struct {
+        fn doTheTest() void {
+            var slice: [:0]const u8 = "hello";
+
+            expect(slice.len == 5);
+            expect(slice[5] == 0);
+        }
+    };
+    S.doTheTest();
+    comptime S.doTheTest();
+}
test/compile_errors.zig
@@ -70,14 +70,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
 
     cases.add(
         "disallow coercion from non-null-terminated pointer to null-terminated pointer",
-        \\extern fn puts(s: [*]null const u8) c_int;
+        \\extern fn puts(s: [*:0]const u8) c_int;
         \\pub fn main() void {
         \\    const no_zero_array = [_]u8{'h', 'e', 'l', 'l', 'o'};
         \\    const no_zero_ptr: [*]const u8 = &no_zero_array;
         \\    _ = puts(no_zero_ptr);
         \\}
     ,
-        "tmp.zig:5:14: error: expected type '[*]null const u8', found '[*]const u8'",
+        "tmp.zig:5:14: error: expected type '[*:0]const u8', found '[*]const u8'",
     );
 
     cases.add(
@@ -784,7 +784,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    strValue = strValue orelse "";
         \\}
     ,
-        "tmp.zig:3:32: error: expected type '[*c]u8', found '*const [0]null u8'",
+        "tmp.zig:3:32: error: expected type '[*c]u8', found '*const [0:0]u8'",
         "tmp.zig:3:32: note: cast discards const qualifier",
     );
 
@@ -2442,12 +2442,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
     );
 
     cases.add(
-        "var not allowed in structs",
+        "var makes structs required to be comptime known",
         \\export fn entry() void {
-        \\   var s = (struct{v: var}){.v=@as(i32, 10)};
+        \\   const S = struct{v: var};
+        \\   var s = S{.v=@as(i32, 10)};
         \\}
     ,
-        "tmp.zig:2:23: error: invalid token: 'var'",
+        "tmp.zig:3:4: error: variable of type 'S' must be const or comptime",
     );
 
     cases.add(
@@ -3357,7 +3358,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\    return a;
         \\}
     ,
-        "tmp.zig:3:12: error: expected type 'i32', found '*const [1]null u8'",
+        "tmp.zig:3:12: error: expected type 'i32', found '*const [1:0]u8'",
     );
 
     cases.add(
@@ -6212,7 +6213,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
         \\}
         \\pub extern fn foo(format: *const u8, ...) void;
     ,
-        "tmp.zig:2:16: error: expected type '*const u8', found '[5]null u8'",
+        "tmp.zig:2:16: error: expected type '*const u8', found '[5:0]u8'",
     );
 
     cases.add(