Commit 4c7b52503b
Changed files (7)
test
stage1
behavior
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(