diff --git a/doc/docgen.zig b/doc/docgen.zig index 502ffda784db6bd9ab9cbc9cce156db24a1a2b92..bf53bed7170283bddecd658b0fcf32b58840e694 100644 --- a/doc/docgen.zig +++ b/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( diff --git a/doc/langref.html.in b/doc/langref.html.in index 5ecf312044237c39228ebcb52c76013d31cf0bcd..324906c36fe85c4eadb8b790492a8ddb3c548836 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -546,7 +546,11 @@ pub fn main() void { {#header_close#} {#header_open|String Literals and Character Literals#}

- String literals are UTF-8 encoded byte arrays. + String literals are single-item constant {#link|Pointers#} to null-terminated UTF-8 encoded byte arrays. + The type of string literals encodes both the length, and the fact that they are null-terminated, + and thus they can be {#link|coerced|Type Coercion#} to both {#link|Slices#} and + {#link|Null-Terminated Pointers|Sentinel-Terminated Pointers#}. + Dereferencing string literals converts them to {#link|Arrays#}.

Character literals have type {#syntax#}comptime_int{#endsyntax#}, the same as @@ -558,20 +562,15 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; test "string literals" { - // In Zig a string literal is an array of bytes. - const normal_bytes = "hello"; - assert(@typeOf(normal_bytes) == [5]u8); - assert(normal_bytes.len == 5); - assert(normal_bytes[1] == 'e'); + const bytes = "hello"; + assert(@typeOf(bytes) == *const [5:0]u8); + assert(bytes.len == 5); + assert(bytes[1] == 'e'); + assert(bytes[5] == 0); assert('e' == '\x65'); assert('\u{1f4a9}' == 128169); assert('💯' == 128175); assert(mem.eql(u8, "hello", "h\x65llo")); - - // A C string literal is a null terminated pointer. - const null_terminated_bytes = c"hello"; - assert(@typeOf(null_terminated_bytes) == [*]const u8); - assert(null_terminated_bytes[5] == 0); } {#code_end#} {#see_also|Arrays|Zig Test|Source Encoding#} @@ -641,23 +640,6 @@ const hello_world_in_c = \\} ; {#code_end#} -

- For a multiline C string literal, prepend c to each {#syntax#}\\{#endsyntax#}: -

- {#code_begin|syntax#} -const c_string_literal = - c\\#include - c\\ - c\\int main(int argc, char **argv) { - c\\ printf("hello world\n"); - c\\ return 0; - c\\} -; - {#code_end#} -

- In this example the variable {#syntax#}c_string_literal{#endsyntax#} has type {#syntax#}[*]const u8{#endsyntax#} and - has a terminating null byte. -

{#see_also|@embedFile#} {#header_close#} {#header_close#} @@ -1638,12 +1620,11 @@ comptime { assert(message.len == 5); } -// a string literal is an array literal -const same_message = "hello"; +// A string literal is a pointer to an array literal. +const same_message = "hello".*; comptime { assert(mem.eql(u8, message, same_message)); - assert(@typeOf(message) == @typeOf(same_message)); } test "iterate over an array" { @@ -1799,6 +1780,26 @@ test "multidimensional arrays" { } {#code_end#} {#header_close#} + + {#header_open|Sentinel-Terminated Arrays#} +

+ The syntax {#syntax#}[N:x]T{#endsyntax#} describes an array which has a sentinel element at the + index corresponding to {#syntax#}len{#endsyntax#}. +

+ {#code_begin|test|null_terminated_array#} +const std = @import("std"); +const assert = std.debug.assert; + +test "null terminated array" { + const array = [_:0]u8 {1, 2, 3, 4}; + + assert(@typeOf(array) == [4:0]u8); + assert(array.len == 4); + assert(array[4] == 0); +} + {#code_end#} + {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Slices#} + {#header_close#} {#header_close#} {#header_open|Vectors#} @@ -1899,7 +1900,7 @@ test "pointer array access" { } {#code_end#}

- In Zig, we prefer slices over pointers to null-terminated arrays. + In Zig, we generally prefer {#link|Slices#} rather than {#link|Sentinel-Terminated Pointers#}. You can turn an array or pointer into a slice using slice syntax.

@@ -2111,6 +2112,29 @@ test "allowzero" { } {#code_end#} {#header_close#} + + {#header_open|Sentinel-Terminated Pointers#} +

+ The syntax {#syntax#}[*:x]T{#endsyntax#} describes a pointer that + has a length determined by a sentinel value. This provides protection + against buffer overflow and overreads. +

+ {#code_begin|exe_build_err#} +const std = @import("std"); + +// This is also available as `std.c.printf`. +pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; + +pub fn main() anyerror!void { + _ = printf("Hello, world!\n"); // OK + + const msg = "Hello, world!\n"; + const non_null_terminated_msg: [msg.len]u8 = msg.*; + _ = printf(&non_null_terminated_msg); +} + {#code_end#} + {#see_also|Sentinel-Terminated Slices|Sentinel-Terminated Arrays#} + {#header_close#} {#header_close#} {#header_open|Slices#} @@ -2194,7 +2218,29 @@ test "slice widening" { } {#code_end#} {#see_also|Pointers|for|Arrays#} + + {#header_open|Sentinel-Terminated Slices#} +

+ The syntax {#syntax#}[:x]T{#endsyntax#} is a slice which has a runtime known length + and also guarantees a sentinel value at the element indexed by the length. The type does not + guarantee that there are no sentinel elements before that. Sentinel-terminated slices allow element + access to the {#syntax#}len{#endsyntax#} index. +

+ {#code_begin|test|null_terminated_slice#} +const std = @import("std"); +const assert = std.debug.assert; + +test "null terminated slice" { + const slice: [:0]const u8 = "hello"; + + assert(slice.len == 5); + assert(slice[5] == 0); +} + {#code_end#} + {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Arrays#} {#header_close#} + {#header_close#} + {#header_open|struct#} {#code_begin|test|structs#} // Declare a struct. @@ -4817,9 +4863,9 @@ 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")); + assert(mem.eql(u8, std.mem.toSliceConst(u8, @ptrCast([*:0]const u8, x[0].?)), "window name")); } {#code_end#} {#header_close#} @@ -4859,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; @@ -4898,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")); @@ -4910,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! @@ -4918,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'); } @@ -5089,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:

- {#code_begin|test#} + {#code_begin|test|peer_type_resolution#} const std = @import("std"); const assert = std.debug.assert; const mem = std.mem; @@ -5156,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); @@ -8627,7 +8673,7 @@ pub fn main() void {

At compile-time:

{#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#} @@ -9603,22 +9649,6 @@ test "assert in release fast mode" { {#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#}

@@ -9633,7 +9663,7 @@ const c = @cImport({ @cInclude("stdio.h"); }); pub fn main() void { - _ = c.printf(c"hello\n"); + _ = c.printf("hello\n"); } {#code_end#}

diff --git a/lib/std/buffer.zig b/lib/std/buffer.zig index 24bd23fa74718c1790bfedc4446c568732dd60b4..37414d64d2e791fa165ecff76c396583f54170bc 100644 --- a/lib/std/buffer.zig +++ b/lib/std/buffer.zig @@ -72,11 +72,11 @@ pub const Buffer = struct { self.list.deinit(); } - pub fn toSlice(self: Buffer) []u8 { + pub fn toSlice(self: Buffer) [:0]u8 { return self.list.toSlice()[0..self.len()]; } - pub fn toSliceConst(self: Buffer) []const u8 { + pub fn toSliceConst(self: Buffer) [:0]const u8 { return self.list.toSliceConst()[0..self.len()]; } @@ -131,11 +131,6 @@ pub const Buffer = struct { try self.resize(m.len); mem.copy(u8, self.list.toSlice(), m); } - - /// For passing to C functions. - pub fn ptr(self: Buffer) [*]u8 { - return self.list.items.ptr; - } }; test "simple Buffer" { diff --git a/lib/std/builtin.zig b/lib/std/builtin.zig index 8052f0b31a152b552ea6f1362916ffd8ce8a6985..af045c5231c53d9797facfe6275305a6bb954fdb 100644 --- a/lib/std/builtin.zig +++ b/lib/std/builtin.zig @@ -144,6 +144,10 @@ pub const TypeInfo = union(enum) { alignment: comptime_int, child: type, is_allowzero: bool, + /// The type of the sentinel is the element type of the pointer, which is + /// the value of the `child` field in this struct. However there is no way + /// to refer to that type here, so we use `var`. + sentinel: var, /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -160,6 +164,10 @@ pub const TypeInfo = union(enum) { pub const Array = struct { len: comptime_int, child: type, + /// The type of the sentinel is the element type of the array, which is + /// the value of the `child` field in this struct. However there is no way + /// to refer to that type here, so we use `var`. + sentinel: var, }; /// This data structure is used by the Zig language code generation and diff --git a/lib/std/c.zig b/lib/std/c.zig index 3fd39b26f5412c205ac363ee86f8e9edadd4d859..19c3c8feb84e6c177d88cae6b4e4bea11bd3fe0a 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -63,7 +63,7 @@ pub extern "c" fn fclose(stream: *FILE) c_int; pub extern "c" fn fwrite(ptr: [*]const u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; pub extern "c" fn fread(ptr: [*]u8, size_of_type: usize, item_count: usize, stream: *FILE) usize; -pub extern "c" fn printf(format: [*]const u8, ...) c_int; +pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; pub extern "c" fn abort() noreturn; pub extern "c" fn exit(code: c_int) noreturn; pub extern "c" fn isatty(fd: fd_t) c_int; @@ -102,7 +102,7 @@ pub extern "c" fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [ pub extern "c" fn dup(fd: fd_t) c_int; pub extern "c" fn dup2(old_fd: fd_t, new_fd: fd_t) c_int; pub extern "c" fn readlink(noalias path: [*]const u8, noalias buf: [*]u8, bufsize: usize) isize; -pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*]u8; +pub extern "c" fn realpath(noalias file_name: [*]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; pub extern "c" fn sigprocmask(how: c_int, noalias set: *const sigset_t, noalias oset: ?*sigset_t) c_int; pub extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; pub extern "c" fn sigaction(sig: c_int, noalias act: *const Sigaction, noalias oact: ?*Sigaction) c_int; @@ -110,7 +110,7 @@ pub extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int; pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int; pub extern "c" fn rmdir(path: [*]const u8) c_int; -pub extern "c" fn getenv(name: [*]const u8) ?[*]u8; +pub extern "c" fn getenv(name: [*:0]const u8) ?[*:0]u8; pub extern "c" fn sysctl(name: [*]const c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int; pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int; diff --git a/lib/std/child_process.zig b/lib/std/child_process.zig index 27ba362a18e6582d5a16dfeabb913f6509c662e3..866b3ad67e25c3846d82f7fb47274233a9b67053 100644 --- a/lib/std/child_process.zig +++ b/lib/std/child_process.zig @@ -330,7 +330,7 @@ pub const ChildProcess = struct { const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); const dev_null_fd = if (any_ignore) - os.openC(c"/dev/null", os.O_RDWR, 0) catch |err| switch (err) { + os.openC("/dev/null", os.O_RDWR, 0) catch |err| switch (err) { error.PathAlreadyExists => unreachable, error.NoSpaceLeft => unreachable, error.FileTooBig => unreachable, @@ -441,6 +441,7 @@ pub const ChildProcess = struct { const any_ignore = (self.stdin_behavior == StdIo.Ignore or self.stdout_behavior == StdIo.Ignore or self.stderr_behavior == StdIo.Ignore); + // TODO use CreateFileW here since we are using a string literal for the path const nul_handle = if (any_ignore) windows.CreateFile( "NUL", diff --git a/lib/std/crypto/x25519.zig b/lib/std/crypto/x25519.zig index cd908b08685408407bc24a6bb61d86bd00b9fac7..73e0f033f2e04a39706b7c26aceea14471bd885e 100644 --- a/lib/std/crypto/x25519.zig +++ b/lib/std/crypto/x25519.zig @@ -610,8 +610,8 @@ test "x25519 rfc7748 vector2" { } test "x25519 rfc7748 one iteration" { - const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - const expected_output = "\x42\x2c\x8e\x7a\x62\x27\xd7\xbc\xa1\x35\x0b\x3e\x2b\xb7\x27\x9f\x78\x97\xb8\x7b\xb6\x85\x4b\x78\x3c\x60\xe8\x03\x11\xae\x30\x79"; + const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*; + const expected_output = "\x42\x2c\x8e\x7a\x62\x27\xd7\xbc\xa1\x35\x0b\x3e\x2b\xb7\x27\x9f\x78\x97\xb8\x7b\xb6\x85\x4b\x78\x3c\x60\xe8\x03\x11\xae\x30\x79".*; var k: [32]u8 = initial_value; var u: [32]u8 = initial_value; @@ -634,8 +634,8 @@ test "x25519 rfc7748 1,000 iterations" { return error.SkipZigTest; } - const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - const expected_output = "\x68\x4c\xf5\x9b\xa8\x33\x09\x55\x28\x00\xef\x56\x6f\x2f\x4d\x3c\x1c\x38\x87\xc4\x93\x60\xe3\x87\x5f\x2e\xb9\x4d\x99\x53\x2c\x51"; + const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*; + const expected_output = "\x68\x4c\xf5\x9b\xa8\x33\x09\x55\x28\x00\xef\x56\x6f\x2f\x4d\x3c\x1c\x38\x87\xc4\x93\x60\xe3\x87\x5f\x2e\xb9\x4d\x99\x53\x2c\x51".*; var k: [32]u8 = initial_value; var u: [32]u8 = initial_value; @@ -657,8 +657,8 @@ test "x25519 rfc7748 1,000,000 iterations" { return error.SkipZigTest; } - const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; - const expected_output = "\x7c\x39\x11\xe0\xab\x25\x86\xfd\x86\x44\x97\x29\x7e\x57\x5e\x6f\x3b\xc6\x01\xc0\x88\x3c\x30\xdf\x5f\x4d\xd2\xd2\x4f\x66\x54\x24"; + const initial_value = "\x09\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*; + const expected_output = "\x7c\x39\x11\xe0\xab\x25\x86\xfd\x86\x44\x97\x29\x7e\x57\x5e\x6f\x3b\xc6\x01\xc0\x88\x3c\x30\xdf\x5f\x4d\xd2\xd2\x4f\x66\x54\x24".*; var k: [32]u8 = initial_value; var u: [32]u8 = initial_value; diff --git a/lib/std/cstr.zig b/lib/std/cstr.zig index dd28e5044936f2b0c1e08e6573777f373953712b..4229ff3ed51fd3ab5f379c85f528fc0bdae654e1 100644 --- a/lib/std/cstr.zig +++ b/lib/std/cstr.zig @@ -27,8 +27,8 @@ test "cstr fns" { } fn testCStrFnsImpl() void { - testing.expect(cmp(c"aoeu", c"aoez") == -1); - testing.expect(mem.len(u8, c"123456789") == 9); + testing.expect(cmp("aoeu", "aoez") == -1); + testing.expect(mem.len(u8, "123456789") == 9); } /// Returns a mutable slice with 1 more byte of length which is a null byte. diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 7698443ce879548f290eec7195704cb2d0e263eb..dd4edf832bc98045bfacbe42cf55f110f347f337 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -401,7 +401,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres const vaddr_start = coff_section.header.virtual_address + proc_sym.CodeOffset; const vaddr_end = vaddr_start + proc_sym.CodeSize; if (relative_address >= vaddr_start and relative_address < vaddr_end) { - break mem.toSliceConst(u8, @ptrCast([*]u8, proc_sym) + @sizeOf(pdb.ProcSym)); + break mem.toSliceConst(u8, @ptrCast([*:0]u8, proc_sym) + @sizeOf(pdb.ProcSym)); } }, else => {}, @@ -703,9 +703,9 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt return; }; - const symbol_name = mem.toSliceConst(u8, di.strings.ptr + symbol.nlist.n_strx); + const symbol_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + symbol.nlist.n_strx)); const compile_unit_name = if (symbol.ofile) |ofile| blk: { - const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); + const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); break :blk fs.path.basename(ofile_path); } else "???"; if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { @@ -915,7 +915,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { for (present) |_| { const name_offset = try pdb_stream.stream.readIntLittle(u32); const name_index = try pdb_stream.stream.readIntLittle(u32); - const name = mem.toSlice(u8, name_bytes.ptr + name_offset); + const name = mem.toSlice(u8, @ptrCast([*:0]u8, name_bytes.ptr + name_offset)); if (mem.eql(u8, name, "/names")) { break :str_tab_index name_index; } @@ -1708,7 +1708,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u const gop = try di.ofiles.getOrPut(ofile); const mach_o_file = if (gop.found_existing) &gop.kv.value else blk: { errdefer _ = di.ofiles.remove(ofile); - const ofile_path = mem.toSliceConst(u8, di.strings.ptr + ofile.n_strx); + const ofile_path = mem.toSliceConst(u8, @ptrCast([*:0]const u8, di.strings.ptr + ofile.n_strx)); gop.kv.value = MachOFile{ .bytes = try std.fs.Dir.cwd().readFileAllocAligned( @@ -1741,7 +1741,7 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u if (sect.flags & macho.SECTION_TYPE == macho.S_REGULAR and (sect.flags & macho.SECTION_ATTRIBUTES) & macho.S_ATTR_DEBUG == macho.S_ATTR_DEBUG) { - const sect_name = mem.toSliceConst(u8, §.sectname); + const sect_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, §.sectname)); if (mem.eql(u8, sect_name, "__debug_line")) { gop.kv.value.sect_debug_line = sect; } else if (mem.eql(u8, sect_name, "__debug_info")) { @@ -2323,8 +2323,8 @@ fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 { } } -fn readStringMem(ptr: *[*]const u8) []const u8 { - const result = mem.toSliceConst(u8, ptr.*); +fn readStringMem(ptr: *[*]const u8) [:0]const u8 { + const result = mem.toSliceConst(u8, @ptrCast([*:0]const u8, ptr.*)); ptr.* += result.len + 1; return result; } diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 0e8792ca9099bff4bf0c2673b7e3d6f34cb1dce4..a4da9a8b03a38725a493b759c45d7fcef45e57b1 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -140,7 +140,7 @@ pub const LinuxDynLib = struct { }; pub const ElfLib = struct { - strings: [*]u8, + strings: [*:0]u8, syms: [*]elf.Sym, hashtab: [*]os.Elf_Symndx, versym: ?[*]u16, @@ -175,7 +175,7 @@ pub const ElfLib = struct { const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation; if (base == maxInt(usize)) return error.BaseNotFound; - var maybe_strings: ?[*]u8 = null; + var maybe_strings: ?[*:0]u8 = null; var maybe_syms: ?[*]elf.Sym = null; var maybe_hashtab: ?[*]os.Elf_Symndx = null; var maybe_versym: ?[*]u16 = null; @@ -186,7 +186,7 @@ pub const ElfLib = struct { while (dynv[i] != 0) : (i += 2) { const p = base + dynv[i + 1]; switch (dynv[i]) { - elf.DT_STRTAB => maybe_strings = @intToPtr([*]u8, p), + elf.DT_STRTAB => maybe_strings = @intToPtr([*:0]u8, p), elf.DT_SYMTAB => maybe_syms = @intToPtr([*]elf.Sym, p), elf.DT_HASH => maybe_hashtab = @intToPtr([*]os.Elf_Symndx, p), elf.DT_VERSYM => maybe_versym = @intToPtr([*]u16, p), @@ -230,7 +230,7 @@ pub const ElfLib = struct { } }; -fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*]u8) bool { +fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [*:0]u8) bool { var def = def_arg; const vsym = @bitCast(u32, vsym_arg) & 0x7fff; while (true) { diff --git a/lib/std/event/fs.zig b/lib/std/event/fs.zig index eef5cfae7d0b0a2191f1aeeacf187bea82d58f76..965302e1e6a9818c75aa65212859f2b68987dd49 100644 --- a/lib/std/event/fs.zig +++ b/lib/std/event/fs.zig @@ -58,8 +58,7 @@ pub const Request = struct { }; pub const Open = struct { - /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265 - path: []const u8, + path: [:0]const u8, flags: u32, mode: File.Mode, result: Error!fd_t, @@ -68,8 +67,7 @@ pub const Request = struct { }; pub const WriteFile = struct { - /// must be null terminated. TODO https://github.com/ziglang/zig/issues/265 - path: []const u8, + path: [:0]const u8, contents: []const u8, mode: File.Mode, result: Error!void, diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 743ca4d9201a4a1b667b7768cc31115740c55cd3..cbb11cba36617e89f6d8a3679612825c9f3a6fb5 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -1,8 +1,6 @@ const std = @import("std.zig"); const math = std.math; -const debug = std.debug; -const assert = debug.assert; -const testing = std.testing; +const assert = std.debug.assert; const mem = std.mem; const builtin = @import("builtin"); const errol = @import("fmt/errol.zig"); @@ -36,7 +34,7 @@ fn nextArg(comptime used_pos_args: *u32, comptime maybe_pos_arg: ?comptime_int, fn peekIsAlign(comptime fmt: []const u8) bool { // Should only be called during a state transition to the format segment. - std.debug.assert(fmt[0] == ':'); + comptime assert(fmt[0] == ':'); inline for (([_]u8{ 1, 2 })[0..]) |i| { if (fmt.len > i and (fmt[i] == '<' or fmt[i] == '^' or fmt[i] == '>')) { @@ -1009,13 +1007,13 @@ pub fn parseInt(comptime T: type, buf: []const u8, radix: u8) !T { } test "parseInt" { - testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10); - testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10); - testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter); - testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter); - testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter); - testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255); - testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); + std.testing.expect((parseInt(i32, "-10", 10) catch unreachable) == -10); + std.testing.expect((parseInt(i32, "+10", 10) catch unreachable) == 10); + std.testing.expect(if (parseInt(i32, " 10", 10)) |_| false else |err| err == error.InvalidCharacter); + std.testing.expect(if (parseInt(i32, "10 ", 10)) |_| false else |err| err == error.InvalidCharacter); + std.testing.expect(if (parseInt(u32, "-10", 10)) |_| false else |err| err == error.InvalidCharacter); + std.testing.expect((parseInt(u8, "255", 10) catch unreachable) == 255); + std.testing.expect(if (parseInt(u8, "256", 10)) |_| false else |err| err == error.Overflow); } const ParseUnsignedError = error{ @@ -1040,30 +1038,30 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned } test "parseUnsigned" { - testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); - testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); - testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); + std.testing.expect((try parseUnsigned(u16, "050124", 10)) == 50124); + std.testing.expect((try parseUnsigned(u16, "65535", 10)) == 65535); + std.testing.expectError(error.Overflow, parseUnsigned(u16, "65536", 10)); - testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); - testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); + std.testing.expect((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); + std.testing.expectError(error.Overflow, parseUnsigned(u64, "10000000000000000", 16)); - testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); + std.testing.expect((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); - testing.expect((try parseUnsigned(u7, "1", 10)) == 1); - testing.expect((try parseUnsigned(u7, "1000", 2)) == 8); + std.testing.expect((try parseUnsigned(u7, "1", 10)) == 1); + std.testing.expect((try parseUnsigned(u7, "1000", 2)) == 8); - testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10)); - testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8)); + std.testing.expectError(error.InvalidCharacter, parseUnsigned(u32, "f", 10)); + std.testing.expectError(error.InvalidCharacter, parseUnsigned(u8, "109", 8)); - testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); + std.testing.expect((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); // these numbers should fit even though the radix itself doesn't fit in the destination type - testing.expect((try parseUnsigned(u1, "0", 10)) == 0); - testing.expect((try parseUnsigned(u1, "1", 10)) == 1); - testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10)); - testing.expect((try parseUnsigned(u1, "001", 16)) == 1); - testing.expect((try parseUnsigned(u2, "3", 16)) == 3); - testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16)); + std.testing.expect((try parseUnsigned(u1, "0", 10)) == 0); + std.testing.expect((try parseUnsigned(u1, "1", 10)) == 1); + std.testing.expectError(error.Overflow, parseUnsigned(u1, "2", 10)); + std.testing.expect((try parseUnsigned(u1, "001", 16)) == 1); + std.testing.expect((try parseUnsigned(u2, "3", 16)) == 3); + std.testing.expectError(error.Overflow, parseUnsigned(u2, "4", 16)); } pub const parseFloat = @import("fmt/parse_float.zig").parseFloat; @@ -1134,19 +1132,19 @@ fn countSize(size: *usize, bytes: []const u8) (error{}!void) { test "bufPrintInt" { var buffer: [100]u8 = undefined; const buf = buffer[0..]; - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 2, false, FormatOptions{}), "-101111000110000101001110")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 10, false, FormatOptions{}), "-12345678")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, false, FormatOptions{}), "-bc614e")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, true, FormatOptions{}), "-BC614E")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 2, false, FormatOptions{}), "-101111000110000101001110")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 10, false, FormatOptions{}), "-12345678")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, false, FormatOptions{}), "-bc614e")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -12345678), 16, true, FormatOptions{}), "-BC614E")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 12345678), 10, true, FormatOptions{}), "12345678")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 12345678), 10, true, FormatOptions{}), "12345678")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 666), 10, false, FormatOptions{ .width = 6 }), " 666")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 6 }), " 1234")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 1 }), "1234")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 666), 10, false, FormatOptions{ .width = 6 }), " 666")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 6 }), " 1234")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(u32, 0x1234), 16, false, FormatOptions{ .width = 1 }), "1234")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, 42), 10, false, FormatOptions{ .width = 3 }), "+42")); - testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -42), 10, false, FormatOptions{ .width = 3 }), "-42")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, 42), 10, false, FormatOptions{ .width = 3 }), "+42")); + std.testing.expect(mem.eql(u8, bufPrintIntToSlice(buf, @as(i32, -42), 10, false, FormatOptions{ .width = 3 }), "-42")); } fn bufPrintIntToSlice(buf: []u8, value: var, base: u8, uppercase: bool, options: FormatOptions) []u8 { @@ -1163,7 +1161,7 @@ test "parse u64 digit too big" { test "parse unsigned comptime" { comptime { - testing.expect((try parseUnsigned(usize, "2", 10)) == 2); + std.testing.expect((try parseUnsigned(usize, "2", 10)) == 2); } } @@ -1218,23 +1216,23 @@ test "buffer" { var context = BufPrintContext{ .remaining = buf1[0..] }; try formatType(1234, "", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth); var res = buf1[0 .. buf1.len - context.remaining.len]; - testing.expect(mem.eql(u8, res, "1234")); + std.testing.expect(mem.eql(u8, res, "1234")); context = BufPrintContext{ .remaining = buf1[0..] }; try formatType('a', "c", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth); res = buf1[0 .. buf1.len - context.remaining.len]; - testing.expect(mem.eql(u8, res, "a")); + std.testing.expect(mem.eql(u8, res, "a")); context = BufPrintContext{ .remaining = buf1[0..] }; try formatType(0b1100, "b", FormatOptions{}, &context, error{BufferTooSmall}, bufPrintWrite, default_max_depth); res = buf1[0 .. buf1.len - context.remaining.len]; - testing.expect(mem.eql(u8, res, "1100")); + std.testing.expect(mem.eql(u8, res, "1100")); } } test "array" { { - const value: [3]u8 = "abc"; + const value: [3]u8 = "abc".*; try testFmt("array: abc\n", "array: {}\n", value); try testFmt("array: abc\n", "array: {}\n", &value); @@ -1278,8 +1276,8 @@ test "pointer" { } test "cstr" { - try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C"); - try testFmt("cstr: Test C \n", "cstr: {s:10}\n", c"Test C"); + try testFmt("cstr: Test C\n", "cstr: {s}\n", "Test C"); + try testFmt("cstr: Test C \n", "cstr: {s:10}\n", "Test C"); } test "filesize" { @@ -1479,10 +1477,10 @@ test "union" { var buf: [100]u8 = undefined; const uu_result = try bufPrint(buf[0..], "{}", uu_inst); - testing.expect(mem.eql(u8, uu_result[0..3], "UU@")); + std.testing.expect(mem.eql(u8, uu_result[0..3], "UU@")); const eu_result = try bufPrint(buf[0..], "{}", eu_inst); - testing.expect(mem.eql(u8, uu_result[0..3], "EU@")); + std.testing.expect(mem.eql(u8, uu_result[0..3], "EU@")); } test "enum" { @@ -1569,11 +1567,11 @@ pub fn trim(buf: []const u8) []const u8 { } test "trim" { - testing.expect(mem.eql(u8, "abc", trim("\n abc \t"))); - testing.expect(mem.eql(u8, "", trim(" "))); - testing.expect(mem.eql(u8, "", trim(""))); - testing.expect(mem.eql(u8, "abc", trim(" abc"))); - testing.expect(mem.eql(u8, "abc", trim("abc "))); + std.testing.expect(mem.eql(u8, "abc", trim("\n abc \t"))); + std.testing.expect(mem.eql(u8, "", trim(" "))); + std.testing.expect(mem.eql(u8, "", trim(""))); + std.testing.expect(mem.eql(u8, "abc", trim(" abc"))); + std.testing.expect(mem.eql(u8, "abc", trim("abc "))); } pub fn isWhiteSpace(byte: u8) bool { @@ -1607,7 +1605,7 @@ test "formatIntValue with comptime_int" { var buf = try std.Buffer.init(std.debug.global_allocator, ""); try formatIntValue(value, "", FormatOptions{}, &buf, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append); - assert(mem.eql(u8, buf.toSlice(), "123456789123456789")); + std.testing.expect(mem.eql(u8, buf.toSlice(), "123456789123456789")); } test "formatType max_depth" { @@ -1661,19 +1659,19 @@ test "formatType max_depth" { var buf0 = try std.Buffer.init(std.debug.global_allocator, ""); try formatType(inst, "", FormatOptions{}, &buf0, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 0); - assert(mem.eql(u8, buf0.toSlice(), "S{ ... }")); + std.testing.expect(mem.eql(u8, buf0.toSlice(), "S{ ... }")); var buf1 = try std.Buffer.init(std.debug.global_allocator, ""); try formatType(inst, "", FormatOptions{}, &buf1, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 1); - assert(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); + std.testing.expect(mem.eql(u8, buf1.toSlice(), "S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }")); var buf2 = try std.Buffer.init(std.debug.global_allocator, ""); try formatType(inst, "", FormatOptions{}, &buf2, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 2); - assert(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); + std.testing.expect(mem.eql(u8, buf2.toSlice(), "S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }")); var buf3 = try std.Buffer.init(std.debug.global_allocator, ""); try formatType(inst, "", FormatOptions{}, &buf3, @typeOf(std.Buffer.append).ReturnType.ErrorSet, std.Buffer.append, 3); - assert(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); + std.testing.expect(mem.eql(u8, buf3.toSlice(), "S{ .a = S{ .a = S{ .a = S{ ... }, .tu = TU{ ... }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ ... } }, .e = E.Two, .vec = (10.200,2.220) }, .tu = TU{ .ptr = TU{ .ptr = TU{ ... } } }, .e = E.Two, .vec = (10.200,2.220) }")); } test "positional" { diff --git a/lib/std/fs.zig b/lib/std/fs.zig index bc2c921d1ef8fd3f73e7e018081b8983164a1e4d..761e3b8c14b6b4afe90feae0f6f02b9fe87c8a7d 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -28,6 +28,7 @@ pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirE /// This represents the maximum size of a UTF-8 encoded file path. /// All file system operations which return a path are guaranteed to /// fit into a UTF-8 encoded array of this length. +/// The byte count includes room for a null sentinel byte. pub const MAX_PATH_BYTES = switch (builtin.os) { .linux, .macosx, .ios, .freebsd, .netbsd, .dragonfly => os.PATH_MAX, // Each UTF-16LE character may be expanded to 3 UTF-8 bytes. @@ -227,7 +228,7 @@ pub const AtomicFile = struct { try crypto.randomBytes(rand_buf[0..]); b64_fs_encoder.encode(tmp_path_buf[dirname_component_len..tmp_path_len], rand_buf); - const file = File.openWriteNoClobberC(&tmp_path_buf, mode) catch |err| switch (err) { + const file = File.openWriteNoClobberC(@ptrCast([*:0]u8, &tmp_path_buf), mode) catch |err| switch (err) { error.PathAlreadyExists => continue, // TODO zig should figure out that this error set does not include PathAlreadyExists since // it is handled in the above switch @@ -247,7 +248,7 @@ pub const AtomicFile = struct { pub fn deinit(self: *AtomicFile) void { if (!self.finished) { self.file.close(); - deleteFileC(&self.tmp_path_buf) catch {}; + deleteFileC(@ptrCast([*:0]u8, &self.tmp_path_buf)) catch {}; self.finished = true; } } @@ -258,11 +259,11 @@ pub const AtomicFile = struct { self.finished = true; if (builtin.os == .windows) { const dest_path_w = try os.windows.sliceToPrefixedFileW(self.dest_path); - const tmp_path_w = try os.windows.cStrToPrefixedFileW(&self.tmp_path_buf); + const tmp_path_w = try os.windows.cStrToPrefixedFileW(@ptrCast([*:0]u8, &self.tmp_path_buf)); return os.renameW(&tmp_path_w, &dest_path_w); } const dest_path_c = try os.toPosixPath(self.dest_path); - return os.renameC(&self.tmp_path_buf, &dest_path_c); + return os.renameC(@ptrCast([*:0]u8, &self.tmp_path_buf), &dest_path_c); } }; @@ -274,12 +275,12 @@ pub fn makeDir(dir_path: []const u8) !void { } /// Same as `makeDir` except the parameter is a null-terminated UTF8-encoded string. -pub fn makeDirC(dir_path: [*]const u8) !void { +pub fn makeDirC(dir_path: [*:0]const u8) !void { return os.mkdirC(dir_path, default_new_dir_mode); } /// Same as `makeDir` except the parameter is a null-terminated UTF16LE-encoded string. -pub fn makeDirW(dir_path: [*]const u16) !void { +pub fn makeDirW(dir_path: [*:0]const u16) !void { return os.mkdirW(dir_path, default_new_dir_mode); } @@ -327,12 +328,12 @@ pub fn deleteDir(dir_path: []const u8) !void { } /// Same as `deleteDir` except the parameter is a null-terminated UTF8-encoded string. -pub fn deleteDirC(dir_path: [*]const u8) !void { +pub fn deleteDirC(dir_path: [*:0]const u8) !void { return os.rmdirC(dir_path); } /// Same as `deleteDir` except the parameter is a null-terminated UTF16LE-encoded string. -pub fn deleteDirW(dir_path: [*]const u16) !void { +pub fn deleteDirW(dir_path: [*:0]const u16) !void { return os.rmdirW(dir_path); } @@ -533,7 +534,7 @@ pub const Dir = struct { const next_index = self.index + linux_entry.reclen(); self.index = next_index; - const name = mem.toSlice(u8, @ptrCast([*]u8, &linux_entry.d_name)); + const name = mem.toSlice(u8, @ptrCast([*:0]u8, &linux_entry.d_name)); // skip . and .. entries if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) { @@ -688,7 +689,7 @@ pub const Dir = struct { } /// Same as `open` except the parameter is null-terminated. - pub fn openC(dir_path_c: [*]const u8) OpenError!Dir { + pub fn openC(dir_path_c: [*:0]const u8) OpenError!Dir { return cwd().openDirC(dir_path_c); } @@ -708,7 +709,7 @@ pub const Dir = struct { } /// Call `File.close` on the result when done. - pub fn openReadC(self: Dir, sub_path: [*]const u8) File.OpenError!File { + pub fn openReadC(self: Dir, sub_path: [*:0]const u8) File.OpenError!File { if (builtin.os == .windows) { const path_w = try os.windows.cStrToPrefixedFileW(sub_path); return self.openReadW(&path_w); @@ -719,7 +720,7 @@ pub const Dir = struct { return File.openHandle(fd); } - pub fn openReadW(self: Dir, sub_path_w: [*]const u16) File.OpenError!File { + pub fn openReadW(self: Dir, sub_path_w: [*:0]const u16) File.OpenError!File { const w = os.windows; var result = File{ .handle = undefined }; @@ -786,7 +787,7 @@ pub const Dir = struct { } /// Same as `openDir` except the parameter is null-terminated. - pub fn openDirC(self: Dir, sub_path_c: [*]const u8) OpenError!Dir { + pub fn openDirC(self: Dir, sub_path_c: [*:0]const u8) OpenError!Dir { if (builtin.os == .windows) { const sub_path_w = try os.windows.cStrToPrefixedFileW(sub_path_c); return self.openDirW(&sub_path_w); @@ -805,7 +806,7 @@ pub const Dir = struct { /// Same as `openDir` except the path parameter is UTF16LE, NT-prefixed. /// This function is Windows-only. - pub fn openDirW(self: Dir, sub_path_w: [*]const u16) OpenError!Dir { + pub fn openDirW(self: Dir, sub_path_w: [*:0]const u16) OpenError!Dir { const w = os.windows; var result = Dir{ @@ -868,7 +869,7 @@ pub const Dir = struct { } /// Same as `deleteFile` except the parameter is null-terminated. - pub fn deleteFileC(self: Dir, sub_path_c: [*]const u8) DeleteFileError!void { + pub fn deleteFileC(self: Dir, sub_path_c: [*:0]const u8) DeleteFileError!void { os.unlinkatC(self.fd, sub_path_c, 0) catch |err| switch (err) { error.DirNotEmpty => unreachable, // not passing AT_REMOVEDIR else => |e| return e, @@ -903,7 +904,7 @@ pub const Dir = struct { } /// Same as `deleteDir` except the parameter is null-terminated. - pub fn deleteDirC(self: Dir, sub_path_c: [*]const u8) DeleteDirError!void { + pub fn deleteDirC(self: Dir, sub_path_c: [*:0]const u8) DeleteDirError!void { os.unlinkatC(self.fd, sub_path_c, os.AT_REMOVEDIR) catch |err| switch (err) { error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR else => |e| return e, @@ -912,7 +913,7 @@ pub const Dir = struct { /// Same as `deleteDir` except the parameter is UTF16LE, NT prefixed. /// This function is Windows-only. - pub fn deleteDirW(self: Dir, sub_path_w: [*]const u16) DeleteDirError!void { + pub fn deleteDirW(self: Dir, sub_path_w: [*:0]const u16) DeleteDirError!void { os.unlinkatW(self.fd, sub_path_w, os.AT_REMOVEDIR) catch |err| switch (err) { error.IsDir => unreachable, // not possible since we pass AT_REMOVEDIR else => |e| return e, @@ -927,7 +928,7 @@ pub const Dir = struct { } /// Same as `readLink`, except the `pathname` parameter is null-terminated. - pub fn readLinkC(self: Dir, sub_path_c: [*]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { + pub fn readLinkC(self: Dir, sub_path_c: [*:0]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { return os.readlinkatC(self.fd, sub_path_c, buffer); } @@ -1240,7 +1241,7 @@ pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfE pub fn openSelfExe() OpenSelfExeError!File { if (builtin.os == .linux) { - return File.openReadC(c"/proc/self/exe"); + return File.openReadC("/proc/self/exe"); } if (builtin.os == .windows) { const wide_slice = selfExePathW(); @@ -1250,7 +1251,8 @@ pub fn openSelfExe() OpenSelfExeError!File { var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; - return File.openReadC(self_exe_path.ptr); + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + return File.openReadC(@ptrCast([*:0]u8, self_exe_path.ptr)); } test "openSelfExe" { @@ -1277,23 +1279,23 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { var u32_len: u32 = out_buffer.len; const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len); if (rc != 0) return error.NameTooLong; - return mem.toSlice(u8, out_buffer); + return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer)); } switch (builtin.os) { - .linux => return os.readlinkC(c"/proc/self/exe", out_buffer), + .linux => return os.readlinkC("/proc/self/exe", out_buffer), .freebsd, .dragonfly => { var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 }; var out_len: usize = out_buffer.len; try os.sysctl(&mib, out_buffer, &out_len, null, 0); // TODO could this slice from 0 to out_len instead? - return mem.toSlice(u8, out_buffer); + return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer)); }, .netbsd => { var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC_ARGS, -1, os.KERN_PROC_PATHNAME }; var out_len: usize = out_buffer.len; try os.sysctl(&mib, out_buffer, &out_len, null, 0); // TODO could this slice from 0 to out_len instead? - return mem.toSlice(u8, out_buffer); + return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer)); }, .windows => { const utf16le_slice = selfExePathW(); @@ -1306,9 +1308,9 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { } /// The result is UTF16LE-encoded. -pub fn selfExePathW() []const u16 { +pub fn selfExePathW() [:0]const u16 { const image_path_name = &os.windows.peb().ProcessParameters.ImagePathName; - return mem.toSliceConst(u16, image_path_name.Buffer); + return mem.toSliceConst(u16, @ptrCast([*:0]const u16, image_path_name.Buffer)); } /// `selfExeDirPath` except allocates the result on the heap. @@ -1326,7 +1328,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const // the file path looks something like `/a/b/c/exe (deleted)` // This path cannot be opened, but it's valid for determining the directory // the executable was in when it was run. - const full_exe_path = try os.readlinkC(c"/proc/self/exe", out_buffer); + const full_exe_path = try os.readlinkC("/proc/self/exe", out_buffer); // Assume that /proc/self/exe has an absolute path, and therefore dirname // will not return null. return path.dirname(full_exe_path).?; diff --git a/lib/std/fs/file.zig b/lib/std/fs/file.zig index b25403fa0272bcf57c6a24cb9af9350966af9bc7..9cfdad3885ded3aafee4115dcf7481b0fdd7ed4e 100644 --- a/lib/std/fs/file.zig +++ b/lib/std/fs/file.zig @@ -31,7 +31,7 @@ pub const File = struct { } /// Deprecated; call `std.fs.Dir.openReadC` directly. - pub fn openReadC(path_c: [*]const u8) OpenError!File { + pub fn openReadC(path_c: [*:0]const u8) OpenError!File { return std.fs.Dir.cwd().openReadC(path_c); } @@ -61,7 +61,7 @@ pub const File = struct { /// Same as `openWriteMode` except `path` is null-terminated. /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteModeC(path: [*]const u8, file_mode: Mode) OpenError!File { + pub fn openWriteModeC(path: [*:0]const u8, file_mode: Mode) OpenError!File { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteModeW(&path_w, file_mode); @@ -74,7 +74,7 @@ pub const File = struct { /// Same as `openWriteMode` except `path` is null-terminated and UTF16LE encoded /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteModeW(path_w: [*]const u16, file_mode: Mode) OpenError!File { + pub fn openWriteModeW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { const handle = try windows.CreateFileW( path_w, windows.GENERIC_WRITE, @@ -101,7 +101,7 @@ pub const File = struct { } /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteNoClobberC(path: [*]const u8, file_mode: Mode) OpenError!File { + pub fn openWriteNoClobberC(path: [*:0]const u8, file_mode: Mode) OpenError!File { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); return openWriteNoClobberW(&path_w, file_mode); @@ -113,7 +113,7 @@ pub const File = struct { } /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn openWriteNoClobberW(path_w: [*]const u16, file_mode: Mode) OpenError!File { + pub fn openWriteNoClobberW(path_w: [*:0]const u16, file_mode: Mode) OpenError!File { const handle = try windows.CreateFileW( path_w, windows.GENERIC_WRITE, @@ -142,13 +142,13 @@ pub const File = struct { /// Same as `access` except the parameter is null-terminated. /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn accessC(path: [*]const u8) !void { + pub fn accessC(path: [*:0]const u8) !void { return os.accessC(path, os.F_OK); } /// Same as `access` except the parameter is null-terminated UTF16LE-encoded. /// TODO: deprecate this and move it to `std.fs.Dir`. - pub fn accessW(path: [*]const u16) !void { + pub fn accessW(path: [*:0]const u16) !void { return os.accessW(path, os.F_OK); } @@ -172,7 +172,7 @@ pub const File = struct { if (self.isTty()) { if (self.handle == os.STDOUT_FILENO or self.handle == os.STDERR_FILENO) { // Use getenvC to workaround https://github.com/ziglang/zig/issues/3511 - if (os.getenvC(c"TERM")) |term| { + if (os.getenvC("TERM")) |term| { if (std.mem.eql(u8, term, "dumb")) return false; } diff --git a/lib/std/fs/path.zig b/lib/std/fs/path.zig index 6a2405566707c743efc0718e435fdd9f023ecb17..e2f1b5ac6531e3b8bee01c20b9817514c24aec31 100644 --- a/lib/std/fs/path.zig +++ b/lib/std/fs/path.zig @@ -394,7 +394,7 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { } // determine which disk designator we will result with, if any - var result_drive_buf = "_:"; + var result_drive_buf = "_:".*; var result_disk_designator: []const u8 = ""; var have_drive_kind = WindowsPath.Kind.None; var have_abs_path = false; diff --git a/lib/std/hash/siphash.zig b/lib/std/hash/siphash.zig index c3a9184fa42966dfc021722615b98edf6a9c2b7f..6b4cc2b16b528215964ddbb7ca8762cbd6324fe8 100644 --- a/lib/std/hash/siphash.zig +++ b/lib/std/hash/siphash.zig @@ -202,70 +202,70 @@ const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x test "siphash64-2-4 sanity" { const vectors = [_][8]u8{ - "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // "" - "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00" - "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc - "\x2d\x7e\xfb\xd7\x96\x66\x67\x85", - "\xb7\x87\x71\x27\xe0\x94\x27\xcf", - "\x8d\xa6\x99\xcd\x64\x55\x76\x18", - "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb", - "\x37\xd1\x01\x8b\xf5\x00\x02\xab", - "\x62\x24\x93\x9a\x79\xf5\xf5\x93", - "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e", - "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a", - "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4", - "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75", - "\x90\x3d\x84\xc0\x27\x56\xea\x14", - "\xee\xf2\x7a\x8e\x90\xca\x23\xf7", - "\xe5\x45\xbe\x49\x61\xca\x29\xa1", - "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f", - "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69", - "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b", - "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb", - "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe", - "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0", - "\x88\x3e\xa3\xe3\x95\x67\x53\x93", - "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8", - "\x94\xaf\x49\xf6\xc6\x50\xad\xb8", - "\xea\xb8\x85\x8a\xde\x92\xe1\xbc", - "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17", - "\xad\xcf\x6b\x07\x63\x61\x2e\x2f", - "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde", - "\x71\x65\x95\x87\x66\x50\xa2\xa6", - "\x28\xef\x49\x5c\x53\xa3\x87\xad", - "\x42\xc3\x41\xd8\xfa\x92\xd8\x32", - "\xce\x7c\xf2\x72\x2f\x51\x27\x71", - "\xe3\x78\x59\xf9\x46\x23\xf3\xa7", - "\x38\x12\x05\xbb\x1a\xb0\xe0\x12", - "\xae\x97\xa1\x0f\xd4\x34\xe0\x15", - "\xb4\xa3\x15\x08\xbe\xff\x4d\x31", - "\x81\x39\x62\x29\xf0\x90\x79\x02", - "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca", - "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a", - "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e", - "\x92\x59\x58\xfc\xd6\x42\x0c\xad", - "\xa9\x15\xc2\x9b\xc8\x06\x73\x18", - "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4", - "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9", - "\x87\x57\x75\x19\x04\x8f\x53\xa9", - "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb", - "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0", - "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6", - "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7", - "\x72\xfe\x52\x97\x5a\x43\x64\xee", - "\x5a\x16\x45\xb2\x76\xd5\x92\xa1", - "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a", - "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81", - "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f", - "\x99\x24\xa4\x3c\xc1\x31\x57\x24", - "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7", - "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea", - "\x13\x50\x79\xa3\x23\x1c\xe6\x60", - "\x93\x2b\x28\x46\xe4\xd7\x06\x66", - "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c", - "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f", - "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5", - "\x72\x45\x06\xeb\x4c\x32\x8a\x95", + "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72".*, // "" + "\xfd\x67\xdc\x93\xc5\x39\xf8\x74".*, // "\x00" + "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d".*, // "\x00\x01" ... etc + "\x2d\x7e\xfb\xd7\x96\x66\x67\x85".*, + "\xb7\x87\x71\x27\xe0\x94\x27\xcf".*, + "\x8d\xa6\x99\xcd\x64\x55\x76\x18".*, + "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb".*, + "\x37\xd1\x01\x8b\xf5\x00\x02\xab".*, + "\x62\x24\x93\x9a\x79\xf5\xf5\x93".*, + "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e".*, + "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a".*, + "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4".*, + "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75".*, + "\x90\x3d\x84\xc0\x27\x56\xea\x14".*, + "\xee\xf2\x7a\x8e\x90\xca\x23\xf7".*, + "\xe5\x45\xbe\x49\x61\xca\x29\xa1".*, + "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f".*, + "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69".*, + "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b".*, + "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb".*, + "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe".*, + "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0".*, + "\x88\x3e\xa3\xe3\x95\x67\x53\x93".*, + "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8".*, + "\x94\xaf\x49\xf6\xc6\x50\xad\xb8".*, + "\xea\xb8\x85\x8a\xde\x92\xe1\xbc".*, + "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17".*, + "\xad\xcf\x6b\x07\x63\x61\x2e\x2f".*, + "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde".*, + "\x71\x65\x95\x87\x66\x50\xa2\xa6".*, + "\x28\xef\x49\x5c\x53\xa3\x87\xad".*, + "\x42\xc3\x41\xd8\xfa\x92\xd8\x32".*, + "\xce\x7c\xf2\x72\x2f\x51\x27\x71".*, + "\xe3\x78\x59\xf9\x46\x23\xf3\xa7".*, + "\x38\x12\x05\xbb\x1a\xb0\xe0\x12".*, + "\xae\x97\xa1\x0f\xd4\x34\xe0\x15".*, + "\xb4\xa3\x15\x08\xbe\xff\x4d\x31".*, + "\x81\x39\x62\x29\xf0\x90\x79\x02".*, + "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca".*, + "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a".*, + "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e".*, + "\x92\x59\x58\xfc\xd6\x42\x0c\xad".*, + "\xa9\x15\xc2\x9b\xc8\x06\x73\x18".*, + "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4".*, + "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9".*, + "\x87\x57\x75\x19\x04\x8f\x53\xa9".*, + "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb".*, + "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0".*, + "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6".*, + "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7".*, + "\x72\xfe\x52\x97\x5a\x43\x64\xee".*, + "\x5a\x16\x45\xb2\x76\xd5\x92\xa1".*, + "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a".*, + "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81".*, + "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f".*, + "\x99\x24\xa4\x3c\xc1\x31\x57\x24".*, + "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7".*, + "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea".*, + "\x13\x50\x79\xa3\x23\x1c\xe6\x60".*, + "\x93\x2b\x28\x46\xe4\xd7\x06\x66".*, + "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c".*, + "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f".*, + "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5".*, + "\x72\x45\x06\xeb\x4c\x32\x8a\x95".*, }; const siphash = SipHash64(2, 4); @@ -281,70 +281,70 @@ test "siphash64-2-4 sanity" { test "siphash128-2-4 sanity" { const vectors = [_][16]u8{ - "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93", - "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45", - "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4", - "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51", - "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79", - "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27", - "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e", - "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39", - "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4", - "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed", - "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba", - "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18", - "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25", - "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7", - "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02", - "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9", - "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77", - "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40", - "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23", - "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1", - "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb", - "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12", - "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae", - "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c", - "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad", - "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f", - "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66", - "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94", - "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4", - "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7", - "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87", - "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35", - "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68", - "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf", - "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde", - "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8", - "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11", - "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b", - "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5", - "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9", - "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8", - "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb", - "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b", - "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89", - "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42", - "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c", - "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02", - "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b", - "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16", - "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03", - "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f", - "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38", - "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c", - "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e", - "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87", - "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda", - "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36", - "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e", - "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d", - "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59", - "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40", - "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a", - "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd", - "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c", + "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93".*, + "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45".*, + "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4".*, + "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51".*, + "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79".*, + "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27".*, + "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e".*, + "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39".*, + "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4".*, + "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed".*, + "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba".*, + "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18".*, + "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25".*, + "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7".*, + "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02".*, + "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9".*, + "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77".*, + "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40".*, + "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23".*, + "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1".*, + "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb".*, + "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12".*, + "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae".*, + "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c".*, + "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad".*, + "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f".*, + "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66".*, + "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94".*, + "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4".*, + "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7".*, + "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87".*, + "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35".*, + "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68".*, + "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf".*, + "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde".*, + "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8".*, + "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11".*, + "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b".*, + "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5".*, + "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9".*, + "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8".*, + "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb".*, + "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b".*, + "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89".*, + "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42".*, + "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c".*, + "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02".*, + "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b".*, + "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16".*, + "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03".*, + "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f".*, + "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38".*, + "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c".*, + "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e".*, + "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87".*, + "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda".*, + "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36".*, + "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e".*, + "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d".*, + "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59".*, + "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40".*, + "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a".*, + "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd".*, + "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c".*, }; const siphash = SipHash128(2, 4); diff --git a/lib/std/io/test.zig b/lib/std/io/test.zig index 28b8371d9d490616e05547d8c281558fcbeae8e6..d2374f0a3fa00264ddf2cb7f8acd7e7a606810ca 100644 --- a/lib/std/io/test.zig +++ b/lib/std/io/test.zig @@ -595,8 +595,8 @@ test "Deserializer bad data" { test "c out stream" { if (!builtin.link_libc) return error.SkipZigTest; - const filename = c"tmp_io_test_file.txt"; - const out_file = std.c.fopen(filename, c"w") orelse return error.UnableToOpenTestFile; + const filename = "tmp_io_test_file.txt"; + const out_file = std.c.fopen(filename, "w") orelse return error.UnableToOpenTestFile; defer { _ = std.c.fclose(out_file); fs.deleteFileC(filename) catch {}; diff --git a/lib/std/mem.zig b/lib/std/mem.zig index 19e9634d5a6165d714b507cb04ab276486c3d7a6..412bf9b649f479198e14258982b9e557d378836c 100644 --- a/lib/std/mem.zig +++ b/lib/std/mem.zig @@ -356,17 +356,17 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool { return true; } -pub fn len(comptime T: type, ptr: [*]const T) usize { +pub fn len(comptime T: type, ptr: [*:0]const T) usize { var count: usize = 0; while (ptr[count] != 0) : (count += 1) {} return count; } -pub fn toSliceConst(comptime T: type, ptr: [*]const T) []const T { +pub fn toSliceConst(comptime T: type, ptr: [*:0]const T) [:0]const T { return ptr[0..len(T, ptr)]; } -pub fn toSlice(comptime T: type, ptr: [*]T) []T { +pub fn toSlice(comptime T: type, ptr: [*:0]T) [:0]T { return ptr[0..len(T, ptr)]; } @@ -1408,7 +1408,9 @@ test "toBytes" { fn BytesAsValueReturnType(comptime T: type, comptime B: type) type { const size = @as(usize, @sizeOf(T)); - if (comptime !trait.is(builtin.TypeId.Pointer)(B) or meta.Child(B) != [size]u8) { + if (comptime !trait.is(builtin.TypeId.Pointer)(B) or + (meta.Child(B) != [size]u8 and meta.Child(B) != [size:0]u8)) + { @compileError("expected *[N]u8 " ++ ", passed " ++ @typeName(B)); } @@ -1430,12 +1432,12 @@ test "bytesAsValue" { builtin.Endian.Little => "\xEF\xBE\xAD\xDE", }; - testing.expect(deadbeef == bytesAsValue(u32, &deadbeef_bytes).*); + testing.expect(deadbeef == bytesAsValue(u32, deadbeef_bytes).*); - var codeface_bytes = switch (builtin.endian) { + var codeface_bytes: [4]u8 = switch (builtin.endian) { builtin.Endian.Big => "\xC0\xDE\xFA\xCE", builtin.Endian.Little => "\xCE\xFA\xDE\xC0", - }; + }.*; var codeface = bytesAsValue(u32, &codeface_bytes); testing.expect(codeface.* == 0xC0DEFACE); codeface.* = 0; @@ -1456,14 +1458,14 @@ test "bytesAsValue" { .d = 0xA1, }; const inst_bytes = "\xBE\xEF\xDE\xA1"; - const inst2 = bytesAsValue(S, &inst_bytes); + const inst2 = bytesAsValue(S, inst_bytes); testing.expect(meta.eql(inst, inst2.*)); } ///Given a pointer to an array of bytes, returns a value of the specified type backed by a /// copy of those bytes. pub fn bytesToValue(comptime T: type, bytes: var) T { - return bytesAsValue(T, &bytes).*; + return bytesAsValue(T, bytes).*; } test "bytesToValue" { const deadbeef_bytes = switch (builtin.endian) { @@ -1491,11 +1493,11 @@ pub fn subArrayPtr(ptr: var, comptime start: usize, comptime length: usize) SubA } test "subArrayPtr" { - const a1 = "abcdef"; + const a1: [6]u8 = "abcdef".*; const sub1 = subArrayPtr(&a1, 2, 3); testing.expect(eql(u8, sub1.*, "cde")); - var a2 = "abcdef"; + var a2: [6]u8 = "abcdef".*; var sub2 = subArrayPtr(&a2, 2, 3); testing.expect(eql(u8, sub2, "cde")); diff --git a/lib/std/meta.zig b/lib/std/meta.zig index 903c3a12b33627941aa31f3e563d84bdc3d7be40..b770b97a471609e8cdb1bf81f1f385fc75ae49e0 100644 --- a/lib/std/meta.zig +++ b/lib/std/meta.zig @@ -469,19 +469,19 @@ test "std.meta.eql" { const s_1 = S{ .a = 134, .b = 123.3, - .c = "12345", + .c = "12345".*, }; const s_2 = S{ .a = 1, .b = 123.3, - .c = "54321", + .c = "54321".*, }; const s_3 = S{ .a = 134, .b = 123.3, - .c = "12345", + .c = "12345".*, }; const u_1 = U{ .f = 24 }; @@ -494,9 +494,9 @@ test "std.meta.eql" { testing.expect(eql(u_1, u_3)); testing.expect(!eql(u_1, u_2)); - var a1 = "abcdef"; - var a2 = "abcdef"; - var a3 = "ghijkl"; + var a1 = "abcdef".*; + var a2 = "abcdef".*; + var a3 = "ghijkl".*; testing.expect(eql(a1, a2)); testing.expect(!eql(a1, a3)); diff --git a/lib/std/meta/trait.zig b/lib/std/meta/trait.zig index 8857b4aa9e1dff0b3bd597b36644f498d8bdd3e0..2388acbeb62ffd63fa1334d1561eb7517c4f00e6 100644 --- a/lib/std/meta/trait.zig +++ b/lib/std/meta/trait.zig @@ -319,7 +319,6 @@ test "std.meta.trait.isNumber" { testing.expect(!isNumber(NotANumber)); } -/// pub fn isConstPtr(comptime T: type) bool { if (!comptime is(builtin.TypeId.Pointer)(T)) return false; const info = @typeInfo(T); @@ -335,7 +334,6 @@ test "std.meta.trait.isConstPtr" { testing.expect(!isConstPtr(@typeOf(6))); } -/// pub fn isContainer(comptime T: type) bool { const info = @typeInfo(T); return switch (info) { diff --git a/lib/std/net.zig b/lib/std/net.zig index f4cd09482b90fa58e31afa0987d2e63020a61822..9a602c010599c4ac6b15ddb4e7e26d30f3100e6e 100644 --- a/lib/std/net.zig +++ b/lib/std/net.zig @@ -360,7 +360,7 @@ pub const Address = extern union { unreachable; } - const path_len = std.mem.len(u8, &self.un.path); + const path_len = std.mem.len(u8, @ptrCast([*:0]const u8, &self.un.path)); return @intCast(os.socklen_t, @sizeOf(os.sockaddr_un) - self.un.path.len + path_len); }, else => unreachable, @@ -666,35 +666,35 @@ const Policy = struct { const defined_policies = [_]Policy{ Policy{ - .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", + .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01".*, .len = 15, .mask = 0xff, .prec = 50, .label = 0, }, Policy{ - .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00", + .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x00".*, .len = 11, .mask = 0xff, .prec = 35, .label = 4, }, Policy{ - .addr = "\x20\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .addr = "\x20\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*, .len = 1, .mask = 0xff, .prec = 30, .label = 2, }, Policy{ - .addr = "\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .addr = "\x20\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*, .len = 3, .mask = 0xff, .prec = 5, .label = 5, }, Policy{ - .addr = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .addr = "\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*, .len = 0, .mask = 0xfe, .prec = 3, @@ -708,7 +708,7 @@ const defined_policies = [_]Policy{ // { "\x3f\xfe", 1, 0xff, 1, 12 }, // Last rule must match all addresses to stop loop. Policy{ - .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + .addr = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".*, .len = 0, .mask = 0, .prec = 40, @@ -812,7 +812,7 @@ fn linuxLookupNameFromHosts( family: os.sa_family_t, port: u16, ) !void { - const file = fs.File.openReadC(c"/etc/hosts") catch |err| switch (err) { + const file = fs.File.openReadC("/etc/hosts") catch |err| switch (err) { error.FileNotFound, error.NotDir, error.AccessDenied, @@ -1006,7 +1006,7 @@ fn getResolvConf(allocator: *mem.Allocator, rc: *ResolvConf) !void { }; errdefer rc.deinit(); - const file = fs.File.openReadC(c"/etc/resolv.conf") catch |err| switch (err) { + const file = fs.File.openReadC("/etc/resolv.conf") catch |err| switch (err) { error.FileNotFound, error.NotDir, error.AccessDenied, @@ -1271,7 +1271,7 @@ fn dnsParseCallback(ctx: dpc_ctx, rr: u8, data: []const u8, packet: []const u8) var tmp: [256]u8 = undefined; // Returns len of compressed name. strlen to get canon name. _ = try os.dn_expand(packet, data, &tmp); - const canon_name = mem.toSliceConst(u8, &tmp); + const canon_name = mem.toSliceConst(u8, @ptrCast([*:0]const u8, &tmp)); if (isValidHostName(canon_name)) { try ctx.canon.replaceContents(canon_name); } diff --git a/lib/std/os.zig b/lib/std/os.zig index 68a3a6e9f65f416a3d6c9d99a8cfad22f3a0b8f6..cda65b7ea7929e48b723f23f5c513974c24b9cb5 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -66,12 +66,12 @@ pub const system = if (builtin.link_libc) std.c else switch (builtin.os) { pub usingnamespace @import("os/bits.zig"); /// See also `getenv`. Populated by startup code before main(). -pub var environ: [][*]u8 = undefined; +pub var environ: [][*:0]u8 = undefined; /// Populated by startup code before main(). /// Not available on Windows. See `std.process.args` /// for obtaining the process arguments. -pub var argv: [][*]u8 = undefined; +pub var argv: [][*:0]u8 = undefined; /// To obtain errno, call this function with the return value of the /// system function call. For some systems this will obtain the value directly @@ -157,7 +157,7 @@ pub fn getrandom(buffer: []u8) GetRandomError!void { } fn getRandomBytesDevURandom(buf: []u8) !void { - const fd = try openC(c"/dev/urandom", O_RDONLY | O_CLOEXEC, 0); + const fd = try openC("/dev/urandom", O_RDONLY | O_CLOEXEC, 0); defer close(fd); const st = try fstat(fd); @@ -655,8 +655,7 @@ pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t { /// Open and possibly create a file. Keeps trying if it gets interrupted. /// See also `open`. -/// TODO https://github.com/ziglang/zig/issues/265 -pub fn openC(file_path: [*]const u8, flags: u32, perm: usize) OpenError!fd_t { +pub fn openC(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t { while (true) { const rc = system.open(file_path, flags, perm); switch (errno(rc)) { @@ -697,7 +696,7 @@ pub fn openat(dir_fd: fd_t, file_path: []const u8, flags: u32, mode: usize) Open /// Open and possibly create a file. Keeps trying if it gets interrupted. /// `file_path` is relative to the open directory handle `dir_fd`. /// See also `openat`. -pub fn openatC(dir_fd: fd_t, file_path: [*]const u8, flags: u32, mode: usize) OpenError!fd_t { +pub fn openatC(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: usize) OpenError!fd_t { while (true) { const rc = system.openat(dir_fd, file_path, flags, mode); switch (errno(rc)) { @@ -757,7 +756,7 @@ pub const ExecveError = error{ /// Like `execve` except the parameters are null-terminated, /// matching the syscall API on all targets. This removes the need for an allocator. /// This function ignores PATH environment variable. See `execvpeC` for that. -pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) ExecveError { +pub fn execveC(path: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { switch (errno(system.execve(path, child_argv, envp))) { 0 => unreachable, EFAULT => unreachable, @@ -784,7 +783,7 @@ pub fn execveC(path: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]co /// matching the syscall API on all targets. This removes the need for an allocator. /// This function also uses the PATH environment variable to get the full path to the executable. /// If `file` is an absolute path, this is the same as `execveC`. -pub fn execvpeC(file: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) ExecveError { +pub fn execvpeC(file: [*:0]const u8, child_argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) ExecveError { const file_slice = mem.toSliceConst(u8, file); if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveC(file, child_argv, envp); @@ -799,7 +798,8 @@ pub fn execvpeC(file: [*]const u8, child_argv: [*]const ?[*]const u8, envp: [*]c path_buf[search_path.len] = '/'; mem.copy(u8, path_buf[search_path.len + 1 ..], file_slice); path_buf[search_path.len + file_slice.len + 1] = 0; - err = execveC(&path_buf, child_argv, envp); + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + err = execveC(@ptrCast([*:0]u8, &path_buf), child_argv, envp); switch (err) { error.AccessDenied => seen_eacces = true, error.FileNotFound, error.NotDir => {}, @@ -820,8 +820,8 @@ pub fn execvpe( argv_slice: []const []const u8, env_map: *const std.BufMap, ) (ExecveError || error{OutOfMemory}) { - const argv_buf = try allocator.alloc(?[*]u8, argv_slice.len + 1); - mem.set(?[*]u8, argv_buf, null); + const argv_buf = try allocator.alloc(?[*:0]u8, argv_slice.len + 1); + mem.set(?[*:0]u8, argv_buf, null); defer { for (argv_buf) |arg| { const arg_buf = if (arg) |ptr| mem.toSlice(u8, ptr) else break; @@ -834,20 +834,24 @@ pub fn execvpe( @memcpy(arg_buf.ptr, arg.ptr, arg.len); arg_buf[arg.len] = 0; - argv_buf[i] = arg_buf.ptr; + // TODO avoid @ptrCast using slice syntax with https://github.com/ziglang/zig/issues/3731 + argv_buf[i] = @ptrCast([*:0]u8, arg_buf.ptr); } argv_buf[argv_slice.len] = null; const envp_buf = try createNullDelimitedEnvMap(allocator, env_map); defer freeNullDelimitedEnvMap(allocator, envp_buf); - return execvpeC(argv_buf.ptr[0].?, argv_buf.ptr, envp_buf.ptr); + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + const argv_ptr = @ptrCast([*:null]?[*:0]u8, argv_buf.ptr); + + return execvpeC(argv_buf.ptr[0].?, argv_ptr, envp_buf.ptr); } -pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![]?[*]u8 { +pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std.BufMap) ![:null]?[*:0]u8 { const envp_count = env_map.count(); - const envp_buf = try allocator.alloc(?[*]u8, envp_count + 1); - mem.set(?[*]u8, envp_buf, null); + const envp_buf = try allocator.alloc(?[*:0]u8, envp_count + 1); + mem.set(?[*:0]u8, envp_buf, null); errdefer freeNullDelimitedEnvMap(allocator, envp_buf); { var it = env_map.iterator(); @@ -859,15 +863,17 @@ pub fn createNullDelimitedEnvMap(allocator: *mem.Allocator, env_map: *const std. @memcpy(env_buf.ptr + pair.key.len + 1, pair.value.ptr, pair.value.len); env_buf[env_buf.len - 1] = 0; - envp_buf[i] = env_buf.ptr; + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 + envp_buf[i] = @ptrCast([*:0]u8, env_buf.ptr); } assert(i == envp_count); } + // TODO avoid @ptrCast here using slice syntax with https://github.com/ziglang/zig/issues/3731 assert(envp_buf[envp_count] == null); - return envp_buf; + return @ptrCast([*:null]?[*:0]u8, envp_buf.ptr)[0..envp_count]; } -pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*]u8) void { +pub fn freeNullDelimitedEnvMap(allocator: *mem.Allocator, envp_buf: []?[*:0]u8) void { for (envp_buf) |env| { const env_buf = if (env) |ptr| ptr[0 .. mem.len(u8, ptr) + 1] else break; allocator.free(env_buf); @@ -896,8 +902,7 @@ pub fn getenv(key: []const u8) ?[]const u8 { /// Get an environment variable with a null-terminated name. /// See also `getenv`. -/// TODO https://github.com/ziglang/zig/issues/265 -pub fn getenvC(key: [*]const u8) ?[]const u8 { +pub fn getenvC(key: [*:0]const u8) ?[]const u8 { if (builtin.link_libc) { const value = system.getenv(key) orelse return null; return mem.toSliceConst(u8, value); @@ -922,7 +927,7 @@ pub fn getcwd(out_buffer: []u8) GetCwdError![]u8 { break :blk errno(system.getcwd(out_buffer.ptr, out_buffer.len)); }; switch (err) { - 0 => return mem.toSlice(u8, out_buffer.ptr), + 0 => return mem.toSlice(u8, @ptrCast([*:0]u8, out_buffer.ptr)), EFAULT => unreachable, EINVAL => unreachable, ENOENT => return error.CurrentWorkingDirectoryUnlinked, @@ -966,7 +971,7 @@ pub fn symlink(target_path: []const u8, sym_link_path: []const u8) SymLinkError! /// This is the same as `symlink` except the parameters are null-terminated pointers. /// See also `symlink`. -pub fn symlinkC(target_path: [*]const u8, sym_link_path: [*]const u8) SymLinkError!void { +pub fn symlinkC(target_path: [*:0]const u8, sym_link_path: [*:0]const u8) SymLinkError!void { if (builtin.os == .windows) { const target_path_w = try windows.cStrToPrefixedFileW(target_path); const sym_link_path_w = try windows.cStrToPrefixedFileW(sym_link_path); @@ -998,7 +1003,7 @@ pub fn symlinkat(target_path: []const u8, newdirfd: fd_t, sym_link_path: []const return symlinkatC(target_path_c, newdirfd, sym_link_path_c); } -pub fn symlinkatC(target_path: [*]const u8, newdirfd: fd_t, sym_link_path: [*]const u8) SymLinkError!void { +pub fn symlinkatC(target_path: [*:0]const u8, newdirfd: fd_t, sym_link_path: [*:0]const u8) SymLinkError!void { switch (errno(system.symlinkat(target_path, newdirfd, sym_link_path))) { 0 => return, EFAULT => unreachable, @@ -1052,7 +1057,7 @@ pub fn unlink(file_path: []const u8) UnlinkError!void { } /// Same as `unlink` except the parameter is a null terminated UTF8-encoded string. -pub fn unlinkC(file_path: [*]const u8) UnlinkError!void { +pub fn unlinkC(file_path: [*:0]const u8) UnlinkError!void { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); return windows.DeleteFileW(&file_path_w); @@ -1092,7 +1097,7 @@ pub fn unlinkat(dirfd: fd_t, file_path: []const u8, flags: u32) UnlinkatError!vo } /// Same as `unlinkat` but `file_path` is a null-terminated string. -pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatError!void { +pub fn unlinkatC(dirfd: fd_t, file_path_c: [*:0]const u8, flags: u32) UnlinkatError!void { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path_c); return unlinkatW(dirfd, &file_path_w, flags); @@ -1121,7 +1126,7 @@ pub fn unlinkatC(dirfd: fd_t, file_path_c: [*]const u8, flags: u32) UnlinkatErro } /// Same as `unlinkat` but `sub_path_w` is UTF16LE, NT prefixed. Windows only. -pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*]const u16, flags: u32) UnlinkatError!void { +pub fn unlinkatW(dirfd: fd_t, sub_path_w: [*:0]const u16, flags: u32) UnlinkatError!void { const w = windows; const want_rmdir_behavior = (flags & AT_REMOVEDIR) != 0; @@ -1216,7 +1221,7 @@ pub fn rename(old_path: []const u8, new_path: []const u8) RenameError!void { } /// Same as `rename` except the parameters are null-terminated byte arrays. -pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { +pub fn renameC(old_path: [*:0]const u8, new_path: [*:0]const u8) RenameError!void { if (builtin.os == .windows) { const old_path_w = try windows.cStrToPrefixedFileW(old_path); const new_path_w = try windows.cStrToPrefixedFileW(new_path); @@ -1248,7 +1253,7 @@ pub fn renameC(old_path: [*]const u8, new_path: [*]const u8) RenameError!void { /// Same as `rename` except the parameters are null-terminated UTF16LE encoded byte arrays. /// Assumes target is Windows. -pub fn renameW(old_path: [*]const u16, new_path: [*]const u16) RenameError!void { +pub fn renameW(old_path: [*:0]const u16, new_path: [*:0]const u16) RenameError!void { const flags = windows.MOVEFILE_REPLACE_EXISTING | windows.MOVEFILE_WRITE_THROUGH; return windows.MoveFileExW(old_path, new_path, flags); } @@ -1282,7 +1287,7 @@ pub fn mkdir(dir_path: []const u8, mode: u32) MakeDirError!void { } /// Same as `mkdir` but the parameter is a null-terminated UTF8-encoded string. -pub fn mkdirC(dir_path: [*]const u8, mode: u32) MakeDirError!void { +pub fn mkdirC(dir_path: [*:0]const u8, mode: u32) MakeDirError!void { if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.CreateDirectoryW(&dir_path_w, null); @@ -1332,7 +1337,7 @@ pub fn rmdir(dir_path: []const u8) DeleteDirError!void { } /// Same as `rmdir` except the parameter is null-terminated. -pub fn rmdirC(dir_path: [*]const u8) DeleteDirError!void { +pub fn rmdirC(dir_path: [*:0]const u8) DeleteDirError!void { if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); return windows.RemoveDirectoryW(&dir_path_w); @@ -1379,7 +1384,7 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void { } /// Same as `chdir` except the parameter is null-terminated. -pub fn chdirC(dir_path: [*]const u8) ChangeCurDirError!void { +pub fn chdirC(dir_path: [*:0]const u8) ChangeCurDirError!void { if (builtin.os == .windows) { const dir_path_w = try windows.cStrToPrefixedFileW(dir_path); @compileError("TODO implement chdir for Windows"); @@ -1421,7 +1426,7 @@ pub fn readlink(file_path: []const u8, out_buffer: []u8) ReadLinkError![]u8 { } /// Same as `readlink` except `file_path` is null-terminated. -pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { +pub fn readlinkC(file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); @@ -1442,7 +1447,7 @@ pub fn readlinkC(file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { } } -pub fn readlinkatC(dirfd: fd_t, file_path: [*]const u8, out_buffer: []u8) ReadLinkError![]u8 { +pub fn readlinkatC(dirfd: fd_t, file_path: [*:0]const u8, out_buffer: []u8) ReadLinkError![]u8 { if (builtin.os == .windows) { const file_path_w = try windows.cStrToPrefixedFileW(file_path); @compileError("TODO implement readlink for Windows"); @@ -2129,7 +2134,7 @@ pub fn inotify_add_watch(inotify_fd: i32, pathname: []const u8, mask: u32) INoti } /// Same as `inotify_add_watch` except pathname is null-terminated. -pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*]const u8, mask: u32) INotifyAddWatchError!i32 { +pub fn inotify_add_watchC(inotify_fd: i32, pathname: [*:0]const u8, mask: u32) INotifyAddWatchError!i32 { const rc = system.inotify_add_watch(inotify_fd, pathname, mask); switch (errno(rc)) { 0 => return @intCast(i32, rc), @@ -2286,7 +2291,7 @@ pub fn access(path: []const u8, mode: u32) AccessError!void { } /// Same as `access` except `path` is null-terminated. -pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { +pub fn accessC(path: [*:0]const u8, mode: u32) AccessError!void { if (builtin.os == .windows) { const path_w = try windows.cStrToPrefixedFileW(path); _ = try windows.GetFileAttributesW(&path_w); @@ -2313,7 +2318,7 @@ pub fn accessC(path: [*]const u8, mode: u32) AccessError!void { /// Call from Windows-specific code if you already have a UTF-16LE encoded, null terminated string. /// Otherwise use `access` or `accessC`. /// TODO currently this ignores `mode`. -pub fn accessW(path: [*]const u16, mode: u32) windows.GetFileAttributesError!void { +pub fn accessW(path: [*:0]const u16, mode: u32) windows.GetFileAttributesError!void { const ret = try windows.GetFileAttributesW(path); if (ret != windows.INVALID_FILE_ATTRIBUTES) { return; @@ -2380,7 +2385,7 @@ pub fn sysctl( } pub fn sysctlbynameC( - name: [*]const u8, + name: [*:0]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, @@ -2562,7 +2567,7 @@ pub fn realpath(pathname: []const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathE } /// Same as `realpath` except `pathname` is null-terminated. -pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { +pub fn realpathC(pathname: [*:0]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { if (builtin.os == .windows) { const pathname_w = try windows.cStrToPrefixedFileW(pathname); return realpathW(&pathname_w, out_buffer); @@ -2571,10 +2576,10 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat const fd = try openC(pathname, linux.O_PATH | linux.O_NONBLOCK | linux.O_CLOEXEC, 0); defer close(fd); - var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; + var procfs_buf: ["/proc/self/fd/-2147483648".len:0]u8 = undefined; const proc_path = std.fmt.bufPrint(procfs_buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable; - return readlinkC(proc_path.ptr, out_buffer); + return readlinkC(@ptrCast([*:0]const u8, proc_path.ptr), out_buffer); } const result_path = std.c.realpath(pathname, out_buffer) orelse switch (std.c._errno().*) { EINVAL => unreachable, @@ -2593,7 +2598,7 @@ pub fn realpathC(pathname: [*]const u8, out_buffer: *[MAX_PATH_BYTES]u8) RealPat } /// Same as `realpath` except `pathname` is null-terminated and UTF16LE-encoded. -pub fn realpathW(pathname: [*]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { +pub fn realpathW(pathname: [*:0]const u16, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 { const h_file = try windows.CreateFileW( pathname, windows.GENERIC_READ, @@ -2674,7 +2679,7 @@ pub fn dl_iterate_phdr( if (it.end()) { var info = dl_phdr_info{ .dlpi_addr = elf_base, - .dlpi_name = c"/proc/self/exe", + .dlpi_name = "/proc/self/exe", .dlpi_phdr = phdrs.ptr, .dlpi_phnum = ehdr.e_phnum, }; @@ -2748,8 +2753,8 @@ pub fn sched_getaffinity(pid: pid_t) SchedGetAffinityError!cpu_set_t { /// Used to convert a slice to a null terminated slice on the stack. /// TODO https://github.com/ziglang/zig/issues/287 -pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { - var path_with_null: [PATH_MAX]u8 = undefined; +pub fn toPosixPath(file_path: []const u8) ![PATH_MAX-1:0]u8 { + var path_with_null: [PATH_MAX-1:0]u8 = undefined; // >= rather than > to make room for the null byte if (file_path.len >= PATH_MAX) return error.NameTooLong; mem.copy(u8, &path_with_null, file_path); @@ -2854,7 +2859,7 @@ pub const GetHostNameError = error{PermissionDenied} || UnexpectedError; pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { if (builtin.link_libc) { switch (errno(system.gethostname(name_buffer, name_buffer.len))) { - 0 => return mem.toSlice(u8, name_buffer), + 0 => return mem.toSlice(u8, @ptrCast([*:0]u8, name_buffer)), EFAULT => unreachable, ENAMETOOLONG => unreachable, // HOST_NAME_MAX prevents this EPERM => return error.PermissionDenied, @@ -2865,7 +2870,7 @@ pub fn gethostname(name_buffer: *[HOST_NAME_MAX]u8) GetHostNameError![]u8 { var uts: utsname = undefined; switch (errno(system.uname(&uts))) { 0 => { - const hostname = mem.toSlice(u8, &uts.nodename); + const hostname = mem.toSlice(u8, @ptrCast([*:0]u8, &uts.nodename)); mem.copy(u8, name_buffer, hostname); return name_buffer[0..hostname.len]; }, diff --git a/lib/std/os/bits/darwin.zig b/lib/std/os/bits/darwin.zig index 9451df6e199224b69775392f9f11f0ee46e2c4b9..26c9e7ec9b0961201ab9647b96b6179f89867263 100644 --- a/lib/std/os/bits/darwin.zig +++ b/lib/std/os/bits/darwin.zig @@ -1205,7 +1205,7 @@ pub const addrinfo = extern struct { socktype: i32, protocol: i32, addrlen: socklen_t, - canonname: ?[*]u8, + canonname: ?[*:0]u8, addr: ?*sockaddr, next: ?*addrinfo, }; diff --git a/lib/std/os/bits/linux.zig b/lib/std/os/bits/linux.zig index bf58d4944b9253d3c835e3950bec835082650883..3cafb8ba0b80c0b86cdec8e262aebad6c7723a03 100644 --- a/lib/std/os/bits/linux.zig +++ b/lib/std/os/bits/linux.zig @@ -1363,7 +1363,7 @@ pub const addrinfo = extern struct { protocol: i32, addrlen: socklen_t, addr: ?*sockaddr, - canonname: ?[*]u8, + canonname: ?[*:0]u8, next: ?*addrinfo, }; diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig index 7e2f14021fd1b6dd7b13aea543175e2bd70cfcc3..1de66b8d2e8f3f5b7f319321ba72aaca829060f5 100644 --- a/lib/std/os/linux.zig +++ b/lib/std/os/linux.zig @@ -1053,7 +1053,7 @@ pub fn dl_iterate_phdr(comptime T: type, callback: extern fn (info: *dl_phdr_inf if (it.end()) { var info = dl_phdr_info{ .dlpi_addr = elf_base, - .dlpi_name = c"/proc/self/exe", + .dlpi_name = "/proc/self/exe", .dlpi_phdr = @intToPtr([*]elf.Phdr, elf_base + __ehdr_start.e_phoff), .dlpi_phnum = __ehdr_start.e_phnum, }; diff --git a/lib/std/os/linux/test.zig b/lib/std/os/linux/test.zig index bccb7beb1e3ac072e16b1215992c93b1c5d8c699..8281851d6b47dbcde6885847b638074a02fe911b 100644 --- a/lib/std/os/linux/test.zig +++ b/lib/std/os/linux/test.zig @@ -56,7 +56,7 @@ test "statx" { } var statx_buf: linux.Statx = undefined; - switch (linux.getErrno(linux.statx(file.handle, c"", linux.AT_EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) { + switch (linux.getErrno(linux.statx(file.handle, "", linux.AT_EMPTY_PATH, linux.STATX_BASIC_STATS, &statx_buf))) { 0 => {}, // The statx syscall was only introduced in linux 4.11 linux.ENOSYS => return error.SkipZigTest, @@ -64,7 +64,7 @@ test "statx" { } var stat_buf: linux.Stat = undefined; - switch (linux.getErrno(linux.fstatat(file.handle, c"", &stat_buf, linux.AT_EMPTY_PATH))) { + switch (linux.getErrno(linux.fstatat(file.handle, "", &stat_buf, linux.AT_EMPTY_PATH))) { 0 => {}, else => unreachable, } diff --git a/lib/std/os/linux/vdso.zig b/lib/std/os/linux/vdso.zig index d3e00b8673954094b849c2046a4e40c3c58ea734..868eb26c69862dbec6e8cf607e8ce4b17e8cb868 100644 --- a/lib/std/os/linux/vdso.zig +++ b/lib/std/os/linux/vdso.zig @@ -65,7 +65,8 @@ pub fn lookup(vername: []const u8, name: []const u8) usize { if (0 == (@as(u32, 1) << @intCast(u5, syms[i].st_info & 0xf) & OK_TYPES)) continue; if (0 == (@as(u32, 1) << @intCast(u5, syms[i].st_info >> 4) & OK_BINDS)) continue; if (0 == syms[i].st_shndx) continue; - if (!mem.eql(u8, name, mem.toSliceConst(u8, strings + syms[i].st_name))) continue; + const sym_name = @ptrCast([*:0]const u8, strings + syms[i].st_name); + if (!mem.eql(u8, name, mem.toSliceConst(u8, sym_name))) continue; if (maybe_versym) |versym| { if (!checkver(maybe_verdef.?, versym[i], vername, strings)) continue; @@ -87,5 +88,6 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: i32, vername: []const u8, strings: [ def = @intToPtr(*elf.Verdef, @ptrToInt(def) + def.vd_next); } const aux = @intToPtr(*elf.Verdaux, @ptrToInt(def) + def.vd_aux); - return mem.eql(u8, vername, mem.toSliceConst(u8, strings + aux.vda_name)); + const vda_name = @ptrCast([*:0]const u8, strings + aux.vda_name); + return mem.eql(u8, vername, mem.toSliceConst(u8, vda_name)); } diff --git a/lib/std/os/wasi.zig b/lib/std/os/wasi.zig index fce29ef0b30cb8d19ec2a2ef30d31210b6c39722..7661be1f856de0d92327e1a951141e6f9d5ac26e 100644 --- a/lib/std/os/wasi.zig +++ b/lib/std/os/wasi.zig @@ -19,13 +19,13 @@ comptime { pub const iovec_t = iovec; pub const ciovec_t = iovec_const; -pub extern "wasi_unstable" fn args_get(argv: [*][*]u8, argv_buf: [*]u8) errno_t; +pub extern "wasi_unstable" fn args_get(argv: [*][*:0]u8, argv_buf: [*]u8) errno_t; pub extern "wasi_unstable" fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; pub extern "wasi_unstable" fn clock_res_get(clock_id: clockid_t, resolution: *timestamp_t) errno_t; pub extern "wasi_unstable" fn clock_time_get(clock_id: clockid_t, precision: timestamp_t, timestamp: *timestamp_t) errno_t; -pub extern "wasi_unstable" fn environ_get(environ: [*]?[*]u8, environ_buf: [*]u8) errno_t; +pub extern "wasi_unstable" fn environ_get(environ: [*]?[*:0]u8, environ_buf: [*]u8) errno_t; pub extern "wasi_unstable" fn environ_sizes_get(environ_count: *usize, environ_buf_size: *usize) errno_t; pub extern "wasi_unstable" fn fd_advise(fd: fd_t, offset: filesize_t, len: filesize_t, advice: advice_t) errno_t; diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index a04e351799e9de520820ddcf571023edeb20c5c7..4bf86bc4fd7188dd1b34ff01fee24c8b3011ba05 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -192,7 +192,7 @@ pub const FindFirstFileError = error{ }; pub fn FindFirstFile(dir_path: []const u8, find_file_data: *WIN32_FIND_DATAW) FindFirstFileError!HANDLE { - const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, [_]u16{ '\\', '*', 0 }); + const dir_path_w = try sliceToPrefixedSuffixedFileW(dir_path, [_]u16{ '\\', '*'}); const handle = kernel32.FindFirstFileW(&dir_path_w, find_file_data); if (handle == INVALID_HANDLE_VALUE) { @@ -919,18 +919,18 @@ pub fn nanoSecondsToFileTime(ns: i64) FILETIME { }; } -pub fn cStrToPrefixedFileW(s: [*]const u8) ![PATH_MAX_WIDE + 1]u16 { +pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); } -pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE + 1]u16 { - return sliceToPrefixedSuffixedFileW(s, [_]u16{0}); +pub fn sliceToPrefixedFileW(s: []const u8) ![PATH_MAX_WIDE:0]u16 { + return sliceToPrefixedSuffixedFileW(s, &[_]u16{}); } /// Assumes an absolute path. -pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 { +pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE:0]u16 { // TODO https://github.com/ziglang/zig/issues/2765 - var result: [PATH_MAX_WIDE + 1]u16 = undefined; + var result: [PATH_MAX_WIDE:0]u16 = undefined; const start_index = if (mem.startsWith(u16, s, [_]u16{'\\', '?'})) 0 else blk: { const prefix = [_]u16{ '\\', '?', '?', '\\' }; @@ -945,9 +945,9 @@ pub fn wToPrefixedFileW(s: []const u16) ![PATH_MAX_WIDE + 1]u16 { } -pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len]u16 { +pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) ![PATH_MAX_WIDE + suffix.len:0]u16 { // TODO https://github.com/ziglang/zig/issues/2765 - var result: [PATH_MAX_WIDE + suffix.len]u16 = undefined; + var result: [PATH_MAX_WIDE + suffix.len:0]u16 = undefined; // > File I/O functions in the Windows API convert "/" to "\" as part of // > converting the name to an NT-style name, except when using the "\\?\" // > prefix as detailed in the following sections. @@ -968,6 +968,7 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) const end_index = start_index + try std.unicode.utf8ToUtf16Le(result[start_index..], s); if (end_index + suffix.len > result.len) return error.NameTooLong; mem.copy(u16, result[end_index..], suffix); + result[end_index + suffix.len] = 0; return result; } diff --git a/lib/std/process.zig b/lib/std/process.zig index fca10a240d2313a7fa846ba610edcc116c6bf562..9880108465773bbfeadc7c4c7cf41cd4058ac7f7 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -77,7 +77,7 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap { // TODO: Verify that the documentation is incorrect // https://github.com/WebAssembly/WASI/issues/27 - var environ = try allocator.alloc(?[*]u8, environ_count + 1); + var environ = try allocator.alloc(?[*:0]u8, environ_count + 1); defer allocator.free(environ); var environ_buf = try std.heap.wasm_allocator.alloc(u8, environ_buf_size); defer allocator.free(environ_buf); @@ -397,7 +397,7 @@ pub fn argsAlloc(allocator: *mem.Allocator) ![][]u8 { return os.unexpectedErrno(args_sizes_get_ret); } - var argv = try allocator.alloc([*]u8, count); + var argv = try allocator.alloc([*:0]u8, count); defer allocator.free(argv); var argv_buf = try allocator.alloc(u8, buf_size); @@ -473,14 +473,14 @@ pub fn argsFree(allocator: *mem.Allocator, args_alloc: []const []u8) void { } test "windows arg parsing" { - testWindowsCmdLine(c"a b\tc d", [_][]const u8{ "a", "b", "c", "d" }); - testWindowsCmdLine(c"\"abc\" d e", [_][]const u8{ "abc", "d", "e" }); - testWindowsCmdLine(c"a\\\\\\b d\"e f\"g h", [_][]const u8{ "a\\\\\\b", "de fg", "h" }); - testWindowsCmdLine(c"a\\\\\\\"b c d", [_][]const u8{ "a\\\"b", "c", "d" }); - testWindowsCmdLine(c"a\\\\\\\\\"b c\" d e", [_][]const u8{ "a\\\\b c", "d", "e" }); - testWindowsCmdLine(c"a b\tc \"d f", [_][]const u8{ "a", "b", "c", "\"d", "f" }); + testWindowsCmdLine("a b\tc d", [_][]const u8{ "a", "b", "c", "d" }); + testWindowsCmdLine("\"abc\" d e", [_][]const u8{ "abc", "d", "e" }); + testWindowsCmdLine("a\\\\\\b d\"e f\"g h", [_][]const u8{ "a\\\\\\b", "de fg", "h" }); + testWindowsCmdLine("a\\\\\\\"b c d", [_][]const u8{ "a\\\"b", "c", "d" }); + testWindowsCmdLine("a\\\\\\\\\"b c\" d e", [_][]const u8{ "a\\\\b c", "d", "e" }); + testWindowsCmdLine("a b\tc \"d f", [_][]const u8{ "a", "b", "c", "\"d", "f" }); - testWindowsCmdLine(c"\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [_][]const u8{ + testWindowsCmdLine("\".\\..\\zig-cache\\build\" \"bin\\zig.exe\" \".\\..\" \".\\..\\zig-cache\" \"--help\"", [_][]const u8{ ".\\..\\zig-cache\\build", "bin\\zig.exe", ".\\..", diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 145c8897d5eae46078ac2a4bb34bfb33d0df5022..8ac00c4e04479bce35363d6ed63d9fe447ec46a8 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -66,14 +66,14 @@ extern fn strncmp(_l: [*]const u8, _r: [*]const u8, _n: usize) c_int { } extern fn strerror(errnum: c_int) [*]const u8 { - return c"TODO strerror implementation"; + return "TODO strerror implementation"; } test "strncmp" { - std.testing.expect(strncmp(c"a", c"b", 1) == -1); - std.testing.expect(strncmp(c"a", c"c", 1) == -2); - std.testing.expect(strncmp(c"b", c"a", 1) == 1); - std.testing.expect(strncmp(c"\xff", c"\x02", 1) == 253); + std.testing.expect(strncmp("a", "b", 1) == -1); + std.testing.expect(strncmp("a", "c", 1) == -2); + std.testing.expect(strncmp("b", "a", 1) == 1); + std.testing.expect(strncmp("\xff", "\x02", 1) == 253); } // Avoid dragging in the runtime safety mechanisms into this .o file, diff --git a/lib/std/special/start.zig b/lib/std/special/start.zig index c56d50d7c403b01343fe1b67602b805d34fab990..6d99618d2e0afa60f0c14b99dfe6665fd15c7be9 100644 --- a/lib/std/special/start.zig +++ b/lib/std/special/start.zig @@ -123,12 +123,12 @@ fn posixCallMainAndExit() noreturn { @setAlignStack(16); } const argc = starting_stack_ptr[0]; - const argv = @ptrCast([*][*]u8, starting_stack_ptr + 1); + const argv = @ptrCast([*][*:0]u8, starting_stack_ptr + 1); - const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); + const envp_optional = @ptrCast([*:null]?[*:0]u8, argv + argc + 1); var envp_count: usize = 0; while (envp_optional[envp_count]) |_| : (envp_count += 1) {} - const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; + const envp = @ptrCast([*][*:0]u8, envp_optional)[0..envp_count]; if (builtin.os == .linux) { // Find the beginning of the auxiliary vector @@ -168,7 +168,7 @@ fn posixCallMainAndExit() noreturn { std.os.exit(@inlineCall(callMainWithArgs, argc, argv, envp)); } -fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { +fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { std.os.argv = argv[0..argc]; std.os.environ = envp; @@ -177,10 +177,10 @@ fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { return initEventLoopAndCallMain(); } -extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { +extern fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) i32 { var env_count: usize = 0; while (c_envp[env_count] != null) : (env_count += 1) {} - const envp = @ptrCast([*][*]u8, c_envp)[0..env_count]; + const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; return @inlineCall(callMainWithArgs, @intCast(usize, c_argc), c_argv, envp); } diff --git a/lib/std/special/test_runner.zig b/lib/std/special/test_runner.zig index 2733775001eca5f625fe868b8a3efa4f687f21fe..4dc8be0fec9759b323a7f03de88cf375fd009726 100644 --- a/lib/std/special/test_runner.zig +++ b/lib/std/special/test_runner.zig @@ -36,7 +36,7 @@ pub fn main() anyerror!void { } root_node.end(); if (ok_count == test_fn_list.len) { - std.debug.warn("All tests passed.\n"); + std.debug.warn("All {} tests passed.\n", ok_count); } else { std.debug.warn("{} passed; {} skipped.\n", ok_count, skip_count); } diff --git a/lib/std/thread.zig b/lib/std/thread.zig index 4e1535405501e36083899feda03eb0fe764e4fef..fe976a6839d0dd13c5f62b4498629b385ab25a65 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -353,7 +353,7 @@ pub const Thread = struct { } var count: c_int = undefined; var count_len: usize = @sizeOf(c_int); - const name = if (comptime std.Target.current.isDarwin()) c"hw.logicalcpu" else c"hw.ncpu"; + const name = if (comptime std.Target.current.isDarwin()) "hw.logicalcpu" else "hw.ncpu"; os.sysctlbynameC(name, &count, &count_len, null, 0) catch |err| switch (err) { error.NameTooLong => unreachable, else => |e| return e, diff --git a/lib/std/valgrind/memcheck.zig b/lib/std/valgrind/memcheck.zig index a15a6cca0e6e32b323197d0403f5c604fa7be5f7..e0aefa7d5f3003dec92f953721d243ddff9f3f62 100644 --- a/lib/std/valgrind/memcheck.zig +++ b/lib/std/valgrind/memcheck.zig @@ -3,7 +3,7 @@ const testing = std.testing; const valgrind = std.valgrind; pub const MemCheckClientRequest = extern enum { - MakeMemNoAccess = valgrind.ToolBase("MC"), + MakeMemNoAccess = valgrind.ToolBase("MC".*), MakeMemUndefined, MakeMemDefined, Discard, diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 0a7bfe2f56b83d9f2e362ce500e938da1c711090..9f9064f88d1d838d2a70f0d590be1e98e6f9ee8f 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -1531,14 +1531,14 @@ pub const Node = struct { }; pub const PrefixOp = struct { - base: Node, + base: Node = Node{ .id = .PrefixOp }, op_token: TokenIndex, op: Op, rhs: *Node, pub const Op = union(enum) { AddressOf, - ArrayType: *Node, + ArrayType: ArrayInfo, Await, BitNot, BoolNot, @@ -1552,11 +1552,17 @@ pub const Node = struct { Try, }; + pub const ArrayInfo = struct { + len_expr: *Node, + sentinel: ?*Node, + }; + pub const PtrInfo = struct { - allowzero_token: ?TokenIndex, - align_info: ?Align, - const_token: ?TokenIndex, - volatile_token: ?TokenIndex, + allowzero_token: ?TokenIndex = null, + align_info: ?Align = null, + const_token: ?TokenIndex = null, + volatile_token: ?TokenIndex = null, + sentinel: ?*Node = null, pub const Align = struct { node: *Node, @@ -1575,6 +1581,11 @@ pub const Node = struct { switch (self.op) { // TODO https://github.com/ziglang/zig/issues/1107 Op.SliceType => |addr_of_info| { + if (addr_of_info.sentinel) |sentinel| { + if (i < 1) return sentinel; + i -= 1; + } + if (addr_of_info.align_info) |align_info| { if (i < 1) return align_info.node; i -= 1; @@ -1588,9 +1599,13 @@ pub const Node = struct { } }, - Op.ArrayType => |size_expr| { - if (i < 1) return size_expr; + Op.ArrayType => |array_info| { + if (i < 1) return array_info.len_expr; i -= 1; + if (array_info.sentinel) |sentinel| { + if (i < 1) return sentinel; + i -= 1; + } }, Op.AddressOf, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 42dff71b2acab222ff79953cbba97113a6bded1c..fd15cda11a6902f73b09f350dce3be4862d7dc7f 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1085,7 +1085,7 @@ fn parseInitList(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node.Suf const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ .base = Node{ .id = .SuffixOp }, - .lhs = .{.node = undefined}, // set by caller + .lhs = .{ .node = undefined }, // set by caller .op = op, .rtoken = try expectToken(it, tree, .RBrace), }; @@ -1138,7 +1138,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { while (try parseSuffixOp(arena, it, tree)) |node| { switch (node.id) { - .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res}, + .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res }, .InfixOp => node.cast(Node.InfixOp).?.lhs = res, else => unreachable, } @@ -1154,7 +1154,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const node = try arena.create(Node.SuffixOp); node.* = Node.SuffixOp{ .base = Node{ .id = .SuffixOp }, - .lhs = .{.node = res}, + .lhs = .{ .node = res }, .op = Node.SuffixOp.Op{ .Call = Node.SuffixOp.Op.Call{ .params = params.list, @@ -1171,7 +1171,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { while (true) { if (try parseSuffixOp(arena, it, tree)) |node| { switch (node.id) { - .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{.node = res}, + .SuffixOp => node.cast(Node.SuffixOp).?.lhs = .{ .node = res }, .InfixOp => node.cast(Node.InfixOp).?.lhs = res, else => unreachable, } @@ -1182,7 +1182,7 @@ fn parseSuffixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const call = try arena.create(Node.SuffixOp); call.* = Node.SuffixOp{ .base = Node{ .id = .SuffixOp }, - .lhs = .{.node = res}, + .lhs = .{ .node = res }, .op = Node.SuffixOp.Op{ .Call = Node.SuffixOp.Op.Call{ .params = params.list, @@ -1531,7 +1531,7 @@ fn parseAnonLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node // anon container literal if (try parseInitList(arena, it, tree)) |node| { - node.lhs = .{.dot = dot}; + node.lhs = .{ .dot = dot }; return &node.base; } @@ -2246,63 +2246,6 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return &node.base; } - if (try parseArrayTypeStart(arena, it, tree)) |node| { - switch (node.cast(Node.PrefixOp).?.op) { - .ArrayType => {}, - .SliceType => |*slice_type| { - // Collect pointer qualifiers in any order, but disallow duplicates - while (true) { - if (try parseByteAlign(arena, it, tree)) |align_expr| { - if (slice_type.align_info != null) { - try tree.errors.push(AstError{ - .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index }, - }); - return error.ParseError; - } - slice_type.align_info = Node.PrefixOp.PtrInfo.Align{ - .node = align_expr, - .bit_range = null, - }; - continue; - } - if (eatToken(it, .Keyword_const)) |const_token| { - if (slice_type.const_token != null) { - try tree.errors.push(AstError{ - .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index }, - }); - return error.ParseError; - } - slice_type.const_token = const_token; - continue; - } - if (eatToken(it, .Keyword_volatile)) |volatile_token| { - if (slice_type.volatile_token != null) { - try tree.errors.push(AstError{ - .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index }, - }); - return error.ParseError; - } - slice_type.volatile_token = volatile_token; - continue; - } - if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { - if (slice_type.allowzero_token != null) { - try tree.errors.push(AstError{ - .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index }, - }); - return error.ParseError; - } - slice_type.allowzero_token = allowzero_token; - continue; - } - break; - } - }, - else => unreachable, - } - return node; - } - if (try parsePtrTypeStart(arena, it, tree)) |node| { // If the token encountered was **, there will be two nodes instead of one. // The attributes should be applied to the rightmost operator. @@ -2361,6 +2304,63 @@ fn parsePrefixTypeOp(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node return node; } + if (try parseArrayTypeStart(arena, it, tree)) |node| { + switch (node.cast(Node.PrefixOp).?.op) { + .ArrayType => {}, + .SliceType => |*slice_type| { + // Collect pointer qualifiers in any order, but disallow duplicates + while (true) { + if (try parseByteAlign(arena, it, tree)) |align_expr| { + if (slice_type.align_info != null) { + try tree.errors.push(AstError{ + .ExtraAlignQualifier = AstError.ExtraAlignQualifier{ .token = it.index }, + }); + return error.ParseError; + } + slice_type.align_info = Node.PrefixOp.PtrInfo.Align{ + .node = align_expr, + .bit_range = null, + }; + continue; + } + if (eatToken(it, .Keyword_const)) |const_token| { + if (slice_type.const_token != null) { + try tree.errors.push(AstError{ + .ExtraConstQualifier = AstError.ExtraConstQualifier{ .token = it.index }, + }); + return error.ParseError; + } + slice_type.const_token = const_token; + continue; + } + if (eatToken(it, .Keyword_volatile)) |volatile_token| { + if (slice_type.volatile_token != null) { + try tree.errors.push(AstError{ + .ExtraVolatileQualifier = AstError.ExtraVolatileQualifier{ .token = it.index }, + }); + return error.ParseError; + } + slice_type.volatile_token = volatile_token; + continue; + } + if (eatToken(it, .Keyword_allowzero)) |allowzero_token| { + if (slice_type.allowzero_token != null) { + try tree.errors.push(AstError{ + .ExtraAllowZeroQualifier = AstError.ExtraAllowZeroQualifier{ .token = it.index }, + }); + return error.ParseError; + } + slice_type.allowzero_token = allowzero_token; + continue; + } + break; + } + }, + else => unreachable, + } + return node; + } + return null; } @@ -2459,10 +2459,21 @@ const AnnotatedParamList = struct { fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { const lbracket = eatToken(it, .LBracket) orelse return null; const expr = try parseExpr(arena, it, tree); + const sentinel = if (eatToken(it, .Colon)) |_| + try expectNode(arena, it, tree, parseExpr, AstError{ + .ExpectedExpr = .{ .token = it.index }, + }) + else + null; const rbracket = try expectToken(it, tree, .RBracket); - const op = if (expr) |element_type| - Node.PrefixOp.Op{ .ArrayType = element_type } + const op = if (expr) |len_expr| + Node.PrefixOp.Op{ + .ArrayType = .{ + .len_expr = len_expr, + .sentinel = sentinel, + }, + } else Node.PrefixOp.Op{ .SliceType = Node.PrefixOp.PtrInfo{ @@ -2470,6 +2481,7 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No .align_info = null, .const_token = null, .volatile_token = null, + .sentinel = sentinel, }, }; @@ -2489,47 +2501,76 @@ fn parseArrayTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No /// / PTRUNKNOWN /// / PTRC fn parsePtrTypeStart(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { - const token = eatAnnotatedToken(it, .Asterisk) orelse - eatAnnotatedToken(it, .AsteriskAsterisk) orelse - eatAnnotatedToken(it, .BracketStarBracket) orelse - eatAnnotatedToken(it, .BracketStarCBracket) orelse - return null; + if (eatToken(it, .Asterisk)) |asterisk| { + const sentinel = if (eatToken(it, .Colon)) |_| + try expectNode(arena, it, tree, parseExpr, AstError{ + .ExpectedExpr = .{ .token = it.index }, + }) + else + null; + const node = try arena.create(Node.PrefixOp); + node.* = .{ + .op_token = asterisk, + .op = .{ .PtrType = .{ .sentinel = sentinel } }, + .rhs = undefined, // set by caller + }; + return &node.base; + } - const node = try arena.create(Node.PrefixOp); - node.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, - .op_token = token.index, - .op = Node.PrefixOp.Op{ - .PtrType = Node.PrefixOp.PtrInfo{ - .allowzero_token = null, - .align_info = null, - .const_token = null, - .volatile_token = null, - }, - }, - .rhs = undefined, // set by caller - }; + if (eatToken(it, .AsteriskAsterisk)) |double_asterisk| { + const node = try arena.create(Node.PrefixOp); + node.* = Node.PrefixOp{ + .op_token = double_asterisk, + .op = Node.PrefixOp.Op{ .PtrType = .{} }, + .rhs = undefined, // set by caller + }; - // Special case for **, which is its own token - if (token.ptr.id == .AsteriskAsterisk) { + // Special case for **, which is its own token const child = try arena.create(Node.PrefixOp); child.* = Node.PrefixOp{ - .base = Node{ .id = .PrefixOp }, - .op_token = token.index, - .op = Node.PrefixOp.Op{ - .PtrType = Node.PrefixOp.PtrInfo{ - .allowzero_token = null, - .align_info = null, - .const_token = null, - .volatile_token = null, - }, - }, + .op_token = double_asterisk, + .op = Node.PrefixOp.Op{ .PtrType = .{} }, .rhs = undefined, // set by caller }; node.rhs = &child.base; - } - return &node.base; + return &node.base; + } + if (eatToken(it, .LBracket)) |lbracket| { + const asterisk = eatToken(it, .Asterisk) orelse { + putBackToken(it, lbracket); + return null; + }; + if (eatToken(it, .Identifier)) |ident| { + if (!std.mem.eql(u8, tree.tokenSlice(ident), "c")) { + putBackToken(it, ident); + } else { + _ = try expectToken(it, tree, .RBracket); + const node = try arena.create(Node.PrefixOp); + node.* = .{ + .op_token = ident, + .op = .{ .PtrType = .{} }, + .rhs = undefined, // set by caller + }; + return &node.base; + } + } + const sentinel = if (eatToken(it, .Colon)) |_| + try expectNode(arena, it, tree, parseExpr, AstError{ + .ExpectedExpr = .{ .token = it.index }, + }) + else + null; + _ = try expectToken(it, tree, .RBracket); + const node = try arena.create(Node.PrefixOp); + node.* = .{ + .op_token = lbracket, + .op = .{ .PtrType = .{ .sentinel = sentinel } }, + .rhs = undefined, // set by caller + }; + return &node.base; + } + return null; } /// ContainerDeclAuto <- ContainerDeclType LBRACE ContainerMembers RBRACE diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 2f420768bffef34e82c292891b0b2bc20b1ea969..ce195887224a2a5380b3d636865bc1c2adf7dc25 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -1552,6 +1552,7 @@ test "zig fmt: pointer attributes" { \\extern fn f2(s: **align(1) *const *volatile u8) c_int; \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; \\extern fn f4(s: *align(1) const volatile u8) c_int; + \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; \\ ); } @@ -1562,6 +1563,7 @@ test "zig fmt: slice attributes" { \\extern fn f2(s: **align(1) *const *volatile u8) c_int; \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; \\extern fn f4(s: *align(1) const volatile u8) c_int; + \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; \\ ); } @@ -1723,11 +1725,6 @@ test "zig fmt: multiline string" { \\ \\two) \\ \\three \\ ; - \\ const s2 = - \\ c\\one - \\ c\\two) - \\ c\\three - \\ ; \\ const s3 = // hi \\ \\one \\ \\two) @@ -1744,7 +1741,6 @@ test "zig fmt: values" { \\ 1; \\ 1.0; \\ "string"; - \\ c"cstring"; \\ 'c'; \\ true; \\ false; @@ -1889,6 +1885,7 @@ test "zig fmt: arrays" { \\ 2, \\ }; \\ const a: [0]u8 = []u8{}; + \\ const x: [4:0]u8 = undefined; \\} \\ ); diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 258a5493de312aea38133310ef0043c447685910..d6e245645598f746585e195a32fc0e7631f1c897 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -418,11 +418,27 @@ fn renderExpression( switch (prefix_op_node.op) { ast.Node.PrefixOp.Op.PtrType => |ptr_info| { - const star_offset = switch (tree.tokens.at(prefix_op_node.op_token).id) { - Token.Id.AsteriskAsterisk => @as(usize, 1), - else => @as(usize, 0), - }; - try renderTokenOffset(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None, star_offset); // * + const op_tok_id = tree.tokens.at(prefix_op_node.op_token).id; + switch (op_tok_id) { + .Asterisk, .AsteriskAsterisk => try stream.writeByte('*'), + .Identifier => try stream.write("[*c]"), + .LBracket => try stream.write("[*"), + else => unreachable, + } + if (ptr_info.sentinel) |sentinel| { + const colon_token = tree.prevToken(sentinel.firstToken()); + try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // : + const sentinel_space = switch (op_tok_id) { + .LBracket => Space.None, + else => Space.Space, + }; + try renderExpression(allocator, stream, tree, indent, start_col, sentinel, sentinel_space); + } + switch (op_tok_id) { + .Asterisk, .AsteriskAsterisk, .Identifier => {}, + .LBracket => try stream.writeByte(']'), + else => unreachable, + } if (ptr_info.allowzero_token) |allowzero_token| { try renderToken(tree, stream, allowzero_token, indent, start_col, Space.Space); // allowzero } @@ -499,9 +515,12 @@ fn renderExpression( } }, - ast.Node.PrefixOp.Op.ArrayType => |array_index| { + ast.Node.PrefixOp.Op.ArrayType => |array_info| { const lbracket = prefix_op_node.op_token; - const rbracket = tree.nextToken(array_index.lastToken()); + const rbracket = tree.nextToken(if (array_info.sentinel) |sentinel| + sentinel.lastToken() + else + array_info.len_expr.lastToken()); try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ @@ -509,13 +528,18 @@ fn renderExpression( const ends_with_comment = tree.tokens.at(rbracket - 1).id == .LineComment; const new_indent = if (ends_with_comment) indent + indent_delta else indent; const new_space = if (ends_with_comment) Space.Newline else Space.None; - try renderExpression(allocator, stream, tree, new_indent, start_col, array_index, new_space); + try renderExpression(allocator, stream, tree, new_indent, start_col, array_info.len_expr, new_space); if (starts_with_comment) { try stream.writeByte('\n'); } if (ends_with_comment or starts_with_comment) { try stream.writeByteNTimes(' ', indent); } + if (array_info.sentinel) |sentinel| { + const colon_token = tree.prevToken(sentinel.firstToken()); + try renderToken(tree, stream, colon_token, indent, start_col, Space.None); // : + try renderExpression(allocator, stream, tree, indent, start_col, sentinel, Space.None); + } try renderToken(tree, stream, rbracket, indent, start_col, Space.None); // ] }, ast.Node.PrefixOp.Op.BitNot, diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index f17adae64862bad48fd1eaeb3fc60e6418f7198b..0b2aea4cf63f90ef33cfd8dfb0ff7aaab5796f7e 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -143,8 +143,6 @@ pub const Token = struct { LineComment, DocComment, ContainerDocComment, - BracketStarBracket, - BracketStarCBracket, ShebangLine, Keyword_align, Keyword_allowzero, @@ -269,8 +267,6 @@ pub const Token = struct { .AngleBracketAngleBracketRight => ">>", .AngleBracketAngleBracketRightEqual => ">>=", .Tilde => "~", - .BracketStarBracket => "[*]", - .BracketStarCBracket => "[*c]", .Keyword_align => "align", .Keyword_allowzero => "allowzero", .Keyword_and => "and", @@ -351,7 +347,6 @@ pub const Tokenizer = struct { Start, Identifier, Builtin, - C, StringLiteral, StringLiteralBackslash, MultilineStringLiteralLine, @@ -401,9 +396,6 @@ pub const Tokenizer = struct { Period, Period2, SawAtSign, - LBracket, - LBracketStar, - LBracketStarC, }; pub fn next(self: *Tokenizer) Token { @@ -427,10 +419,6 @@ pub const Tokenizer = struct { ' ', '\n', '\t', '\r' => { result.start = self.index + 1; }, - 'c' => { - state = State.C; - result.id = Token.Id.Identifier; - }, '"' => { state = State.StringLiteral; result.id = Token.Id.StringLiteral; @@ -438,7 +426,7 @@ pub const Tokenizer = struct { '\'' => { state = State.CharLiteral; }, - 'a'...'b', 'd'...'z', 'A'...'Z', '_' => { + 'a'...'z', 'A'...'Z', '_' => { state = State.Identifier; result.id = Token.Id.Identifier; }, @@ -465,7 +453,9 @@ pub const Tokenizer = struct { break; }, '[' => { - state = State.LBracket; + result.id = .LBracket; + self.index += 1; + break; }, ']' => { result.id = Token.Id.RBracket; @@ -569,43 +559,6 @@ pub const Tokenizer = struct { }, }, - State.LBracket => switch (c) { - '*' => { - state = State.LBracketStar; - }, - else => { - result.id = Token.Id.LBracket; - break; - }, - }, - - State.LBracketStar => switch (c) { - 'c' => { - state = State.LBracketStarC; - }, - ']' => { - result.id = Token.Id.BracketStarBracket; - self.index += 1; - break; - }, - else => { - result.id = Token.Id.Invalid; - break; - }, - }, - - State.LBracketStarC => switch (c) { - ']' => { - result.id = Token.Id.BracketStarCBracket; - self.index += 1; - break; - }, - else => { - result.id = Token.Id.Invalid; - break; - }, - }, - State.Ampersand => switch (c) { '&' => { result.id = Token.Id.Invalid_ampersands; @@ -730,20 +683,6 @@ pub const Tokenizer = struct { }, else => break, }, - State.C => switch (c) { - '\\' => { - state = State.Backslash; - result.id = Token.Id.MultilineStringLiteralLine; - }, - '"' => { - state = State.StringLiteral; - result.id = Token.Id.StringLiteral; - }, - 'a'...'z', 'A'...'Z', '_', '0'...'9' => { - state = State.Identifier; - }, - else => break, - }, State.StringLiteral => switch (c) { '\\' => { state = State.StringLiteralBackslash; @@ -1204,7 +1143,6 @@ pub const Tokenizer = struct { } else if (self.index == self.buffer.len) { switch (state) { State.Start, - State.C, State.IntegerLiteral, State.IntegerLiteralWithRadix, State.IntegerLiteralWithRadixHex, @@ -1247,8 +1185,6 @@ pub const Tokenizer = struct { State.CharLiteralEnd, State.CharLiteralUnicode, State.StringLiteralBackslash, - State.LBracketStar, - State.LBracketStarC, => { result.id = Token.Id.Invalid; }, @@ -1265,9 +1201,6 @@ pub const Tokenizer = struct { State.Slash => { result.id = Token.Id.Slash; }, - State.LBracket => { - result.id = Token.Id.LBracket; - }, State.Zero => { result.id = Token.Id.IntegerLiteral; }, @@ -1388,9 +1321,14 @@ test "tokenizer - unknown length pointer and then c pointer" { \\[*]u8 \\[*c]u8 , [_]Token.Id{ - Token.Id.BracketStarBracket, + Token.Id.LBracket, + Token.Id.Asterisk, + Token.Id.RBracket, Token.Id.Identifier, - Token.Id.BracketStarCBracket, + Token.Id.LBracket, + Token.Id.Asterisk, + Token.Id.Identifier, + Token.Id.RBracket, Token.Id.Identifier, }); } diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 8f3e539162edb1f50580003688850a1cc1ee6161..31907ff2662d7f6edcbcdbe9fb2bbe1527b1e92a 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -708,7 +708,7 @@ pub const ZigClangStringLiteral_StringKind = extern enum { }; pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; -pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*]const u8; +pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; pub extern fn ZigClangSourceManager_getSpellingColumnNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; pub extern fn ZigClangSourceManager_getCharacterData(self: ?*const struct_ZigClangSourceManager, SL: struct_ZigClangSourceLocation) [*c]const u8; @@ -746,7 +746,7 @@ pub extern fn ZigClangQualType_isRestrictQualified(self: struct_ZigClangQualType pub extern fn ZigClangType_getTypeClass(self: ?*const struct_ZigClangType) ZigClangTypeClass; pub extern fn ZigClangType_getPointeeType(self: ?*const struct_ZigClangType) struct_ZigClangQualType; pub extern fn ZigClangType_isVoidType(self: ?*const struct_ZigClangType) bool; -pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*]const u8; +pub extern fn ZigClangType_getTypeClassName(self: *const struct_ZigClangType) [*:0]const u8; pub extern fn ZigClangStmt_getBeginLoc(self: *const struct_ZigClangStmt) struct_ZigClangSourceLocation; pub extern fn ZigClangStmt_getStmtClass(self: ?*const struct_ZigClangStmt) ZigClangStmtClass; pub extern fn ZigClangStmt_classof_Expr(self: ?*const struct_ZigClangStmt) bool; @@ -904,7 +904,7 @@ pub extern fn ZigClangLoadFromCommandLine( ) ?*ZigClangASTUnit; pub extern fn ZigClangDecl_getKind(decl: *const ZigClangDecl) ZigClangDeclKind; -pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*]const u8; +pub extern fn ZigClangDecl_getDeclKindName(decl: *const struct_ZigClangDecl) [*:0]const u8; pub const ZigClangCompoundStmt_const_body_iterator = [*c]const *struct_ZigClangStmt; diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 77b1d4fd74f0eea2e9db6bc5a071031ced71e418..7d4fb5fa7213b4ed23a294e5b8ea99f1859e6255 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -52,7 +52,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) u32(c.ZIG_VERSION_MINOR), u32(c.ZIG_VERSION_PATCH), ); - const flags = c""; + const flags = ""; const runtime_version = 0; const compile_unit_file = llvm.CreateFile( dibuilder, @@ -68,7 +68,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) is_optimized, flags, runtime_version, - c"", + "", 0, !comp.strip, ) orelse return error.OutOfMemory; @@ -402,7 +402,7 @@ pub fn getHandleValue(ofile: *ObjectFile, ptr: *llvm.Value, ptr_type: *Type.Poin if (child_type.handleIsPtr()) { return ptr; } - return try renderLoad(ofile, ptr, ptr_type, c""); + return try renderLoad(ofile, ptr, ptr_type, ""); } pub fn renderStoreUntyped( diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index b12a01d6494b10c3d9dfcdc5d65b938ba285e477..2f0de0c5212a263606b9b6e7606b23db12669403 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -490,8 +490,8 @@ pub const Compilation = struct { // LLVM creates invalid binaries on Windows sometimes. // See https://github.com/ziglang/zig/issues/508 // As a workaround we do not use target native features on Windows. - var target_specific_cpu_args: ?[*]u8 = null; - var target_specific_cpu_features: ?[*]u8 = null; + var target_specific_cpu_args: ?[*:0]u8 = null; + var target_specific_cpu_features: ?[*:0]u8 = null; defer llvm.DisposeMessage(target_specific_cpu_args); defer llvm.DisposeMessage(target_specific_cpu_features); if (target == Target.Native and !target.isWindows()) { @@ -501,9 +501,9 @@ pub const Compilation = struct { comp.target_machine = llvm.CreateTargetMachine( comp.llvm_target, - comp.llvm_triple.ptr(), - target_specific_cpu_args orelse c"", - target_specific_cpu_features orelse c"", + comp.llvm_triple.toSliceConst(), + target_specific_cpu_args orelse "", + target_specific_cpu_features orelse "", opt_level, reloc_mode, llvm.CodeModelDefault, diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 0017edd96caab76b043a8d76794fc148f50f2989..905d21811425d56fe8cbc4def830758cb861a4fb 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -330,7 +330,7 @@ pub const Inst = struct { @intCast(c_uint, args.len), llvm_cc, fn_inline, - c"", + "", ) orelse error.OutOfMemory; } }; @@ -1409,7 +1409,7 @@ pub const Builder = struct { if (block.label) |label| { block_scope.incoming_values = std.ArrayList(*Inst).init(irb.arena()); block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena()); - block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd"); + block_scope.end_block = try irb.createBasicBlock(parent_scope, "BlockEnd"); block_scope.is_comptime = try irb.buildConstBool( parent_scope, Span.token(block.lbrace), @@ -1541,8 +1541,8 @@ pub const Builder = struct { const defer_counts = irb.countDefers(scope, outer_scope); const have_err_defers = defer_counts.error_exit != 0; if (have_err_defers or irb.comp.have_err_ret_tracing) { - const err_block = try irb.createBasicBlock(scope, c"ErrRetErr"); - const ok_block = try irb.createBasicBlock(scope, c"ErrRetOk"); + const err_block = try irb.createBasicBlock(scope, "ErrRetErr"); + const ok_block = try irb.createBasicBlock(scope, "ErrRetOk"); if (!have_err_defers) { _ = try irb.genDefersForBlock(scope, outer_scope, .ScopeExit); } @@ -1563,7 +1563,7 @@ pub const Builder = struct { .is_comptime = err_is_comptime, }); - const ret_stmt_block = try irb.createBasicBlock(scope, c"RetStmt"); + const ret_stmt_block = try irb.createBasicBlock(scope, "RetStmt"); try irb.setCursorAtEndAndAppendBlock(err_block); if (have_err_defers) { @@ -2528,7 +2528,7 @@ pub async fn gen( var irb = try Builder.init(comp, tree_scope, scope); errdefer irb.abort(); - const entry_block = try irb.createBasicBlock(scope, c"Entry"); + const entry_block = try irb.createBasicBlock(scope, "Entry"); entry_block.ref(&irb); // Entry block gets a reference because we enter it to begin. try irb.setCursorAtEndAndAppendBlock(entry_block); diff --git a/src-self-hosted/link.zig b/src-self-hosted/link.zig index 845d96b193ce25858fe544cbb36fc5b876f6f1d4..aafe05eb8be959c83959d2b883ba080b8751bcf3 100644 --- a/src-self-hosted/link.zig +++ b/src-self-hosted/link.zig @@ -55,7 +55,7 @@ pub async fn link(comp: *Compilation) !void { // even though we're calling LLD as a library it thinks the first // argument is its own exe name - try ctx.args.append(c"lld"); + try ctx.args.append("lld"); if (comp.haveLibC()) { ctx.libc = ctx.comp.override_libc orelse blk: { @@ -145,7 +145,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { // lj->args.append("-T"); // lj->args.append(g->linker_script); //} - try ctx.args.append(c"--gc-sections"); + try ctx.args.append("--gc-sections"); //lj->args.append("-m"); //lj->args.append(getLDMOption(&g->zig_target)); @@ -155,9 +155,9 @@ fn constructLinkerArgsElf(ctx: *Context) !void { //Buf *soname = nullptr; if (ctx.comp.is_static) { if (util.isArmOrThumb(ctx.comp.target)) { - try ctx.args.append(c"-Bstatic"); + try ctx.args.append("-Bstatic"); } else { - try ctx.args.append(c"-static"); + try ctx.args.append("-static"); } } //} else if (shared) { @@ -170,7 +170,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { // soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major); //} - try ctx.args.append(c"-o"); + try ctx.args.append("-o"); try ctx.args.append(ctx.out_file_path.ptr()); if (ctx.link_in_crt) { @@ -213,10 +213,10 @@ fn constructLinkerArgsElf(ctx: *Context) !void { //} if (ctx.comp.haveLibC()) { - try ctx.args.append(c"-L"); + try ctx.args.append("-L"); try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr); - try ctx.args.append(c"-L"); + try ctx.args.append("-L"); try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr); if (!ctx.comp.is_static) { @@ -225,7 +225,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void { if (util.getDynamicLinkerPath(ctx.comp.target)) |dl| break :blk dl; return error.LibCMissingDynamicLinker; }; - try ctx.args.append(c"-dynamic-linker"); + try ctx.args.append("-dynamic-linker"); try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr); } } @@ -272,23 +272,23 @@ fn constructLinkerArgsElf(ctx: *Context) !void { // libc dep if (ctx.comp.haveLibC()) { if (ctx.comp.is_static) { - try ctx.args.append(c"--start-group"); - try ctx.args.append(c"-lgcc"); - try ctx.args.append(c"-lgcc_eh"); - try ctx.args.append(c"-lc"); - try ctx.args.append(c"-lm"); - try ctx.args.append(c"--end-group"); + try ctx.args.append("--start-group"); + try ctx.args.append("-lgcc"); + try ctx.args.append("-lgcc_eh"); + try ctx.args.append("-lc"); + try ctx.args.append("-lm"); + try ctx.args.append("--end-group"); } else { - try ctx.args.append(c"-lgcc"); - try ctx.args.append(c"--as-needed"); - try ctx.args.append(c"-lgcc_s"); - try ctx.args.append(c"--no-as-needed"); - try ctx.args.append(c"-lc"); - try ctx.args.append(c"-lm"); - try ctx.args.append(c"-lgcc"); - try ctx.args.append(c"--as-needed"); - try ctx.args.append(c"-lgcc_s"); - try ctx.args.append(c"--no-as-needed"); + try ctx.args.append("-lgcc"); + try ctx.args.append("--as-needed"); + try ctx.args.append("-lgcc_s"); + try ctx.args.append("--no-as-needed"); + try ctx.args.append("-lc"); + try ctx.args.append("-lm"); + try ctx.args.append("-lgcc"); + try ctx.args.append("--as-needed"); + try ctx.args.append("-lgcc_s"); + try ctx.args.append("--no-as-needed"); } } @@ -299,14 +299,14 @@ fn constructLinkerArgsElf(ctx: *Context) !void { } if (ctx.comp.target != Target.Native) { - try ctx.args.append(c"--allow-shlib-undefined"); + try ctx.args.append("--allow-shlib-undefined"); } if (ctx.comp.target.getOs() == .zen) { - try ctx.args.append(c"-e"); - try ctx.args.append(c"_start"); + try ctx.args.append("-e"); + try ctx.args.append("_start"); - try ctx.args.append(c"--image-base=0x10000000"); + try ctx.args.append("--image-base=0x10000000"); } } @@ -317,23 +317,23 @@ fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void { } fn constructLinkerArgsCoff(ctx: *Context) !void { - try ctx.args.append(c"-NOLOGO"); + try ctx.args.append("-NOLOGO"); if (!ctx.comp.strip) { - try ctx.args.append(c"-DEBUG"); + try ctx.args.append("-DEBUG"); } switch (ctx.comp.target.getArch()) { - .i386 => try ctx.args.append(c"-MACHINE:X86"), - .x86_64 => try ctx.args.append(c"-MACHINE:X64"), - .aarch64 => try ctx.args.append(c"-MACHINE:ARM"), + .i386 => try ctx.args.append("-MACHINE:X86"), + .x86_64 => try ctx.args.append("-MACHINE:X64"), + .aarch64 => try ctx.args.append("-MACHINE:ARM"), else => return error.UnsupportedLinkArchitecture, } if (ctx.comp.windows_subsystem_windows) { - try ctx.args.append(c"/SUBSYSTEM:windows"); + try ctx.args.append("/SUBSYSTEM:windows"); } else if (ctx.comp.windows_subsystem_console) { - try ctx.args.append(c"/SUBSYSTEM:console"); + try ctx.args.append("/SUBSYSTEM:console"); } const is_library = ctx.comp.kind == .Lib; @@ -367,14 +367,14 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { // Visual C++ 2015 Conformance Changes // https://msdn.microsoft.com/en-us/library/bb531344.aspx - try ctx.args.append(c"legacy_stdio_definitions.lib"); + try ctx.args.append("legacy_stdio_definitions.lib"); // msvcrt depends on kernel32 - try ctx.args.append(c"kernel32.lib"); + try ctx.args.append("kernel32.lib"); } else { - try ctx.args.append(c"-NODEFAULTLIB"); + try ctx.args.append("-NODEFAULTLIB"); if (!is_library) { - try ctx.args.append(c"-ENTRY:WinMainCRTStartup"); + try ctx.args.append("-ENTRY:WinMainCRTStartup"); // TODO //if (g->have_winmain) { // lj->args.append("-ENTRY:WinMain"); @@ -385,7 +385,7 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { } if (is_library and !ctx.comp.is_static) { - try ctx.args.append(c"-DLL"); + try ctx.args.append("-DLL"); } //for (size_t i = 0; i < g->lib_dirs.length; i += 1) { @@ -463,18 +463,18 @@ fn constructLinkerArgsCoff(ctx: *Context) !void { } fn constructLinkerArgsMachO(ctx: *Context) !void { - try ctx.args.append(c"-demangle"); + try ctx.args.append("-demangle"); if (ctx.comp.linker_rdynamic) { - try ctx.args.append(c"-export_dynamic"); + try ctx.args.append("-export_dynamic"); } const is_lib = ctx.comp.kind == .Lib; const shared = !ctx.comp.is_static and is_lib; if (ctx.comp.is_static) { - try ctx.args.append(c"-static"); + try ctx.args.append("-static"); } else { - try ctx.args.append(c"-dynamic"); + try ctx.args.append("-dynamic"); } //if (is_lib) { @@ -503,7 +503,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { // } //} - try ctx.args.append(c"-arch"); + try ctx.args.append("-arch"); const darwin_arch_str = try std.cstr.addNullByte( &ctx.arena.allocator, ctx.comp.target.getDarwinArchString(), @@ -512,22 +512,22 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { const platform = try DarwinPlatform.get(ctx.comp); switch (platform.kind) { - .MacOS => try ctx.args.append(c"-macosx_version_min"), - .IPhoneOS => try ctx.args.append(c"-iphoneos_version_min"), - .IPhoneOSSimulator => try ctx.args.append(c"-ios_simulator_version_min"), + .MacOS => try ctx.args.append("-macosx_version_min"), + .IPhoneOS => try ctx.args.append("-iphoneos_version_min"), + .IPhoneOSSimulator => try ctx.args.append("-ios_simulator_version_min"), } const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro); try ctx.args.append(ver_str.ptr); if (ctx.comp.kind == .Exe) { if (ctx.comp.is_static) { - try ctx.args.append(c"-no_pie"); + try ctx.args.append("-no_pie"); } else { - try ctx.args.append(c"-pie"); + try ctx.args.append("-pie"); } } - try ctx.args.append(c"-o"); + try ctx.args.append("-o"); try ctx.args.append(ctx.out_file_path.ptr()); //for (size_t i = 0; i < g->rpath_list.length; i += 1) { @@ -537,27 +537,27 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { //add_rpath(lj, &lj->out_file); if (shared) { - try ctx.args.append(c"-headerpad_max_install_names"); + try ctx.args.append("-headerpad_max_install_names"); } else if (ctx.comp.is_static) { - try ctx.args.append(c"-lcrt0.o"); + try ctx.args.append("-lcrt0.o"); } else { switch (platform.kind) { .MacOS => { if (platform.versionLessThan(10, 5)) { - try ctx.args.append(c"-lcrt1.o"); + try ctx.args.append("-lcrt1.o"); } else if (platform.versionLessThan(10, 6)) { - try ctx.args.append(c"-lcrt1.10.5.o"); + try ctx.args.append("-lcrt1.10.5.o"); } else if (platform.versionLessThan(10, 8)) { - try ctx.args.append(c"-lcrt1.10.6.o"); + try ctx.args.append("-lcrt1.10.6.o"); } }, .IPhoneOS => { if (ctx.comp.target.getArch() == .aarch64) { // iOS does not need any crt1 files for arm64 } else if (platform.versionLessThan(3, 1)) { - try ctx.args.append(c"-lcrt1.o"); + try ctx.args.append("-lcrt1.o"); } else if (platform.versionLessThan(6, 0)) { - try ctx.args.append(c"-lcrt1.3.1.o"); + try ctx.args.append("-lcrt1.3.1.o"); } }, .IPhoneOSSimulator => {}, // no crt1.o needed @@ -589,7 +589,7 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { // to make syscalls because the syscall numbers are not documented // and change between versions. // so we always link against libSystem - try ctx.args.append(c"-lSystem"); + try ctx.args.append("-lSystem"); } else { if (mem.indexOfScalar(u8, lib.name, '/') == null) { const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name); @@ -601,15 +601,15 @@ fn constructLinkerArgsMachO(ctx: *Context) !void { } } } else { - try ctx.args.append(c"-undefined"); - try ctx.args.append(c"dynamic_lookup"); + try ctx.args.append("-undefined"); + try ctx.args.append("dynamic_lookup"); } if (platform.kind == .MacOS) { if (platform.versionLessThan(10, 5)) { - try ctx.args.append(c"-lgcc_s.10.4"); + try ctx.args.append("-lgcc_s.10.4"); } else if (platform.versionLessThan(10, 6)) { - try ctx.args.append(c"-lgcc_s.10.5"); + try ctx.args.append("-lgcc_s.10.5"); } } else { @panic("TODO"); diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index c8eba2cd2d930ab5b256eb7c4f0da1c430a59477..af42adb97dfa0c10e3010d7567c0b4d122aa25e0 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -83,16 +83,16 @@ pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; pub const AddGlobal = LLVMAddGlobal; -extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*]const u8) ?*Value; +extern fn LLVMAddGlobal(M: *Module, Ty: *Type, Name: [*:0]const u8) ?*Value; pub const ConstStringInContext = LLVMConstStringInContext; -extern fn LLVMConstStringInContext(C: *Context, Str: [*]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; +extern fn LLVMConstStringInContext(C: *Context, Str: [*:0]const u8, Length: c_uint, DontNullTerminate: Bool) ?*Value; pub const ConstInt = LLVMConstInt; extern fn LLVMConstInt(IntTy: *Type, N: c_ulonglong, SignExtend: Bool) ?*Value; pub const BuildLoad = LLVMBuildLoad; -extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*]const u8) ?*Value; +extern fn LLVMBuildLoad(arg0: *Builder, PointerVal: *Value, Name: [*:0]const u8) ?*Value; pub const ConstNull = LLVMConstNull; extern fn LLVMConstNull(Ty: *Type) ?*Value; @@ -110,24 +110,24 @@ pub const CreateEnumAttribute = LLVMCreateEnumAttribute; extern fn LLVMCreateEnumAttribute(C: *Context, KindID: c_uint, Val: u64) ?*Attribute; pub const AddFunction = LLVMAddFunction; -extern fn LLVMAddFunction(M: *Module, Name: [*]const u8, FunctionTy: *Type) ?*Value; +extern fn LLVMAddFunction(M: *Module, Name: [*:0]const u8, FunctionTy: *Type) ?*Value; pub const CreateCompileUnit = ZigLLVMCreateCompileUnit; extern fn ZigLLVMCreateCompileUnit( dibuilder: *DIBuilder, lang: c_uint, difile: *DIFile, - producer: [*]const u8, + producer: [*:0]const u8, is_optimized: bool, - flags: [*]const u8, + flags: [*:0]const u8, runtime_version: c_uint, - split_name: [*]const u8, + split_name: [*:0]const u8, dwo_id: u64, emit_debug_info: bool, ) ?*DICompileUnit; pub const CreateFile = ZigLLVMCreateFile; -extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*]const u8, directory: [*]const u8) ?*DIFile; +extern fn ZigLLVMCreateFile(dibuilder: *DIBuilder, filename: [*:0]const u8, directory: [*:0]const u8) ?*DIFile; pub const ArrayType = LLVMArrayType; extern fn LLVMArrayType(ElementType: *Type, ElementCount: c_uint) ?*Type; @@ -145,7 +145,7 @@ pub const IntTypeInContext = LLVMIntTypeInContext; extern fn LLVMIntTypeInContext(C: *Context, NumBits: c_uint) ?*Type; pub const ModuleCreateWithNameInContext = LLVMModuleCreateWithNameInContext; -extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*]const u8, C: *Context) ?*Module; +extern fn LLVMModuleCreateWithNameInContext(ModuleID: [*:0]const u8, C: *Context) ?*Module; pub const VoidTypeInContext = LLVMVoidTypeInContext; extern fn LLVMVoidTypeInContext(C: *Context) ?*Type; @@ -157,7 +157,7 @@ pub const ContextDispose = LLVMContextDispose; extern fn LLVMContextDispose(C: *Context) void; pub const CopyStringRepOfTargetData = LLVMCopyStringRepOfTargetData; -extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8; +extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*:0]u8; pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout; extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData; @@ -165,9 +165,9 @@ extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData; pub const CreateTargetMachine = ZigLLVMCreateTargetMachine; extern fn ZigLLVMCreateTargetMachine( T: *Target, - Triple: [*]const u8, - CPU: [*]const u8, - Features: [*]const u8, + Triple: [*:0]const u8, + CPU: [*:0]const u8, + Features: [*:0]const u8, Level: CodeGenOptLevel, Reloc: RelocMode, CodeModel: CodeModel, @@ -175,10 +175,10 @@ extern fn ZigLLVMCreateTargetMachine( ) ?*TargetMachine; pub const GetHostCPUName = LLVMGetHostCPUName; -extern fn LLVMGetHostCPUName() ?[*]u8; +extern fn LLVMGetHostCPUName() ?[*:0]u8; pub const GetNativeFeatures = ZigLLVMGetNativeFeatures; -extern fn ZigLLVMGetNativeFeatures() ?[*]u8; +extern fn ZigLLVMGetNativeFeatures() ?[*:0]u8; pub const GetElementType = LLVMGetElementType; extern fn LLVMGetElementType(Ty: *Type) *Type; @@ -190,16 +190,16 @@ pub const BuildStore = LLVMBuildStore; extern fn LLVMBuildStore(arg0: *Builder, Val: *Value, Ptr: *Value) ?*Value; pub const BuildAlloca = LLVMBuildAlloca; -extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*]const u8) ?*Value; +extern fn LLVMBuildAlloca(arg0: *Builder, Ty: *Type, Name: ?[*:0]const u8) ?*Value; pub const ConstInBoundsGEP = LLVMConstInBoundsGEP; pub extern fn LLVMConstInBoundsGEP(ConstantVal: *Value, ConstantIndices: [*]*Value, NumIndices: c_uint) ?*Value; pub const GetTargetFromTriple = LLVMGetTargetFromTriple; -extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: **Target, ErrorMessage: ?*[*]u8) Bool; +extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **Target, ErrorMessage: ?*[*:0]u8) Bool; pub const VerifyModule = LLVMVerifyModule; -extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; +extern fn LLVMVerifyModule(M: *Module, Action: VerifierFailureAction, OutMessage: *?[*:0]u8) Bool; pub const GetInsertBlock = LLVMGetInsertBlock; extern fn LLVMGetInsertBlock(Builder: *Builder) *BasicBlock; @@ -216,7 +216,7 @@ pub const GetParam = LLVMGetParam; extern fn LLVMGetParam(Fn: *Value, Index: c_uint) *Value; pub const AppendBasicBlockInContext = LLVMAppendBasicBlockInContext; -extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*]const u8) ?*BasicBlock; +extern fn LLVMAppendBasicBlockInContext(C: *Context, Fn: *Value, Name: [*:0]const u8) ?*BasicBlock; pub const PositionBuilderAtEnd = LLVMPositionBuilderAtEnd; extern fn LLVMPositionBuilderAtEnd(Builder: *Builder, Block: *BasicBlock) void; @@ -278,14 +278,14 @@ pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile; extern fn ZigLLVMTargetMachineEmitToFile( targ_machine_ref: *TargetMachine, module_ref: *Module, - filename: [*]const u8, + filename: [*:0]const u8, output_type: EmitOutputType, - error_message: *[*]u8, + error_message: *[*:0]u8, is_debug: bool, is_small: bool, ) bool; pub const BuildCall = ZigLLVMBuildCall; -extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?*Value; +extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*:0]const u8) ?*Value; pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage; diff --git a/src-self-hosted/stage1.zig b/src-self-hosted/stage1.zig index e214ba6ea9444dd75e5534d0f61cef25ba0f137c..7220c3d0d97bcfeefdd1d38d563bc8e83f3991e3 100644 --- a/src-self-hosted/stage1.zig +++ b/src-self-hosted/stage1.zig @@ -27,7 +27,7 @@ comptime { // ABI warning export fn stage2_zen(ptr: *[*]const u8, len: *usize) void { const info_zen = @import("main.zig").info_zen; - ptr.* = &info_zen; + ptr.* = info_zen; len.* = info_zen.len; } @@ -144,7 +144,7 @@ export fn stage2_render_ast(tree: *ast.Tree, output_file: *FILE) Error { // TODO: just use the actual self-hosted zig fmt. Until https://github.com/ziglang/zig/issues/2377, // we use a blocking implementation. -export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int { +export fn stage2_fmt(argc: c_int, argv: [*]const [*:0]const u8) c_int { if (std.debug.runtime_safety) { fmtMain(argc, argv) catch unreachable; } else { @@ -156,7 +156,7 @@ export fn stage2_fmt(argc: c_int, argv: [*]const [*]const u8) c_int { return 0; } -fn fmtMain(argc: c_int, argv: [*]const [*]const u8) !void { +fn fmtMain(argc: c_int, argv: [*]const [*:0]const u8) !void { const allocator = std.heap.c_allocator; var args_list = std.ArrayList([]const u8).init(allocator); const argc_usize = @intCast(usize, argc); diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 32753ed9967d0baaea71c0ad687114afedf71a59..0470ab92dc1d75136f617c18633df665ea6555a3 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -113,7 +113,7 @@ const Context = struct { } /// Convert a null-terminated C string to a slice allocated in the arena - fn str(c: *Context, s: [*]const u8) ![]u8 { + fn str(c: *Context, s: [*:0]const u8) ![]u8 { return std.mem.dupe(c.a(), u8, std.mem.toSliceConst(u8, s)); } @@ -696,10 +696,9 @@ fn transStringLiteral( len = 0; for (str) |c| len += escapeChar(c, &char_buf).len; - const buf = try rp.c.a().alloc(u8, len + "c\"\"".len); - buf[0] = 'c'; - buf[1] = '"'; - writeEscapedString(buf[2..], str); + const buf = try rp.c.a().alloc(u8, len + "\"\"".len); + buf[0] = '"'; + writeEscapedString(buf[1..], str); buf[buf.len - 1] = '"'; const token = try appendToken(rp.c, .StringLiteral, buf); @@ -1104,16 +1103,30 @@ fn transCreateNodePtrType( is_const: bool, is_volatile: bool, op_tok_id: std.zig.Token.Id, - bytes: []const u8, ) !*ast.Node.PrefixOp { const node = try c.a().create(ast.Node.PrefixOp); + const op_token = switch (op_tok_id) { + .LBracket => blk: { + const lbracket = try appendToken(c, .LBracket, "["); + _ = try appendToken(c, .Asterisk, "*"); + _ = try appendToken(c, .RBracket, "]"); + break :blk lbracket; + }, + .Identifier => blk: { + _ = try appendToken(c, .LBracket, "["); + _ = try appendToken(c, .Asterisk, "*"); + const c_ident = try appendToken(c, .Identifier, "c"); + _ = try appendToken(c, .RBracket, "]"); + break :blk c_ident; + }, + .Asterisk => try appendToken(c, .Asterisk, "*"), + else => unreachable, + }; node.* = ast.Node.PrefixOp{ .base = ast.Node{ .id = .PrefixOp }, - .op_token = try appendToken(c, op_tok_id, bytes), + .op_token = op_token, .op = ast.Node.PrefixOp.Op{ - .PtrType = ast.Node.PrefixOp.PtrInfo{ - .allowzero_token = null, - .align_info = null, + .PtrType = .{ .const_token = if (is_const) try appendToken(c, .Keyword_const, "const") else null, .volatile_token = if (is_volatile) try appendToken(c, .Keyword_volatile, "volatile") else null, }, @@ -1224,7 +1237,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour ZigClangQualType_isConstQualified(child_qt), ZigClangQualType_isVolatileQualified(child_qt), .Asterisk, - "*", ); optional_node.rhs = &pointer_node.base; pointer_node.rhs = try transQualType(rp, child_qt, source_loc); @@ -1234,8 +1246,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour rp.c, ZigClangQualType_isConstQualified(child_qt), ZigClangQualType_isVolatileQualified(child_qt), - .BracketStarCBracket, - "[*c]", + .Identifier, ); pointer_node.rhs = try transQualType(rp, child_qt, source_loc); return &pointer_node.base; diff --git a/src-self-hosted/util.zig b/src-self-hosted/util.zig index c1e2393d0f6d6cf464d7839b555456590cec9104..f1d892411f1d6c844c4ff80bad046d3ab1cf326a 100644 --- a/src-self-hosted/util.zig +++ b/src-self-hosted/util.zig @@ -172,9 +172,9 @@ pub fn getDarwinArchString(self: Target) []const u8 { pub fn llvmTargetFromTriple(triple: std.Buffer) !*llvm.Target { var result: *llvm.Target = undefined; - var err_msg: [*]u8 = undefined; - if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) { - std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg); + var err_msg: [*:0]u8 = undefined; + if (llvm.GetTargetFromTriple(triple.toSlice(), &result, &err_msg) != 0) { + std.debug.warn("triple: {s} error: {s}\n", triple.toSlice(), err_msg); return error.UnsupportedTarget; } return result; diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index 5d579a5ef77624f48da69285792bd0113f324970..0458bac12a3a23725b17fc78bcaae89c6873c83f 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -473,7 +473,7 @@ pub const Value = struct { dont_null_terminate, ) orelse return error.OutOfMemory; const str_init_type = llvm.TypeOf(llvm_str_init); - const global = llvm.AddGlobal(ofile.module, str_init_type, c"") orelse return error.OutOfMemory; + const global = llvm.AddGlobal(ofile.module, str_init_type, "") orelse return error.OutOfMemory; llvm.SetInitializer(global, llvm_str_init); llvm.SetLinkage(global, llvm.PrivateLinkage); llvm.SetGlobalConstant(global, 1); diff --git a/src/all_types.hpp b/src/all_types.hpp index c4178cb130e66f29c424378509a6d4d92de8c54e..3b5a067ffcc2bacd17b724de7029ecb3596608c3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -101,6 +101,10 @@ struct IrExecutable { bool is_inline; bool is_generic_instantiation; bool need_err_code_spill; + + // This is a function for use in the debugger to print + // the source location. + void src(); }; enum OutType { @@ -236,9 +240,6 @@ struct ConstPtrValue { struct { ConstExprValue *array_val; size_t elem_index; - // This helps us preserve the null byte when performing compile-time - // concatenation on C strings. - bool is_cstr; } base_array; struct { ConstExprValue *struct_val; @@ -351,6 +352,7 @@ struct LazyValueSliceType { LazyValue base; IrAnalyze *ira; + IrInstruction *sentinel; // can be null IrInstruction *elem_type; IrInstruction *align_inst; // can be null @@ -363,6 +365,7 @@ struct LazyValuePtrType { LazyValue base; IrAnalyze *ira; + IrInstruction *sentinel; // can be null IrInstruction *elem_type; IrInstruction *align_inst; // can be null @@ -598,6 +601,7 @@ enum NodeType { NodeTypeSuspend, NodeTypeAnyFrameType, NodeTypeEnumLiteral, + NodeTypeVarFieldType, }; enum CallingConvention { @@ -818,6 +822,7 @@ struct AstNodePrefixOpExpr { struct AstNodePointerType { Token *star_token; + AstNode *sentinel; AstNode *align_expr; BigInt *bit_offset_start; BigInt *host_int_bytes; @@ -828,11 +833,13 @@ struct AstNodePointerType { }; struct AstNodeInferredArrayType { + AstNode *sentinel; // can be null AstNode *child_type; }; struct AstNodeArrayType { AstNode *size; + AstNode *sentinel; AstNode *child_type; AstNode *align_expr; Token *allow_zero_token; @@ -997,7 +1004,6 @@ struct AstNodeStructField { struct AstNodeStringLiteral { Buf *buf; - bool c; }; struct AstNodeCharLiteral { @@ -1204,6 +1210,11 @@ struct ZigTypePointer { // struct. InferredStructField *inferred_struct_field; + // This can be null. If it is non-null, it means the pointer is terminated by this + // sentinel value. This is most commonly used for C-style strings, with a 0 byte + // to specify the length of the memory pointed to. + ConstExprValue *sentinel; + PtrLen ptr_len; uint32_t explicit_alignment; // 0 means use ABI alignment @@ -1231,6 +1242,7 @@ struct ZigTypeFloat { struct ZigTypeArray { ZigType *child_type; uint64_t len; + ConstExprValue *sentinel; }; struct TypeStructField { @@ -1756,8 +1768,10 @@ struct TypeId { union { struct { + CodeGen *codegen; ZigType *child_type; InferredStructField *inferred_struct_field; + ConstExprValue *sentinel; PtrLen ptr_len; uint32_t alignment; @@ -1770,8 +1784,10 @@ struct TypeId { bool allow_zero; } pointer; struct { + CodeGen *codegen; ZigType *child_type; uint64_t size; + ConstExprValue *sentinel; } array; struct { bool is_signed; @@ -1950,6 +1966,7 @@ struct CodeGen { HashMap external_prototypes; HashMap string_literals_table; HashMap type_info_cache; + HashMap one_possible_values; ZigList resolve_queue; size_t resolve_queue_index; @@ -2026,6 +2043,7 @@ struct CodeGen { IrInstruction *invalid_instruction; IrInstruction *unreach_instruction; + ConstExprValue const_zero_byte; ConstExprValue const_void_val; ConstExprValue panic_msg_vals[PanicMsgIdCount]; @@ -2982,12 +3000,14 @@ struct IrInstructionArrayType { IrInstruction base; IrInstruction *size; + IrInstruction *sentinel; IrInstruction *child_type; }; struct IrInstructionPtrType { IrInstruction base; + IrInstruction *sentinel; IrInstruction *align_value; IrInstruction *child_type; uint32_t bit_offset_start; @@ -3007,6 +3027,7 @@ struct IrInstructionAnyFrameType { struct IrInstructionSliceType { IrInstruction base; + IrInstruction *sentinel; IrInstruction *align_value; IrInstruction *child_type; bool is_const; diff --git a/src/analyze.cpp b/src/analyze.cpp index d8c2d29486b36b8fe75ca3e9e5aec4fb0515d01b..70dfd4f181a111e3853bae033d87330284cf53cb 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -452,18 +452,6 @@ ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type) { return entry; } -static const char *ptr_len_to_star_str(PtrLen ptr_len) { - switch (ptr_len) { - case PtrLenSingle: - return "*"; - case PtrLenUnknown: - return "[*]"; - case PtrLenC: - return "[*c]"; - } - zig_unreachable(); -} - ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { if (fn->frame_type != nullptr) { return fn->frame_type; @@ -483,10 +471,47 @@ ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn) { return entry; } +static void append_ptr_type_attrs(Buf *type_name, ZigType *ptr_type) { + const char *const_str = ptr_type->data.pointer.is_const ? "const " : ""; + const char *volatile_str = ptr_type->data.pointer.is_volatile ? "volatile " : ""; + const char *allow_zero_str; + if (ptr_type->data.pointer.ptr_len == PtrLenC) { + assert(ptr_type->data.pointer.allow_zero); + allow_zero_str = ""; + } else { + allow_zero_str = ptr_type->data.pointer.allow_zero ? "allowzero " : ""; + } + if (ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.host_int_bytes != 0 || + ptr_type->data.pointer.vector_index != VECTOR_INDEX_NONE) + { + buf_appendf(type_name, "align("); + if (ptr_type->data.pointer.explicit_alignment != 0) { + buf_appendf(type_name, "%" PRIu32, ptr_type->data.pointer.explicit_alignment); + } + if (ptr_type->data.pointer.host_int_bytes != 0) { + buf_appendf(type_name, ":%" PRIu32 ":%" PRIu32, ptr_type->data.pointer.bit_offset_in_host, ptr_type->data.pointer.host_int_bytes); + } + if (ptr_type->data.pointer.vector_index == VECTOR_INDEX_RUNTIME) { + buf_appendf(type_name, ":?"); + } 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, "%s%s%s", const_str, volatile_str, allow_zero_str); + if (ptr_type->data.pointer.inferred_struct_field != nullptr) { + buf_appendf(type_name, " field '%s' of %s)", + buf_ptr(ptr_type->data.pointer.inferred_struct_field->field_name), + buf_ptr(&ptr_type->data.pointer.inferred_struct_field->inferred_struct_type->name)); + } else { + buf_appendf(type_name, "%s", buf_ptr(&ptr_type->data.pointer.child_type->name)); + } +} + ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero, - uint32_t vector_index, InferredStructField *inferred_struct_field) + uint32_t vector_index, InferredStructField *inferred_struct_field, ConstExprValue *sentinel) { assert(ptr_len != PtrLenC || allow_zero); assert(!type_is_invalid(child_type)); @@ -509,9 +534,11 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con TypeId type_id = {}; ZigType **parent_pointer = nullptr; if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || - allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr) + allow_zero || vector_index != VECTOR_INDEX_NONE || inferred_struct_field != nullptr || + sentinel != nullptr) { type_id.id = ZigTypeIdPointer; + type_id.data.pointer.codegen = g; type_id.data.pointer.child_type = child_type; type_id.data.pointer.is_const = is_const; type_id.data.pointer.is_volatile = is_volatile; @@ -522,6 +549,7 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con type_id.data.pointer.allow_zero = allow_zero; type_id.data.pointer.vector_index = vector_index; type_id.data.pointer.inferred_struct_field = inferred_struct_field; + type_id.data.pointer.sentinel = sentinel; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) @@ -537,56 +565,35 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con ZigType *entry = new_type_table_entry(ZigTypeIdPointer); - const char *star_str = ptr_len_to_star_str(ptr_len); - const char *const_str = is_const ? "const " : ""; - const char *volatile_str = is_volatile ? "volatile " : ""; - const char *allow_zero_str; - if (ptr_len == PtrLenC) { - assert(allow_zero); - allow_zero_str = ""; - } else { - allow_zero_str = allow_zero ? "allowzero " : ""; - } buf_resize(&entry->name, 0); - if (host_int_bytes == 0 && byte_alignment == 0 && vector_index == VECTOR_INDEX_NONE) { - if (inferred_struct_field == nullptr) { - buf_appendf(&entry->name, "%s%s%s%s%s", - star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); - } else { - buf_appendf(&entry->name, "(%s%s%s%s field '%s' of %s)", - star_str, const_str, volatile_str, allow_zero_str, - buf_ptr(inferred_struct_field->field_name), - buf_ptr(&inferred_struct_field->inferred_struct_type->name)); - } - } else if (host_int_bytes == 0 && vector_index == VECTOR_INDEX_NONE) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, - const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); - } else if (byte_alignment == 0) { - assert(vector_index == VECTOR_INDEX_NONE); - buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", - star_str, - bit_offset_in_host, host_int_bytes, - const_str, volatile_str, allow_zero_str, - buf_ptr(&child_type->name)); - } else if (vector_index == VECTOR_INDEX_NONE) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", - star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, - const_str, volatile_str, allow_zero_str, - buf_ptr(&child_type->name)); - } else if (vector_index == VECTOR_INDEX_RUNTIME) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":?) %s%s%s%s", - star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, - const_str, volatile_str, allow_zero_str, - buf_ptr(&child_type->name)); - } else { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", - star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, vector_index, - const_str, volatile_str, allow_zero_str, - buf_ptr(&child_type->name)); + if (inferred_struct_field != nullptr) { + buf_appendf(&entry->name, "("); } + switch (ptr_len) { + case PtrLenSingle: + buf_appendf(&entry->name, "*"); + break; + case PtrLenUnknown: + buf_appendf(&entry->name, "[*"); + break; + case PtrLenC: + assert(sentinel == nullptr); + buf_appendf(&entry->name, "[*c]"); + break; + } + if (sentinel != nullptr) { + buf_appendf(&entry->name, ":"); + render_const_value(g, &entry->name, sentinel); + } + switch (ptr_len) { + case PtrLenSingle: + case PtrLenC: + break; + case PtrLenUnknown: + buf_appendf(&entry->name, "]"); + break; + } + if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { if (type_has_bits(child_type)) { @@ -615,6 +622,9 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con entry->data.pointer.allow_zero = allow_zero; entry->data.pointer.vector_index = vector_index; entry->data.pointer.inferred_struct_field = inferred_struct_field; + entry->data.pointer.sentinel = sentinel; + + append_ptr_type_attrs(&entry->name, entry); if (parent_pointer) { *parent_pointer = entry; @@ -629,12 +639,12 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons uint32_t bit_offset_in_host, uint32_t host_int_bytes, bool allow_zero) { return get_pointer_to_type_extra2(g, child_type, is_const, is_volatile, ptr_len, - byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr); + byte_alignment, bit_offset_in_host, host_int_bytes, allow_zero, VECTOR_INDEX_NONE, nullptr, nullptr); } ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const) { return get_pointer_to_type_extra2(g, child_type, is_const, false, PtrLenSingle, 0, 0, 0, false, - VECTOR_INDEX_NONE, nullptr); + VECTOR_INDEX_NONE, nullptr, nullptr); } ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { @@ -750,11 +760,13 @@ ZigType *get_error_union_type(CodeGen *g, ZigType *err_set_type, ZigType *payloa return entry; } -ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) { +ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ConstExprValue *sentinel) { TypeId type_id = {}; type_id.id = ZigTypeIdArray; + type_id.data.array.codegen = g; type_id.data.array.child_type = child_type; type_id.data.array.size = array_size; + type_id.data.array.sentinel = sentinel; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) { return existing_entry->value; @@ -765,14 +777,27 @@ ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size) { ZigType *entry = new_type_table_entry(ZigTypeIdArray); buf_resize(&entry->name, 0); - buf_appendf(&entry->name, "[%" ZIG_PRI_u64 "]%s", array_size, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "[%" ZIG_PRI_u64, array_size); + if (sentinel != nullptr) { + buf_appendf(&entry->name, ":"); + render_const_value(g, &entry->name, sentinel); + } + buf_appendf(&entry->name, "]%s", buf_ptr(&child_type->name)); - entry->size_in_bits = child_type->size_in_bits * array_size; + size_t full_array_size; + if (array_size == 0) { + full_array_size = 0; + } else { + full_array_size = array_size + ((sentinel != nullptr) ? 1 : 0); + } + + entry->size_in_bits = child_type->size_in_bits * full_array_size; entry->abi_align = child_type->abi_align; - entry->abi_size = child_type->abi_size * array_size; + entry->abi_size = child_type->abi_size * full_array_size; entry->data.array.child_type = child_type; entry->data.array.len = array_size; + entry->data.array.sentinel = sentinel; g->type_table.put(type_id, entry); return entry; @@ -789,10 +814,14 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *entry = new_type_table_entry(ZigTypeIdStruct); - // replace the & with [] to go from a ptr type name to a slice type name buf_resize(&entry->name, 0); - size_t name_offset = (ptr_type->data.pointer.ptr_len == PtrLenSingle) ? 1 : 3; - buf_appendf(&entry->name, "[]%s", buf_ptr(&ptr_type->name) + name_offset); + buf_appendf(&entry->name, "["); + if (ptr_type->data.pointer.sentinel != nullptr) { + buf_appendf(&entry->name, ":"); + render_const_value(g, &entry->name, ptr_type->data.pointer.sentinel); + } + buf_appendf(&entry->name, "]"); + append_ptr_type_attrs(&entry->name, ptr_type); unsigned element_count = 2; Buf *ptr_field_name = buf_create_from_str("ptr"); @@ -832,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; @@ -1150,6 +1163,10 @@ Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType * Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) { if (type_val->special != ConstValSpecialLazy) { assert(type_val->special == ConstValSpecialStatic); + if (type_val->data.x_type == g->builtin_types.entry_var) { + *is_opaque_type = false; + return ErrorNone; + } *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque); return ErrorNone; } @@ -3638,6 +3655,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeEnumLiteral: case NodeTypeAnyFrameType: case NodeTypeErrorSetField: + case NodeTypeVarFieldType: zig_unreachable(); } } @@ -5041,7 +5059,6 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { hash_val += (uint32_t)1764906839; hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); - hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492; return hash_val; case ConstPtrSpecialBaseStruct: hash_val += (uint32_t)3518317043; @@ -5545,8 +5562,23 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { zig_unreachable(); } +ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry) { + auto entry = g->one_possible_values.maybe_get(type_entry); + if (entry != nullptr) { + return entry->value; + } + ConstExprValue *result = create_const_vals(1); + result->type = type_entry; + result->special = ConstValSpecialStatic; + g->one_possible_values.put(type_entry, result); + return result; +} + ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { Error err; + if (ty == g->builtin_types.entry_var) { + return ReqCompTimeYes; + } switch (ty->id) { case ZigTypeIdInvalid: zig_unreachable(); @@ -5612,52 +5644,26 @@ void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { return; } - const_val->special = ConstValSpecialStatic; - const_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str)); - const_val->data.x_array.special = ConstArraySpecialBuf; - const_val->data.x_array.data.s_buf = str; - - g->string_literals_table.put(str, const_val); -} - -ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) { - ConstExprValue *const_val = create_const_vals(1); - init_const_str_lit(g, const_val, str); - return const_val; -} - -void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { // first we build the underlying array - size_t len_with_null = buf_len(str) + 1; ConstExprValue *array_val = create_const_vals(1); array_val->special = ConstValSpecialStatic; - array_val->type = get_array_type(g, g->builtin_types.entry_u8, len_with_null); - // TODO buf optimization - array_val->data.x_array.data.s_none.elements = create_const_vals(len_with_null); - for (size_t i = 0; i < buf_len(str); i += 1) { - ConstExprValue *this_char = &array_val->data.x_array.data.s_none.elements[i]; - this_char->special = ConstValSpecialStatic; - this_char->type = g->builtin_types.entry_u8; - bigint_init_unsigned(&this_char->data.x_bigint, (uint8_t)buf_ptr(str)[i]); - } - ConstExprValue *null_char = &array_val->data.x_array.data.s_none.elements[len_with_null - 1]; - null_char->special = ConstValSpecialStatic; - null_char->type = g->builtin_types.entry_u8; - bigint_init_unsigned(&null_char->data.x_bigint, 0); + array_val->type = get_array_type(g, g->builtin_types.entry_u8, buf_len(str), &g->const_zero_byte); + array_val->data.x_array.special = ConstArraySpecialBuf; + array_val->data.x_array.data.s_buf = str; // then make the pointer point to it const_val->special = ConstValSpecialStatic; - // TODO make this `[*]null u8` instead of `[*]u8` - const_val->type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, 0, 0, 0, false); - const_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - const_val->data.x_ptr.data.base_array.array_val = array_val; - const_val->data.x_ptr.data.base_array.elem_index = 0; - const_val->data.x_ptr.data.base_array.is_cstr = true; + const_val->type = get_pointer_to_type_extra2(g, array_val->type, true, false, + PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr); + const_val->data.x_ptr.special = ConstPtrSpecialRef; + const_val->data.x_ptr.data.ref.pointee = array_val; + + g->string_literals_table.put(str, const_val); } -ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) { + +ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str) { ConstExprValue *const_val = create_const_vals(1); - init_const_c_str_lit(g, const_val, str); + init_const_str_lit(g, const_val, str); return const_val; } @@ -5707,6 +5713,18 @@ ConstExprValue *create_const_signed(ZigType *type, int64_t x) { return const_val; } +void init_const_null(ConstExprValue *const_val, ZigType *type) { + const_val->special = ConstValSpecialStatic; + const_val->type = type; + const_val->data.x_optional = nullptr; +} + +ConstExprValue *create_const_null(ZigType *type) { + ConstExprValue *const_val = create_const_vals(1); + init_const_null(const_val, type); + return const_val; +} + void init_const_float(ConstExprValue *const_val, ZigType *type, double value) { const_val->special = ConstValSpecialStatic; const_val->type = type; @@ -6069,7 +6087,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { fields.append({"@stack_trace", get_stack_trace_type(g), 0}); fields.append({"@instruction_addresses", - get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0}); + get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0}); } frame_type->data.frame.locals_struct = get_struct_type(g, buf_ptr(&frame_type->name), @@ -6277,7 +6295,7 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { if (codegen_fn_has_err_ret_tracing_stack(g, fn, true)) { fields.append({"@stack_trace", get_stack_trace_type(g), 0}); fields.append({"@instruction_addresses", - get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count), 0}); + get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr), 0}); } for (size_t alloca_i = 0; alloca_i < fn->alloca_gen_list.length; alloca_i += 1) { @@ -6441,8 +6459,6 @@ bool ir_get_var_is_comptime(ZigVar *var) { bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { if (a->data.x_ptr.special != b->data.x_ptr.special) return false; - if (a->data.x_ptr.mut != b->data.x_ptr.mut) - return false; switch (a->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); @@ -6459,8 +6475,6 @@ bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { } if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) return false; - if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr) - return false; return true; case ConstPtrSpecialBaseStruct: if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val && @@ -6536,9 +6550,19 @@ static bool const_values_equal_array(CodeGen *g, ConstExprValue *a, ConstExprVal } bool const_values_equal(CodeGen *g, ConstExprValue *a, ConstExprValue *b) { - assert(a->type->id == b->type->id); + if (a->type->id != b->type->id) return false; assert(a->special == ConstValSpecialStatic); assert(b->special == ConstValSpecialStatic); + if (a->type == b->type) { + switch (type_has_one_possible_value(g, a->type)) { + case OnePossibleValueInvalid: + zig_unreachable(); + case OnePossibleValueNo: + break; + case OnePossibleValueYes: + return true; + } + } switch (a->type->id) { case ZigTypeIdOpaque: zig_unreachable(); @@ -6704,15 +6728,10 @@ static void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); return; case ConstPtrSpecialBaseArray: - if (const_val->data.x_ptr.data.base_array.is_cstr) { - buf_appendf(buf, "*(c str lit)"); - return; - } else { - buf_appendf(buf, "*"); - // TODO we need a source node for const_ptr_pointee because it can generate compile errors - render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); - return; - } + buf_appendf(buf, "*"); + // TODO we need a source node for const_ptr_pointee because it can generate compile errors + render_const_value(g, buf, const_ptr_pointee(nullptr, g, const_val, nullptr)); + return; case ConstPtrSpecialHardCodedAddr: buf_appendf(buf, "(%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->name), const_val->data.x_ptr.data.hard_coded_addr.addr); @@ -7032,17 +7051,19 @@ uint32_t type_id_hash(TypeId x) { return hash_ptr(x.data.error_union.err_set_type) ^ hash_ptr(x.data.error_union.payload_type); case ZigTypeIdPointer: return hash_ptr(x.data.pointer.child_type) + - ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) + + (uint32_t)x.data.pointer.ptr_len * 1120226602u + (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) + (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) + (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.vector_index) ^ (uint32_t)0x19199716) + - (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); + (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881) * + (x.data.pointer.sentinel ? hash_const_val(x.data.pointer.sentinel) : (uint32_t)2955491856); case ZigTypeIdArray: - return hash_ptr(x.data.array.child_type) + - ((uint32_t)x.data.array.size ^ (uint32_t)2122979968); + return hash_ptr(x.data.array.child_type) * + ((uint32_t)x.data.array.size ^ (uint32_t)2122979968) * + (x.data.array.sentinel ? hash_const_val(x.data.array.sentinel) : (uint32_t)1927201585); case ZigTypeIdInt: return (x.data.integer.is_signed ? (uint32_t)2652528194 : (uint32_t)163929201) + (((uint32_t)x.data.integer.bit_count) ^ (uint32_t)2998081557); @@ -7093,6 +7114,11 @@ bool type_id_eql(TypeId a, TypeId b) { a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.vector_index == b.data.pointer.vector_index && a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes && + ( + a.data.pointer.sentinel == b.data.pointer.sentinel || + (a.data.pointer.sentinel != nullptr && b.data.pointer.sentinel != nullptr && + const_values_equal(a.data.pointer.codegen, a.data.pointer.sentinel, b.data.pointer.sentinel)) + ) && ( a.data.pointer.inferred_struct_field == b.data.pointer.inferred_struct_field || (a.data.pointer.inferred_struct_field != nullptr && @@ -7104,7 +7130,12 @@ bool type_id_eql(TypeId a, TypeId b) { ); case ZigTypeIdArray: return a.data.array.child_type == b.data.array.child_type && - a.data.array.size == b.data.array.size; + a.data.array.size == b.data.array.size && + ( + a.data.array.sentinel == b.data.array.sentinel || + (a.data.array.sentinel != nullptr && b.data.array.sentinel != nullptr && + const_values_equal(a.data.array.codegen, a.data.array.sentinel, b.data.array.sentinel)) + ); case ZigTypeIdInt: return a.data.integer.is_signed == b.data.integer.is_signed && a.data.integer.bit_count == b.data.integer.bit_count; @@ -7761,7 +7792,8 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa bool done = false; 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) + ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero || + ptr_type->data.pointer.sentinel != nullptr) { ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenUnknown, 0, 0, 0, false); @@ -7780,7 +7812,8 @@ static void resolve_llvm_types_slice(CodeGen *g, ZigType *type, ResolveStatus wa ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index]->type_entry; assert(child_ptr_type->id == ZigTypeIdPointer); if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero) + child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero || + child_ptr_type->data.pointer.sentinel != nullptr) { ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, @@ -8290,7 +8323,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; if (padding_bytes > 0) { ZigType *u8_type = get_int_type(g, false, 8); - ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); + ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr); LLVMTypeRef union_element_types[] = { most_aligned_union_member->type_entry->llvm_type, get_llvm_type(g, padding_array), @@ -8324,7 +8357,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry); } else { ZigType *u8_type = get_int_type(g, false, 8); - ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); + ZigType *padding_array = get_array_type(g, u8_type, padding_bytes, nullptr); LLVMTypeRef union_element_types[] = { get_llvm_type(g, most_aligned_union_member->type_entry), get_llvm_type(g, padding_array), @@ -8405,19 +8438,19 @@ static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus if (type->data.pointer.is_const || type->data.pointer.is_volatile || type->data.pointer.explicit_alignment != 0 || type->data.pointer.ptr_len != PtrLenSingle || type->data.pointer.bit_offset_in_host != 0 || type->data.pointer.allow_zero || - type->data.pointer.vector_index != VECTOR_INDEX_NONE) + type->data.pointer.vector_index != VECTOR_INDEX_NONE || type->data.pointer.sentinel != nullptr) { assertNoError(type_resolve(g, elem_type, ResolveStatusLLVMFwdDecl)); ZigType *peer_type; if (type->data.pointer.vector_index == VECTOR_INDEX_NONE) { peer_type = get_pointer_to_type_extra2(g, elem_type, false, false, PtrLenSingle, 0, 0, type->data.pointer.host_int_bytes, false, - VECTOR_INDEX_NONE, nullptr); + VECTOR_INDEX_NONE, nullptr, nullptr); } else { uint32_t host_vec_len = type->data.pointer.host_int_bytes; ZigType *host_vec_type = get_vector_type(g, host_vec_len, elem_type); peer_type = get_pointer_to_type_extra2(g, host_vec_type, false, false, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr); + PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, nullptr); } type->llvm_type = get_llvm_type(g, peer_type); type->llvm_di_type = get_llvm_di_type(g, peer_type); @@ -8646,14 +8679,16 @@ static void resolve_llvm_types_array(CodeGen *g, ZigType *type) { ZigType *elem_type = type->data.array.child_type; + uint64_t extra_len_from_sentinel = (type->data.array.sentinel != nullptr) ? 1 : 0; + uint64_t full_len = type->data.array.len + extra_len_from_sentinel; // TODO https://github.com/ziglang/zig/issues/1424 - type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)type->data.array.len); + type->llvm_type = LLVMArrayType(get_llvm_type(g, elem_type), (unsigned)full_len); uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, type->llvm_type); uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, type->llvm_type); type->llvm_di_type = ZigLLVMCreateDebugArrayType(g->dbuilder, debug_size_in_bits, - debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)type->data.array.len); + debug_align_in_bits, get_llvm_di_type(g, elem_type), (int)full_len); } static void resolve_llvm_types_fn_type(CodeGen *g, ZigType *fn_type) { @@ -9143,3 +9178,11 @@ Error analyze_import(CodeGen *g, ZigType *source_import, Buf *import_target_str, *out_import = add_source_file(g, target_package, resolved_path, import_code, source_kind); return ErrorNone; } + + +void IrExecutable::src() { + IrExecutable *it; + for (it = this; it != nullptr && it->source_node != nullptr; it = it->parent_exec) { + it->source_node->src(); + } +} diff --git a/src/analyze.hpp b/src/analyze.hpp index ddfb31c286f52381933ce7767cfd1eeac2bc702e..fcf993eac44cd3080e469d1b3fe4e0ebd017940f 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -24,7 +24,8 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset, uint32_t unaligned_bit_count, - bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field); + bool allow_zero, uint32_t vector_index, InferredStructField *inferred_struct_field, + ConstExprValue *sentinel); uint64_t type_size(CodeGen *g, ZigType *type_entry); uint64_t type_size_bits(CodeGen *g, ZigType *type_entry); ZigType *get_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); @@ -33,7 +34,7 @@ ZigType **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type); ZigType *get_c_int_type(CodeGen *g, CIntType c_int_type); ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); ZigType *get_optional_type(CodeGen *g, ZigType *child_type); -ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size); +ZigType *get_array_type(CodeGen *g, ZigType *child_type, uint64_t array_size, ConstExprValue *sentinel); ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type); ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, AstNode *decl_node, const char *full_name, Buf *bare_name, ContainerLayout layout); @@ -126,9 +127,6 @@ ScopeExpr *create_expr_scope(CodeGen *g, AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); -void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str); -ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str); - void init_const_bigint(ConstExprValue *const_val, ZigType *type, const BigInt *bigint); ConstExprValue *create_const_bigint(ZigType *type, const BigInt *bigint); @@ -176,6 +174,9 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end); ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); +void init_const_null(ConstExprValue *const_val, ZigType *type); +ConstExprValue *create_const_null(ZigType *type); + ConstExprValue *create_const_vals(size_t count); ConstExprValue **alloc_const_vals_ptrs(size_t count); ConstExprValue **realloc_const_vals_ptrs(ConstExprValue **ptr, size_t old_count, size_t new_count); @@ -275,5 +276,5 @@ IrInstruction *ir_create_alloca(CodeGen *g, Scope *scope, AstNode *source_node, ZigType *var_type, const char *name_hint); Error analyze_import(CodeGen *codegen, ZigType *source_import, Buf *import_target_str, ZigType **out_import, Buf **out_import_target_path, Buf *out_full_path); - +ConstExprValue *get_the_one_possible_value(CodeGen *g, ZigType *type_entry); #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 34cbed245a193dc4f67433195b31b5a3c50971f6..531fcf18522629f6d8d304f623a1b9d345cf6b91 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -147,9 +147,9 @@ static const char *token_to_ptr_len_str(Token *tok) { case TokenIdStar: case TokenIdStarStar: return "*"; - case TokenIdBracketStarBracket: + case TokenIdLBracket: return "[*]"; - case TokenIdBracketStarCBracket: + case TokenIdSymbol: return "[*c]"; default: zig_unreachable(); @@ -268,6 +268,8 @@ static const char *node_type_str(NodeType node_type) { return "EnumLiteral"; case NodeTypeErrorSetField: return "ErrorSetField"; + case NodeTypeVarFieldType: + return "VarFieldType"; } zig_unreachable(); } @@ -619,9 +621,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { break; case NodeTypeStringLiteral: { - if (node->data.string_literal.c) { - fprintf(ar->f, "c"); - } Buf tmp_buf = BUF_INIT; string_literal_escape(node->data.string_literal.buf, &tmp_buf); fprintf(ar->f, "\"%s\"", buf_ptr(&tmp_buf)); @@ -1187,6 +1186,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str)); break; } + case NodeTypeVarFieldType: { + fprintf(ar->f, "var"); + break; + } case NodeTypeParamDecl: case NodeTypeTestDecl: case NodeTypeStructField: diff --git a/src/codegen.cpp b/src/codegen.cpp index f90777c9831211c63159f808e74cd4ee1a0ce06e..6f68bad322ab57b872deec1f7b1ec03f48aefe18 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -949,7 +949,7 @@ static LLVMValueRef get_panic_msg_ptr_val(CodeGen *g, PanicMsgId msg_id) { if (!val->global_refs->llvm_global) { Buf *buf_msg = panic_msg_buf(msg_id); - ConstExprValue *array_val = create_const_str_lit(g, buf_msg); + ConstExprValue *array_val = create_const_str_lit(g, buf_msg)->data.x_ptr.data.ref.pointee; init_const_slice(g, val, array_val, 0, buf_len(buf_msg), true); render_const_val(g, val, ""); @@ -2784,14 +2784,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, IrInstruction *op1 = bin_op_instruction->op1; IrInstruction *op2 = bin_op_instruction->op2; - assert(op1->value.type == op2->value.type || op_id == IrBinOpBitShiftLeftLossy || - op_id == IrBinOpBitShiftLeftExact || op_id == IrBinOpBitShiftRightLossy || - op_id == IrBinOpBitShiftRightExact || - (op1->value.type->id == ZigTypeIdErrorSet && op2->value.type->id == ZigTypeIdErrorSet) || - (op1->value.type->id == ZigTypeIdPointer && - (op_id == IrBinOpAdd || op_id == IrBinOpSub) && - op1->value.type->data.pointer.ptr_len != PtrLenSingle) - ); ZigType *operand_type = op1->value.type; ZigType *scalar_type = (operand_type->id == ZigTypeIdVector) ? operand_type->data.vector.elem_type : operand_type; @@ -2848,7 +2840,6 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, AddSubMulMul; if (scalar_type->id == ZigTypeIdPointer) { - assert(scalar_type->data.pointer.ptr_len != PtrLenSingle); LLVMValueRef subscript_value; if (operand_type->id == ZigTypeIdVector) zig_panic("TODO: Implement vector operations on pointers."); @@ -3077,7 +3068,14 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, case CastOpNumLitToConcrete: zig_unreachable(); case CastOpNoop: - return expr_val; + if (actual_type->id == ZigTypeIdPointer && wanted_type->id == ZigTypeIdPointer && + actual_type->data.pointer.child_type->id == ZigTypeIdArray && + wanted_type->data.pointer.child_type->id == ZigTypeIdArray) + { + return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); + } else { + return expr_val; + } case CastOpIntToFloat: assert(actual_type->id == ZigTypeIdInt); if (actual_type->data.integral.is_signed) { @@ -3709,8 +3707,9 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI array_type = array_type->data.pointer.child_type; } if (safety_check_on) { - LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - array_type->data.array.len, false); + uint64_t extra_len_from_sentinel = (array_type->data.array.sentinel != nullptr) ? 1 : 0; + uint64_t full_len = array_type->data.array.len + extra_len_from_sentinel; + LLVMValueRef end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, full_len, false); add_bounds_check(g, subscript_value, LLVMIntEQ, nullptr, LLVMIntULT, end); } if (array_ptr_type->data.pointer.host_int_bytes != 0) { @@ -3753,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); @@ -3770,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; @@ -6637,11 +6637,20 @@ static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, con ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; assert(array_const_val->type->id == ZigTypeIdArray); if (!type_has_bits(array_const_val->type)) { - // make this a null pointer - ZigType *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), - get_llvm_type(g, const_val->type)); - return const_val->global_refs->llvm_value; + if (array_const_val->type->data.array.sentinel != nullptr) { + ConstExprValue *pointee = array_const_val->type->data.array.sentinel; + render_const_val(g, pointee, ""); + render_const_val_global(g, pointee, ""); + const_val->global_refs->llvm_value = LLVMConstBitCast(pointee->global_refs->llvm_global, + get_llvm_type(g, const_val->type)); + return const_val->global_refs->llvm_value; + } else { + // make this a null pointer + ZigType *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->llvm_type), + get_llvm_type(g, const_val->type)); + return const_val->global_refs->llvm_value; + } } size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, elem_index); @@ -6955,7 +6964,9 @@ check: switch (const_val->special) { case ConstArraySpecialUndef: return LLVMGetUndef(get_llvm_type(g, type_entry)); case ConstArraySpecialNone: { - LLVMValueRef *values = allocate(len); + uint64_t extra_len_from_sentinel = (type_entry->data.array.sentinel != nullptr) ? 1 : 0; + uint64_t full_len = len + extra_len_from_sentinel; + LLVMValueRef *values = allocate(full_len); LLVMTypeRef element_type_ref = get_llvm_type(g, type_entry->data.array.child_type); bool make_unnamed_struct = false; for (uint64_t i = 0; i < len; i += 1) { @@ -6964,15 +6975,19 @@ check: switch (const_val->special) { values[i] = val; make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(g, elem_value->type, val); } + if (type_entry->data.array.sentinel != nullptr) { + values[len] = gen_const_val(g, type_entry->data.array.sentinel, ""); + } if (make_unnamed_struct) { - return LLVMConstStruct(values, len, true); + return LLVMConstStruct(values, full_len, true); } else { - return LLVMConstArray(element_type_ref, values, (unsigned)len); + return LLVMConstArray(element_type_ref, values, (unsigned)full_len); } } case ConstArraySpecialBuf: { Buf *buf = const_val->data.x_array.data.s_buf; - return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), true); + return LLVMConstString(buf_ptr(buf), (unsigned)buf_len(buf), + type_entry->data.array.sentinel == nullptr); } } zig_unreachable(); @@ -7465,7 +7480,7 @@ static void do_code_gen(CodeGen *g) { !is_async && !have_err_ret_trace_arg; LLVMValueRef err_ret_array_val = nullptr; if (have_err_ret_trace_stack) { - ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count); + ZigType *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count, nullptr); err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type)); (void)get_llvm_type(g, get_stack_trace_type(g)); @@ -8628,6 +8643,11 @@ static void init(CodeGen *g) { g->const_void_val.type = g->builtin_types.entry_void; g->const_void_val.global_refs = allocate(1); + g->const_zero_byte.special = ConstValSpecialStatic; + g->const_zero_byte.type = g->builtin_types.entry_u8; + g->const_zero_byte.global_refs = allocate(1); + bigint_init_unsigned(&g->const_zero_byte.data.x_bigint, 0); + { ConstGlobalRefs *global_refs = allocate(PanicMsgIdCount); for (size_t i = 0; i < PanicMsgIdCount; i += 1) { @@ -9067,7 +9087,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { zig_unreachable(); ConstExprValue *test_fn_array = create_const_vals(1); - test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length); + test_fn_array->type = get_array_type(g, struct_type, g->test_fns.length, nullptr); test_fn_array->special = ConstValSpecialStatic; test_fn_array->data.x_array.data.s_none.elements = create_const_vals(g->test_fns.length); @@ -9092,7 +9112,7 @@ static void create_test_compile_var_and_add_test_runner(CodeGen *g) { this_val->data.x_struct.fields = alloc_const_vals_ptrs(2); ConstExprValue *name_field = this_val->data.x_struct.fields[0]; - ConstExprValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name); + ConstExprValue *name_array_val = create_const_str_lit(g, &test_fn_entry->symbol_name)->data.x_ptr.data.ref.pointee; init_const_slice(g, name_field, name_array_val, 0, buf_len(&test_fn_entry->symbol_name), true); ConstExprValue *fn_field = this_val->data.x_struct.fields[1]; @@ -10415,6 +10435,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->external_prototypes.init(8); g->string_literals_table.init(16); g->type_info_cache.init(32); + g->one_possible_values.init(32); g->is_test_build = is_test_build; g->is_single_threaded = false; buf_resize(&g->global_asm, 0); diff --git a/src/ir.cpp b/src/ir.cpp index 9f0fc40dedaba54eb00c0ddce2440e9527b7932f..017f6b489f340186da0d86e84aceae38fa02d6bf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -66,6 +66,11 @@ enum ConstCastResultId { ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, ConstCastResultIdBadAllowsZero, + ConstCastResultIdArrayChild, + ConstCastResultIdSentinelArrays, + ConstCastResultIdPtrLens, + ConstCastResultIdCV, + ConstCastResultIdPtrSentinel, }; struct ConstCastOnly; @@ -87,7 +92,11 @@ struct ConstCastErrUnionErrSetMismatch; struct ConstCastErrUnionPayloadMismatch; struct ConstCastErrSetMismatch; struct ConstCastTypeMismatch; +struct ConstCastArrayMismatch; struct ConstCastBadAllowsZero; +struct ConstCastBadNullTermArrays; +struct ConstCastBadCV; +struct ConstCastPtrSentinel; struct ConstCastOnly { ConstCastResultId id; @@ -99,11 +108,15 @@ struct ConstCastOnly { ConstCastErrUnionPayloadMismatch *error_union_payload; ConstCastErrUnionErrSetMismatch *error_union_error_set; ConstCastTypeMismatch *type_mismatch; + ConstCastArrayMismatch *array_mismatch; ConstCastOnly *return_type; ConstCastOnly *null_wrap_ptr_child; ConstCastArg fn_arg; ConstCastArgNoAlias arg_no_alias; ConstCastBadAllowsZero *bad_allows_zero; + ConstCastBadNullTermArrays *sentinel_arrays; + ConstCastBadCV *bad_cv; + ConstCastPtrSentinel *bad_ptr_sentinel; } data; }; @@ -130,6 +143,12 @@ struct ConstCastSliceMismatch { ZigType *actual_child; }; +struct ConstCastArrayMismatch { + ConstCastOnly child; + ZigType *wanted_child; + ZigType *actual_child; +}; + struct ConstCastErrUnionErrSetMismatch { ConstCastOnly child; ZigType *wanted_err_set; @@ -151,11 +170,28 @@ struct ConstCastBadAllowsZero { ZigType *actual_type; }; +struct ConstCastBadNullTermArrays { + ConstCastOnly child; + ZigType *wanted_type; + ZigType *actual_type; +}; + +struct ConstCastBadCV { + ZigType *wanted_type; + ZigType *actual_type; +}; + +struct ConstCastPtrSentinel { + ZigType *wanted_type; + ZigType *actual_type; +}; static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type); +static IrInstruction *ir_implicit_cast2(IrAnalyze *ira, IrInstruction *value_source_instr, + IrInstruction *value, ZigType *expected_type); static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, ResultLoc *result_loc); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); @@ -217,10 +253,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c case OnePossibleValueInvalid: zig_unreachable(); case OnePossibleValueYes: - result = create_const_vals(1); - result->type = const_val->type->data.pointer.child_type; - result->special = ConstValSpecialStatic; - return result; + return get_the_one_possible_value(g, const_val->type->data.pointer.child_type); case OnePossibleValueNo: break; } @@ -233,8 +266,12 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c break; case ConstPtrSpecialBaseArray: { ConstExprValue *array_val = const_val->data.x_ptr.data.base_array.array_val; - expand_undef_array(g, array_val); - result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; + if (const_val->data.x_ptr.data.base_array.elem_index == array_val->type->data.array.len) { + result = array_val->type->data.array.sentinel; + } else { + expand_undef_array(g, array_val); + result = &array_val->data.x_array.data.s_none.elements[const_val->data.x_ptr.data.base_array.elem_index]; + } break; } case ConstPtrSpecialBaseStruct: { @@ -282,20 +319,20 @@ static bool slice_is_const(ZigType *type) { // This function returns true when you can change the type of a ConstExprValue and the // value remains meaningful. -static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { - if (a == b) +static bool types_have_same_zig_comptime_repr(CodeGen *codegen, ZigType *expected, ZigType *actual) { + if (expected == actual) return true; - if (get_codegen_ptr_type(a) != nullptr && get_codegen_ptr_type(b) != nullptr) + if (get_codegen_ptr_type(expected) != nullptr && get_codegen_ptr_type(actual) != nullptr) return true; - if (is_opt_err_set(a) && is_opt_err_set(b)) + if (is_opt_err_set(expected) && is_opt_err_set(actual)) return true; - if (a->id != b->id) + if (expected->id != actual->id) return false; - switch (a->id) { + switch (expected->id) { case ZigTypeIdInvalid: case ZigTypeIdUnreachable: zig_unreachable(); @@ -314,12 +351,11 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { case ZigTypeIdAnyFrame: return true; case ZigTypeIdFloat: - return a->data.floating.bit_count == b->data.floating.bit_count; + return expected->data.floating.bit_count == actual->data.floating.bit_count; case ZigTypeIdInt: - return a->data.integral.is_signed == b->data.integral.is_signed; + return expected->data.integral.is_signed == actual->data.integral.is_signed; case ZigTypeIdStruct: - return is_slice(a) && is_slice(b); - case ZigTypeIdArray: + return is_slice(expected) && is_slice(actual); case ZigTypeIdOptional: case ZigTypeIdErrorUnion: case ZigTypeIdEnum: @@ -329,6 +365,11 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { case ZigTypeIdVector: case ZigTypeIdFnFrame: return false; + case ZigTypeIdArray: + return expected->data.array.len == actual->data.array.len && + expected->data.array.child_type == actual->data.array.child_type && + (expected->data.array.sentinel == nullptr || (actual->data.array.sentinel != nullptr && + const_values_equal(codegen, expected->data.array.sentinel, actual->data.array.sentinel))); } zig_unreachable(); } @@ -1299,12 +1340,6 @@ static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, Scope *scope, AstNo return instruction; } -static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) { - IrInstructionConst *const_instruction = ir_build_instruction(irb, scope, source_node); - init_const_c_str_lit(irb->codegen, &const_instruction->base.value, str); - return &const_instruction->base; -} - static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id, IrInstruction *op1, IrInstruction *op2, bool safety_check_on) { @@ -1544,9 +1579,11 @@ static IrInstruction *ir_build_br(IrBuilder *irb, Scope *scope, AstNode *source_ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *child_type, bool is_const, bool is_volatile, PtrLen ptr_len, - IrInstruction *align_value, uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero) + IrInstruction *sentinel, IrInstruction *align_value, + uint32_t bit_offset_start, uint32_t host_int_bytes, bool is_allow_zero) { IrInstructionPtrType *ptr_type_of_instruction = ir_build_instruction(irb, scope, source_node); + ptr_type_of_instruction->sentinel = sentinel; ptr_type_of_instruction->align_value = align_value; ptr_type_of_instruction->child_type = child_type; ptr_type_of_instruction->is_const = is_const; @@ -1556,6 +1593,7 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s ptr_type_of_instruction->host_int_bytes = host_int_bytes; ptr_type_of_instruction->is_allow_zero = is_allow_zero; + if (sentinel) ir_ref_instruction(sentinel, irb->current_basic_block); if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); ir_ref_instruction(child_type, irb->current_basic_block); @@ -1772,13 +1810,15 @@ static IrInstruction *ir_build_set_float_mode(IrBuilder *irb, Scope *scope, AstN } static IrInstruction *ir_build_array_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *size, - IrInstruction *child_type) + IrInstruction *sentinel, IrInstruction *child_type) { IrInstructionArrayType *instruction = ir_build_instruction(irb, scope, source_node); instruction->size = size; + instruction->sentinel = sentinel; instruction->child_type = child_type; ir_ref_instruction(size, irb->current_basic_block); + if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block); ir_ref_instruction(child_type, irb->current_basic_block); return &instruction->base; @@ -1794,18 +1834,22 @@ static IrInstruction *ir_build_anyframe_type(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } + static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *child_type, bool is_const, bool is_volatile, IrInstruction *align_value, bool is_allow_zero) + IrInstruction *child_type, bool is_const, bool is_volatile, + IrInstruction *sentinel, IrInstruction *align_value, bool is_allow_zero) { IrInstructionSliceType *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_const = is_const; instruction->is_volatile = is_volatile; instruction->child_type = child_type; + instruction->sentinel = sentinel; instruction->align_value = align_value; instruction->is_allow_zero = is_allow_zero; + if (sentinel != nullptr) ir_ref_instruction(sentinel, irb->current_basic_block); + if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); ir_ref_instruction(child_type, irb->current_basic_block); - if (align_value) ir_ref_instruction(align_value, irb->current_basic_block); return &instruction->base; } @@ -6032,9 +6076,9 @@ static PtrLen star_token_to_ptr_len(TokenId token_id) { case TokenIdStar: case TokenIdStarStar: return PtrLenSingle; - case TokenIdBracketStarBracket: + case TokenIdLBracket: return PtrLenUnknown; - case TokenIdBracketStarCBracket: + case TokenIdSymbol: return PtrLenC; default: zig_unreachable(); @@ -6043,13 +6087,25 @@ static PtrLen star_token_to_ptr_len(TokenId token_id) { static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypePointerType); + PtrLen ptr_len = star_token_to_ptr_len(node->data.pointer_type.star_token->id); + bool is_const = node->data.pointer_type.is_const; bool is_volatile = node->data.pointer_type.is_volatile; bool is_allow_zero = node->data.pointer_type.allow_zero_token != nullptr; + AstNode *sentinel_expr = node->data.pointer_type.sentinel; AstNode *expr_node = node->data.pointer_type.op_expr; AstNode *align_expr = node->data.pointer_type.align_expr; + IrInstruction *sentinel; + if (sentinel_expr != nullptr) { + sentinel = ir_gen_node(irb, sentinel_expr, scope); + if (sentinel == irb->codegen->invalid_instruction) + return sentinel; + } else { + sentinel = nullptr; + } + IrInstruction *align_value; if (align_expr != nullptr) { align_value = ir_gen_node(irb, align_expr, scope); @@ -6094,7 +6150,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode } return ir_build_ptr_type(irb, scope, node, child_type, is_const, is_volatile, - ptr_len, align_value, bit_offset_start, host_int_bytes, is_allow_zero); + ptr_len, sentinel, align_value, bit_offset_start, host_int_bytes, is_allow_zero); } static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, @@ -6198,13 +6254,22 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A buf_sprintf("initializing array with struct syntax")); return irb->codegen->invalid_instruction; } + IrInstruction *sentinel; + if (container_init_expr->type->data.inferred_array_type.sentinel != nullptr) { + sentinel = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.sentinel, scope); + if (sentinel == irb->codegen->invalid_instruction) + return sentinel; + } else { + sentinel = nullptr; + } + IrInstruction *elem_type = ir_gen_node(irb, container_init_expr->type->data.inferred_array_type.child_type, scope); if (elem_type == irb->codegen->invalid_instruction) return elem_type; size_t item_count = container_init_expr->entries.length; IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); - container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); + container_type = ir_build_array_type(irb, scope, node, item_count_inst, sentinel, elem_type); } else { container_type = ir_gen_node(irb, container_init_expr->type, scope); if (container_type == irb->codegen->invalid_instruction) @@ -6917,11 +6982,7 @@ static IrInstruction *ir_gen_enum_literal(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_gen_string_literal(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeStringLiteral); - if (node->data.string_literal.c) { - return ir_build_const_c_str_lit(irb, scope, node, node->data.string_literal.buf); - } else { - return ir_build_const_str_lit(irb, scope, node, node->data.string_literal.buf); - } + return ir_build_const_str_lit(irb, scope, node, node->data.string_literal.buf); } static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -6932,9 +6993,20 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n bool is_const = node->data.array_type.is_const; bool is_volatile = node->data.array_type.is_volatile; bool is_allow_zero = node->data.array_type.allow_zero_token != nullptr; + AstNode *sentinel_expr = node->data.array_type.sentinel; AstNode *align_expr = node->data.array_type.align_expr; Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); + + IrInstruction *sentinel; + if (sentinel_expr != nullptr) { + sentinel = ir_gen_node(irb, sentinel_expr, comptime_scope); + if (sentinel == irb->codegen->invalid_instruction) + return sentinel; + } else { + sentinel = nullptr; + } + if (size_node) { if (is_const) { add_node_error(irb->codegen, node, buf_create_from_str("const qualifier invalid on array type")); @@ -6961,7 +7033,7 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n if (child_type == irb->codegen->invalid_instruction) return child_type; - return ir_build_array_type(irb, scope, node, size_value, child_type); + return ir_build_array_type(irb, scope, node, size_value, sentinel, child_type); } else { IrInstruction *align_value; if (align_expr != nullptr) { @@ -6976,7 +7048,8 @@ static IrInstruction *ir_gen_array_type(IrBuilder *irb, Scope *scope, AstNode *n if (child_type == irb->codegen->invalid_instruction) return child_type; - return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, align_value, is_allow_zero); + return ir_build_slice_type(irb, scope, node, child_type, is_const, is_volatile, sentinel, + align_value, is_allow_zero); } } @@ -8486,6 +8559,9 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop add_node_error(irb->codegen, node, buf_sprintf("inferred array size invalid here")); return irb->codegen->invalid_instruction; + case NodeTypeVarFieldType: + return ir_lval_wrap(irb, scope, + ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_var), lval, result_loc); } zig_unreachable(); } @@ -8645,7 +8721,18 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal assert(val != nullptr); assert(const_val->type->id == ZigTypeIdPointer); ZigType *expected_type = const_val->type->data.pointer.child_type; - if (!types_have_same_zig_comptime_repr(val->type, expected_type)) { + if (expected_type == codegen->builtin_types.entry_var) { + return val; + } + switch (type_has_one_possible_value(codegen, expected_type)) { + case OnePossibleValueInvalid: + return nullptr; + case OnePossibleValueNo: + break; + case OnePossibleValueYes: + return get_the_one_possible_value(codegen, expected_type); + } + if (!types_have_same_zig_comptime_repr(codegen, expected_type, val->type)) { if ((err = eval_comptime_ptr_reinterpret(ira, codegen, source_node, const_val))) return nullptr; return const_ptr_pointee_unchecked(codegen, const_val); @@ -9793,6 +9880,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted // alignment can be decreased // bit offset attributes must match exactly // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one + // sentinel-terminated pointers can coerce into PtrLenUnknown ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); ZigType *actual_ptr_type = get_src_ptr_type(actual_type); bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); @@ -9804,6 +9892,35 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted bool actual_opt_or_ptr = actual_ptr_type != nullptr && (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional); if (wanted_opt_or_ptr && actual_opt_or_ptr) { + bool ok_null_term_ptrs = + wanted_ptr_type->data.pointer.sentinel == nullptr || + (actual_ptr_type->data.pointer.sentinel != nullptr && + const_values_equal(ira->codegen, wanted_ptr_type->data.pointer.sentinel, + actual_ptr_type->data.pointer.sentinel)); + if (!ok_null_term_ptrs) { + result.id = ConstCastResultIdPtrSentinel; + result.data.bad_ptr_sentinel = allocate_nonzero(1); + result.data.bad_ptr_sentinel->wanted_type = wanted_ptr_type; + result.data.bad_ptr_sentinel->actual_type = actual_ptr_type; + return result; + } + bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; + if (!(ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr)) { + result.id = ConstCastResultIdPtrLens; + return result; + } + + bool ok_cv_qualifiers = + (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && + (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile); + if (!ok_cv_qualifiers) { + result.id = ConstCastResultIdCV; + result.data.bad_cv = allocate_nonzero(1); + result.data.bad_cv->wanted_type = wanted_ptr_type; + result.data.bad_cv->actual_type = actual_ptr_type; + return result; + } + ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) @@ -9842,11 +9959,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.id = ConstCastResultIdInvalid; return result; } - bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; - if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && - type_has_bits(wanted_type) == type_has_bits(actual_type) && - (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && - (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && + if (type_has_bits(wanted_type) == type_has_bits(actual_type) && actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && actual_ptr_type->data.pointer.host_int_bytes == wanted_ptr_type->data.pointer.host_int_bytes && get_ptr_align(ira->codegen, actual_ptr_type) >= get_ptr_align(ira->codegen, wanted_ptr_type)) @@ -9855,6 +9968,36 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } } + // arrays + if (wanted_type->id == ZigTypeIdArray && actual_type->id == ZigTypeIdArray && + wanted_type->data.array.len == actual_type->data.array.len) + { + ConstCastOnly child = types_match_const_cast_only(ira, wanted_type->data.array.child_type, + actual_type->data.array.child_type, source_node, wanted_is_mutable); + if (child.id == ConstCastResultIdInvalid) + return child; + if (child.id != ConstCastResultIdOk) { + result.id = ConstCastResultIdArrayChild; + result.data.array_mismatch = allocate_nonzero(1); + result.data.array_mismatch->child = child; + result.data.array_mismatch->wanted_child = wanted_type->data.array.child_type; + result.data.array_mismatch->actual_child = actual_type->data.array.child_type; + return result; + } + bool ok_null_terminated = (wanted_type->data.array.sentinel == nullptr) || + (actual_type->data.array.sentinel != nullptr && + const_values_equal(ira->codegen, wanted_type->data.array.sentinel, actual_type->data.array.sentinel)); + if (!ok_null_terminated) { + result.id = ConstCastResultIdSentinelArrays; + result.data.sentinel_arrays = allocate_nonzero(1); + result.data.sentinel_arrays->child = child; + result.data.sentinel_arrays->wanted_type = wanted_type; + result.data.sentinel_arrays->actual_type = actual_type; + return result; + } + return result; + } + // slice const if (is_slice(wanted_type) && is_slice(actual_type)) { ZigType *actual_ptr_type = actual_type->data.structure.fields[slice_ptr_index]->type_entry; @@ -10615,6 +10758,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT // *[N]T to []T // *[N]T to E![]T if (cur_type->id == ZigTypeIdPointer && + cur_type->data.pointer.ptr_len == PtrLenSingle && cur_type->data.pointer.child_type->id == ZigTypeIdArray && ((prev_type->id == ZigTypeIdErrorUnion && is_slice(prev_type->data.error_union.payload_type)) || is_slice(prev_type))) @@ -10623,7 +10767,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT ZigType *slice_type = (prev_type->id == ZigTypeIdErrorUnion) ? prev_type->data.error_union.payload_type : prev_type; ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && + if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || + !cur_type->data.pointer.is_const) && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) @@ -10637,6 +10782,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT // *[N]T to E![]T if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.child_type->id == ZigTypeIdArray && + prev_type->data.pointer.ptr_len == PtrLenSingle && ((cur_type->id == ZigTypeIdErrorUnion && is_slice(cur_type->data.error_union.payload_type)) || is_slice(cur_type))) { @@ -10644,7 +10790,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT ZigType *slice_type = (cur_type->id == ZigTypeIdErrorUnion) ? cur_type->data.error_union.payload_type : cur_type; ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index]->type_entry; - if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0) && + if ((slice_ptr_type->data.pointer.is_const || array_type->data.array.len == 0 || + !prev_type->data.pointer.is_const) && types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, array_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) @@ -10667,6 +10814,50 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT continue; } + + // *[N]T and *[M]T + if (cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && + cur_type->data.pointer.child_type->id == ZigTypeIdArray && + prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && + prev_type->data.pointer.child_type->id == ZigTypeIdArray && + (cur_type->data.pointer.is_const || !prev_type->data.pointer.is_const || + prev_type->data.pointer.child_type->data.array.len == 0) && + ( + prev_type->data.pointer.child_type->data.array.sentinel == nullptr || + (cur_type->data.pointer.child_type->data.array.sentinel != nullptr && + const_values_equal(ira->codegen, prev_type->data.pointer.child_type->data.array.sentinel, + cur_type->data.pointer.child_type->data.array.sentinel)) + ) && + types_match_const_cast_only(ira, + cur_type->data.pointer.child_type->data.array.child_type, + prev_type->data.pointer.child_type->data.array.child_type, + source_node, !cur_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + prev_inst = cur_inst; + convert_to_const_slice = true; + continue; + } + if (prev_type->id == ZigTypeIdPointer && prev_type->data.pointer.ptr_len == PtrLenSingle && + prev_type->data.pointer.child_type->id == ZigTypeIdArray && + cur_type->id == ZigTypeIdPointer && cur_type->data.pointer.ptr_len == PtrLenSingle && + cur_type->data.pointer.child_type->id == ZigTypeIdArray && + (prev_type->data.pointer.is_const || !cur_type->data.pointer.is_const || + cur_type->data.pointer.child_type->data.array.len == 0) && + ( + cur_type->data.pointer.child_type->data.array.sentinel == nullptr || + (prev_type->data.pointer.child_type->data.array.sentinel != nullptr && + const_values_equal(ira->codegen, cur_type->data.pointer.child_type->data.array.sentinel, + prev_type->data.pointer.child_type->data.array.sentinel)) + ) && + types_match_const_cast_only(ira, + prev_type->data.pointer.child_type->data.array.child_type, + cur_type->data.pointer.child_type->data.array.child_type, + source_node, !prev_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + convert_to_const_slice = true; + continue; + } + // [N]T to []T if (prev_type->id == ZigTypeIdArray && is_slice(cur_type) && (cur_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const || @@ -10715,16 +10906,34 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT free(errors); if (convert_to_const_slice) { - assert(prev_inst->value.type->id == ZigTypeIdArray); - ZigType *ptr_type = get_pointer_to_type_extra( - ira->codegen, prev_inst->value.type->data.array.child_type, - true, false, PtrLenUnknown, - 0, 0, 0, false); - ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); - if (err_set_type != nullptr) { - return get_error_union_type(ira->codegen, err_set_type, slice_type); + if (prev_inst->value.type->id == ZigTypeIdArray) { + ZigType *ptr_type = get_pointer_to_type_extra( + ira->codegen, prev_inst->value.type->data.array.child_type, + true, false, PtrLenUnknown, + 0, 0, 0, false); + ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); + if (err_set_type != nullptr) { + return get_error_union_type(ira->codegen, err_set_type, slice_type); + } else { + return slice_type; + } + } else if (prev_inst->value.type->id == ZigTypeIdPointer) { + ZigType *array_type = prev_inst->value.type->data.pointer.child_type; + src_assert(array_type->id == ZigTypeIdArray, source_node); + ZigType *ptr_type = get_pointer_to_type_extra2( + ira->codegen, array_type->data.array.child_type, + prev_inst->value.type->data.pointer.is_const, false, + PtrLenUnknown, + 0, 0, 0, false, + VECTOR_INDEX_NONE, nullptr, array_type->data.array.sentinel); + ZigType *slice_type = get_slice_type(ira->codegen, ptr_type); + if (err_set_type != nullptr) { + return get_error_union_type(ira->codegen, err_set_type, slice_type); + } else { + return slice_type; + } } else { - return slice_type; + zig_unreachable(); } } else if (err_set_type != nullptr) { if (prev_inst->value.type->id == ZigTypeIdErrorSet) { @@ -10945,7 +11154,6 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; result->value.data.x_ptr.data.base_array.array_val = pointee; result->value.data.x_ptr.data.base_array.elem_index = 0; - result->value.data.x_ptr.data.base_array.is_cstr = false; return result; } } @@ -10957,31 +11165,31 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, } static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *wanted_type, ResultLoc *result_loc) + IrInstruction *array_ptr, ZigType *wanted_type, ResultLoc *result_loc) { Error err; - if ((err = type_resolve(ira->codegen, value->value.type->data.pointer.child_type, + if ((err = type_resolve(ira->codegen, array_ptr->value.type->data.pointer.child_type, ResolveStatusAlignmentKnown))) { return ira->codegen->invalid_instruction; } - wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, value->value.type)); + wanted_type = adjust_slice_align(ira->codegen, wanted_type, get_ptr_align(ira->codegen, array_ptr->value.type)); - if (instr_is_comptime(value)) { - ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &value->value, source_instr->source_node); + if (instr_is_comptime(array_ptr)) { + ConstExprValue *pointee = const_ptr_pointee(ira, ira->codegen, &array_ptr->value, source_instr->source_node); if (pointee == nullptr) return ira->codegen->invalid_instruction; if (pointee->special != ConstValSpecialRuntime) { - assert(value->value.type->id == ZigTypeIdPointer); - ZigType *array_type = value->value.type->data.pointer.child_type; + assert(array_ptr->value.type->id == ZigTypeIdPointer); + ZigType *array_type = array_ptr->value.type->data.pointer.child_type; assert(is_slice(wanted_type)); bool is_const = wanted_type->data.structure.fields[slice_ptr_index]->type_entry->data.pointer.is_const; IrInstruction *result = ir_const(ira, source_instr, wanted_type); init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); - result->value.data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = value->value.data.x_ptr.mut; + result->value.data.x_struct.fields[slice_ptr_index]->data.x_ptr.mut = array_ptr->value.data.x_ptr.mut; result->value.type = wanted_type; return result; } @@ -10993,7 +11201,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } - return ir_build_ptr_of_array_to_slice(ira, source_instr, wanted_type, value, result_loc_inst); + return ir_build_ptr_of_array_to_slice(ira, source_instr, wanted_type, array_ptr, result_loc_inst); } static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) { @@ -11524,7 +11732,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); const_instruction->base.value.special = ConstValSpecialStatic; - if (types_have_same_zig_comptime_repr(wanted_type, payload_type)) { + if (types_have_same_zig_comptime_repr(ira->codegen, wanted_type, payload_type)) { copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); } else { const_instruction->base.value.data.x_optional = val; @@ -12442,6 +12650,55 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa } break; } + case ConstCastResultIdPtrLens: { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("pointer length mismatch")); + break; + } + case ConstCastResultIdPtrSentinel: { + ZigType *actual_type = cast_result->data.bad_ptr_sentinel->actual_type; + ZigType *wanted_type = cast_result->data.bad_ptr_sentinel->wanted_type; + { + Buf *txt_msg = buf_sprintf("destination pointer requires a terminating '"); + render_const_value(ira->codegen, txt_msg, wanted_type->data.pointer.sentinel); + buf_appendf(txt_msg, "' sentinel"); + if (actual_type->data.pointer.sentinel != nullptr) { + buf_appendf(txt_msg, ", but source pointer has a terminating '"); + render_const_value(ira->codegen, txt_msg, actual_type->data.pointer.sentinel); + buf_appendf(txt_msg, "' sentinel"); + } + add_error_note(ira->codegen, parent_msg, source_node, txt_msg); + } + break; + } + case ConstCastResultIdSentinelArrays: { + ZigType *actual_type = cast_result->data.sentinel_arrays->actual_type; + ZigType *wanted_type = cast_result->data.sentinel_arrays->wanted_type; + Buf *txt_msg = buf_sprintf("destination array requires a terminating '"); + render_const_value(ira->codegen, txt_msg, wanted_type->data.array.sentinel); + buf_appendf(txt_msg, "' sentinel"); + if (actual_type->data.array.sentinel != nullptr) { + buf_appendf(txt_msg, ", but source array has a terminating '"); + render_const_value(ira->codegen, txt_msg, actual_type->data.array.sentinel); + buf_appendf(txt_msg, "' sentinel"); + } + add_error_note(ira->codegen, parent_msg, source_node, txt_msg); + break; + } + case ConstCastResultIdCV: { + ZigType *wanted_type = cast_result->data.bad_cv->wanted_type; + ZigType *actual_type = cast_result->data.bad_cv->actual_type; + bool ok_const = !actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const; + bool ok_volatile = !actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile; + if (!ok_const) { + add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("cast discards const qualifier")); + } else if (!ok_volatile) { + add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("cast discards volatile qualifier")); + } else { + zig_unreachable(); + } + break; + } case ConstCastResultIdFnIsGeneric: add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("only one of the functions is generic")); @@ -12458,6 +12715,7 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa case ConstCastResultIdFnArgNoAlias: // TODO case ConstCastResultIdUnresolvedInferredErrSet: // TODO case ConstCastResultIdAsyncAllocatorType: // TODO + case ConstCastResultIdArrayChild: // TODO break; } } @@ -12584,8 +12842,55 @@ static IrInstruction *ir_analyze_struct_literal_to_union(IrAnalyze *ira, IrInstr return ira->codegen->invalid_instruction; } +// Add a compile error and return ErrorSemanticAnalyzeFail if the pointer alignment does not work, +// otherwise return ErrorNone. Does not emit any instructions. +// Assumes that the pointer types have element types with the same ABI alignment. Avoids resolving the +// pointer types' alignments if both of the pointer types are ABI aligned. +static Error ir_cast_ptr_align(IrAnalyze *ira, IrInstruction *source_instr, ZigType *dest_ptr_type, + ZigType *src_ptr_type, AstNode *src_source_node) +{ + Error err; + + ir_assert(dest_ptr_type->id == ZigTypeIdPointer, source_instr); + ir_assert(src_ptr_type->id == ZigTypeIdPointer, source_instr); + + if (dest_ptr_type->data.pointer.explicit_alignment == 0 && + src_ptr_type->data.pointer.explicit_alignment == 0) + { + return ErrorNone; + } + + if ((err = type_resolve(ira->codegen, dest_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ErrorSemanticAnalyzeFail; + + if ((err = type_resolve(ira->codegen, src_ptr_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ErrorSemanticAnalyzeFail; + + uint32_t wanted_align = get_ptr_align(ira->codegen, dest_ptr_type); + uint32_t actual_align = get_ptr_align(ira->codegen, src_ptr_type); + if (wanted_align > actual_align) { + ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment")); + add_error_note(ira->codegen, msg, src_source_node, + buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&src_ptr_type->name), actual_align)); + add_error_note(ira->codegen, msg, source_instr->source_node, + buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&dest_ptr_type->name), wanted_align)); + return ErrorSemanticAnalyzeFail; + } + + return ErrorNone; +} + +static IrInstruction *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *struct_operand, TypeStructField *field) +{ + IrInstruction *struct_ptr = ir_get_ref(ira, source_instr, struct_operand, true, false); + IrInstruction *field_ptr = ir_analyze_struct_field_ptr(ira, source_instr, field, struct_ptr, + struct_operand->value.type, false); + return ir_get_deref(ira, source_instr, field_ptr, nullptr); +} + static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, - ZigType *wanted_type, IrInstruction *value, ResultLoc *result_loc) + ZigType *wanted_type, IrInstruction *value) { Error err; ZigType *actual_type = value->value.type; @@ -12631,12 +12936,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, nullptr); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, nullptr); } else { return ira->codegen->invalid_instruction; } @@ -12660,7 +12965,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_child_type); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type, result_loc); + return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type, nullptr); } } } @@ -12670,12 +12975,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, nullptr); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, nullptr); } else { return ira->codegen->invalid_instruction; } @@ -12693,11 +12998,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value, nullptr); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12770,7 +13075,6 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type); } - // cast from [N]T to []const T // TODO: once https://github.com/ziglang/zig/issues/265 lands, remove this if (is_slice(wanted_type) && actual_type->id == ZigTypeIdArray) { @@ -12780,7 +13084,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type, nullptr); } } @@ -12797,11 +13101,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value, nullptr); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12809,23 +13113,50 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } + // *[N]T to ?[]const T + if (wanted_type->id == ZigTypeIdOptional && + is_slice(wanted_type->data.maybe.child_type) && + actual_type->id == ZigTypeIdPointer && + actual_type->data.pointer.ptr_len == PtrLenSingle && + actual_type->data.pointer.child_type->id == ZigTypeIdArray) + { + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); + if (type_is_invalid(cast1->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + if (type_is_invalid(cast2->value.type)) + return ira->codegen->invalid_instruction; + + return cast2; + } + // *[N]T to [*]T and [*c]T if (wanted_type->id == ZigTypeIdPointer && (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC) && actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && - actual_type->data.pointer.child_type->id == ZigTypeIdArray) + actual_type->data.pointer.child_type->id == ZigTypeIdArray && + (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && + (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) { - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) && - types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, - actual_type->data.pointer.child_type->data.array.child_type, source_node, - !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) + ZigType *actual_array_type = actual_type->data.pointer.child_type; + if (wanted_type->data.pointer.sentinel == nullptr || + (actual_array_type->data.array.sentinel != nullptr && + const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, + actual_array_type->data.array.sentinel))) { - return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type); + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, ResolveStatusAlignmentKnown))) + return ira->codegen->invalid_instruction; + if (get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, wanted_type) && + types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node, + !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk) + { + return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type); + } } } @@ -12870,17 +13201,17 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } if (ok_align) { if (wanted_type->id == ZigTypeIdErrorUnion) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, slice_type, value, nullptr); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, slice_type, value); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; return cast2; } else { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, slice_type, result_loc); + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, slice_type, nullptr); } } } @@ -12921,7 +13252,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); } if (ok_align) { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, slice_type, result_loc); + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, slice_type, nullptr); } } } @@ -12977,11 +13308,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value, nullptr); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12993,7 +13324,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorSet) { - return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type, nullptr); } // cast from typed number to integer or float literal. @@ -13019,7 +13350,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (result == ira->codegen->invalid_instruction) return result; - return ir_analyze_optional_wrap(ira, result, value, wanted_type, result_loc); + return ir_analyze_optional_wrap(ira, result, value, wanted_type, nullptr); } // cast from enum literal to error union when payload is an enum @@ -13030,7 +13361,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (result == ira->codegen->invalid_instruction) return result; - return ir_analyze_err_wrap_payload(ira, result, value, wanted_type, result_loc); + return ir_analyze_err_wrap_payload(ira, result, value, wanted_type, nullptr); } // cast from union to the enum type of the union @@ -13060,35 +13391,39 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, array_type->data.array.child_type, actual_type->data.pointer.child_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && - // This should be the job of `types_match_const_cast_only` - // but `types_match_const_cast_only` only gets info for child_types - ((wanted_type->data.pointer.is_const && actual_type->data.pointer.is_const) || - !actual_type->data.pointer.is_const)) + // `types_match_const_cast_only` only gets info for child_types + (!actual_type->data.pointer.is_const || wanted_type->data.pointer.is_const) && + (!actual_type->data.pointer.is_volatile || wanted_type->data.pointer.is_volatile)) { - if ((err = type_resolve(ira->codegen, wanted_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { + if ((err = ir_cast_ptr_align(ira, source_instr, wanted_type, actual_type, value->source_node))) return ira->codegen->invalid_instruction; - } - if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, - ResolveStatusAlignmentKnown))) - { - return ira->codegen->invalid_instruction; - } - uint32_t wanted_align = get_ptr_align(ira->codegen, wanted_type); - uint32_t actual_align = get_ptr_align(ira->codegen, actual_type); - if (wanted_align > actual_align) { - ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment")); - add_error_note(ira->codegen, msg, value->source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name), actual_align)); - add_error_note(ira->codegen, msg, source_instr->source_node, - buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name), wanted_align)); - return ira->codegen->invalid_instruction; - } + return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type); } } + // [:x]T to [*:x]T + // [:x]T to [*c]T + if (wanted_type->id == ZigTypeIdPointer && is_slice(actual_type) && + ((wanted_type->data.pointer.ptr_len == PtrLenUnknown && wanted_type->data.pointer.sentinel != nullptr) || + wanted_type->data.pointer.ptr_len == PtrLenC)) + { + ZigType *slice_ptr_type = resolve_struct_field_type(ira->codegen, + actual_type->data.structure.fields[slice_ptr_index]); + if (types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, + slice_ptr_type->data.pointer.child_type, source_node, + !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk && + (slice_ptr_type->data.pointer.sentinel != nullptr && + (wanted_type->data.pointer.ptr_len == PtrLenC || + const_values_equal(ira->codegen, wanted_type->data.pointer.sentinel, + slice_ptr_type->data.pointer.sentinel)))) + { + TypeStructField *ptr_field = actual_type->data.structure.fields[slice_ptr_index]; + IrInstruction *slice_ptr = ir_analyze_struct_value_field_value(ira, source_instr, value, ptr_field); + return ir_implicit_cast2(ira, source_instr, slice_ptr, wanted_type); + } + } + // cast from *T and [*]T to *c_void and ?*c_void // but don't do it if the actual type is a double pointer if (is_pointery_and_elem_is_not_pointery(actual_type)) { @@ -13127,7 +13462,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, wanted_type->data.array.child_type, actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type, result_loc); + return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type, nullptr); } // cast from [N]T to @Vector(N, T) @@ -13188,8 +13523,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ira->codegen->invalid_instruction; } -static IrInstruction *ir_implicit_cast_with_result(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *expected_type, ResultLoc *result_loc) +static IrInstruction *ir_implicit_cast2(IrAnalyze *ira, IrInstruction *value_source_instr, + IrInstruction *value, ZigType *expected_type) { assert(value); assert(value != ira->codegen->invalid_instruction); @@ -13203,11 +13538,11 @@ static IrInstruction *ir_implicit_cast_with_result(IrAnalyze *ira, IrInstruction if (value->value.type->id == ZigTypeIdUnreachable) return value; - return ir_analyze_cast(ira, source_instr, expected_type, value, result_loc); + return ir_analyze_cast(ira, value_source_instr, expected_type, value); } static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) { - return ir_implicit_cast_with_result(ira, value, value, expected_type, nullptr); + return ir_implicit_cast2(ira, value, value, expected_type); } static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, @@ -13242,6 +13577,9 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc } if (ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + if (child_type == ira->codegen->builtin_types.entry_var) { + child_type = pointee->type; + } if (pointee->special != ConstValSpecialRuntime) { IrInstruction *result = ir_const(ira, source_instruction, child_type); @@ -14519,23 +14857,23 @@ static bool ok_float_op(IrBinOp op) { } static bool is_pointer_arithmetic_allowed(ZigType *lhs_type, IrBinOp op) { + switch (op) { + case IrBinOpAdd: + case IrBinOpSub: + break; + default: + return false; + } if (lhs_type->id != ZigTypeIdPointer) return false; - switch (op) { - case IrBinOpAdd: - case IrBinOpSub: - break; - default: - return false; - } switch (lhs_type->data.pointer.ptr_len) { case PtrLenSingle: - return false; + return lhs_type->data.pointer.child_type->id == ZigTypeIdArray; case PtrLenUnknown: case PtrLenC: - break; + return true; } - return true; + zig_unreachable(); } static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp *instruction) { @@ -14797,6 +15135,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i if (!op2_val) return ira->codegen->invalid_instruction; + ConstExprValue *sentinel1 = nullptr; ConstExprValue *op1_array_val; size_t op1_array_index; size_t op1_array_end; @@ -14806,15 +15145,17 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op1_array_val = op1_val; op1_array_index = 0; op1_array_end = op1_type->data.array.len; + sentinel1 = op1_type->data.array.sentinel; } else if (op1_type->id == ZigTypeIdPointer && op1_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray && - op1_val->data.x_ptr.data.base_array.is_cstr) + op1_type->data.pointer.sentinel != nullptr && + op1_val->data.x_ptr.special == ConstPtrSpecialBaseArray) { child_type = op1_type->data.pointer.child_type; op1_array_val = op1_val->data.x_ptr.data.base_array.array_val; op1_array_index = op1_val->data.x_ptr.data.base_array.elem_index; - op1_array_end = op1_array_val->type->data.array.len - 1; + op1_array_end = op1_array_val->type->data.array.len; + sentinel1 = op1_type->data.pointer.sentinel; } else if (is_slice(op1_type)) { ZigType *ptr_type = op1_type->data.structure.fields[slice_ptr_index]->type_entry; child_type = ptr_type->data.pointer.child_type; @@ -14824,12 +15165,25 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; ConstExprValue *len_val = op1_val->data.x_struct.fields[slice_len_index]; op1_array_end = op1_array_index + bigint_as_usize(&len_val->data.x_bigint); + sentinel1 = ptr_type->data.pointer.sentinel; + } else if (op1_type->id == ZigTypeIdPointer && op1_type->data.pointer.ptr_len == PtrLenSingle && + op1_type->data.pointer.child_type->id == ZigTypeIdArray) + { + ZigType *array_type = op1_type->data.pointer.child_type; + child_type = array_type->data.array.child_type; + op1_array_val = const_ptr_pointee(ira, ira->codegen, op1_val, op1->source_node); + if (op1_array_val == nullptr) + return ira->codegen->invalid_instruction; + op1_array_index = 0; + op1_array_end = array_type->data.array.len; + sentinel1 = array_type->data.array.sentinel; } else { ir_add_error(ira, op1, - buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); + buf_sprintf("expected array, found '%s'", buf_ptr(&op1->value.type->name))); return ira->codegen->invalid_instruction; } + ConstExprValue *sentinel2 = nullptr; ConstExprValue *op2_array_val; size_t op2_array_index; size_t op2_array_end; @@ -14839,15 +15193,17 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_val = op2_val; op2_array_index = 0; op2_array_end = op2_array_val->type->data.array.len; + sentinel2 = op2_type->data.array.sentinel; } else if (op2_type->id == ZigTypeIdPointer && - op2_type->data.pointer.child_type == ira->codegen->builtin_types.entry_u8 && - op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray && - op2_val->data.x_ptr.data.base_array.is_cstr) + op2_type->data.pointer.sentinel != nullptr && + op2_val->data.x_ptr.special == ConstPtrSpecialBaseArray) { - op2_type_valid = child_type == ira->codegen->builtin_types.entry_u8; + op2_type_valid = op2_type->data.pointer.child_type == child_type; op2_array_val = op2_val->data.x_ptr.data.base_array.array_val; op2_array_index = op2_val->data.x_ptr.data.base_array.elem_index; - op2_array_end = op2_array_val->type->data.array.len - 1; + op2_array_end = op2_array_val->type->data.array.len; + + sentinel2 = op2_type->data.pointer.sentinel; } else if (is_slice(op2_type)) { ZigType *ptr_type = op2_type->data.structure.fields[slice_ptr_index]->type_entry; op2_type_valid = ptr_type->data.pointer.child_type == child_type; @@ -14857,6 +15213,20 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; ConstExprValue *len_val = op2_val->data.x_struct.fields[slice_len_index]; op2_array_end = op2_array_index + bigint_as_usize(&len_val->data.x_bigint); + + sentinel2 = ptr_type->data.pointer.sentinel; + } else if (op2_type->id == ZigTypeIdPointer && op2_type->data.pointer.ptr_len == PtrLenSingle && + op2_type->data.pointer.child_type->id == ZigTypeIdArray) + { + ZigType *array_type = op2_type->data.pointer.child_type; + op2_type_valid = array_type->data.array.child_type == child_type; + op2_array_val = const_ptr_pointee(ira, ira->codegen, op2_val, op2->source_node); + if (op2_array_val == nullptr) + return ira->codegen->invalid_instruction; + op2_array_index = 0; + op2_array_end = array_type->data.array.len; + + sentinel2 = array_type->data.array.sentinel; } else { ir_add_error(ira, op2, buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); @@ -14869,6 +15239,19 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i return ira->codegen->invalid_instruction; } + ConstExprValue *sentinel; + if (sentinel1 != nullptr && sentinel2 != nullptr) { + // When there is a sentinel mismatch, no sentinel on the result. The type system + // will catch this if it is a problem. + sentinel = const_values_equal(ira->codegen, sentinel1, sentinel2) ? sentinel1 : nullptr; + } else if (sentinel1 != nullptr) { + sentinel = sentinel1; + } else if (sentinel2 != nullptr) { + sentinel = sentinel2; + } else { + sentinel = nullptr; + } + // The type of result is populated in the following if blocks IrInstruction *result = ir_const(ira, &instruction->base, nullptr); ConstExprValue *out_val = &result->value; @@ -14876,16 +15259,25 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i ConstExprValue *out_array_val; size_t new_len = (op1_array_end - op1_array_index) + (op2_array_end - op2_array_index); if (op1_type->id == ZigTypeIdArray || op2_type->id == ZigTypeIdArray) { - result->value.type = get_array_type(ira->codegen, child_type, new_len); + result->value.type = get_array_type(ira->codegen, child_type, new_len, sentinel); out_array_val = out_val; + } else if (op1_type->id == ZigTypeIdPointer || op2_type->id == ZigTypeIdPointer) { + out_array_val = create_const_vals(1); + out_array_val->special = ConstValSpecialStatic; + out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); + + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = out_array_val; + out_val->type = get_pointer_to_type(ira->codegen, out_array_val->type, true); } else if (is_slice(op1_type) || is_slice(op2_type)) { - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, - true, false, PtrLenUnknown, 0, 0, 0, false); + ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, child_type, + true, false, PtrLenUnknown, 0, 0, 0, false, + VECTOR_INDEX_NONE, nullptr, sentinel); result->value.type = get_slice_type(ira->codegen, ptr_type); out_array_val = create_const_vals(1); out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len); + out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); out_val->data.x_struct.fields = alloc_const_vals_ptrs(2); @@ -14899,46 +15291,54 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i out_val->data.x_struct.fields[slice_len_index]->special = ConstValSpecialStatic; bigint_init_unsigned(&out_val->data.x_struct.fields[slice_len_index]->data.x_bigint, new_len); } else { - new_len += 1; // null byte - - // TODO make this `[*]null T` instead of `[*]T` - result->value.type = get_pointer_to_type_extra(ira->codegen, child_type, true, false, PtrLenUnknown, 0, 0, 0, false); + result->value.type = get_pointer_to_type_extra2(ira->codegen, child_type, true, false, PtrLenUnknown, + 0, 0, 0, false, VECTOR_INDEX_NONE, nullptr, sentinel); out_array_val = create_const_vals(1); out_array_val->special = ConstValSpecialStatic; - out_array_val->type = get_array_type(ira->codegen, child_type, new_len); + out_array_val->type = get_array_type(ira->codegen, child_type, new_len, sentinel); out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; - out_val->data.x_ptr.data.base_array.is_cstr = true; out_val->data.x_ptr.data.base_array.array_val = out_array_val; out_val->data.x_ptr.data.base_array.elem_index = 0; } if (op1_array_val->data.x_array.special == ConstArraySpecialUndef && - op2_array_val->data.x_array.special == ConstArraySpecialUndef) { + op2_array_val->data.x_array.special == ConstArraySpecialUndef) + { out_array_val->data.x_array.special = ConstArraySpecialUndef; return result; } - out_array_val->data.x_array.data.s_none.elements = create_const_vals(new_len); + uint64_t full_len = new_len + ((sentinel != nullptr) ? 1 : 0); + out_array_val->data.x_array.data.s_none.elements = create_const_vals(full_len); // TODO handle the buf case here for an optimization expand_undef_array(ira->codegen, op1_array_val); expand_undef_array(ira->codegen, op2_array_val); size_t next_index = 0; for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { - copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index], - &op1_array_val->data.x_array.data.s_none.elements[i], true); + ConstExprValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; + copy_const_val(elem_dest_val, &op1_array_val->data.x_array.data.s_none.elements[i], false); + elem_dest_val->parent.id = ConstParentIdArray; + elem_dest_val->parent.data.p_array.array_val = out_array_val; + elem_dest_val->parent.data.p_array.elem_index = next_index; } for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) { - copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index], - &op2_array_val->data.x_array.data.s_none.elements[i], true); + ConstExprValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; + copy_const_val(elem_dest_val, &op2_array_val->data.x_array.data.s_none.elements[i], false); + elem_dest_val->parent.id = ConstParentIdArray; + elem_dest_val->parent.data.p_array.array_val = out_array_val; + elem_dest_val->parent.data.p_array.elem_index = next_index; } - if (next_index < new_len) { - ConstExprValue *null_byte = &out_array_val->data.x_array.data.s_none.elements[next_index]; - init_const_unsigned_negative(null_byte, child_type, 0, false); + if (next_index < full_len) { + ConstExprValue *elem_dest_val = &out_array_val->data.x_array.data.s_none.elements[next_index]; + copy_const_val(elem_dest_val, sentinel, false); + elem_dest_val->parent.id = ConstParentIdArray; + elem_dest_val->parent.data.p_array.array_val = out_array_val; + elem_dest_val->parent.data.p_array.elem_index = next_index; next_index += 1; } - assert(next_index == new_len); + assert(next_index == full_len); return result; } @@ -14952,20 +15352,34 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * if (type_is_invalid(op2->value.type)) return ira->codegen->invalid_instruction; - ConstExprValue *array_val = ir_resolve_const(ira, op1, UndefBad); - if (!array_val) + bool want_ptr_to_array = false; + ZigType *array_type; + ConstExprValue *array_val; + if (op1->value.type->id == ZigTypeIdArray) { + array_type = op1->value.type; + array_val = ir_resolve_const(ira, op1, UndefOk); + if (array_val == nullptr) + return ira->codegen->invalid_instruction; + } else if (op1->value.type->id == ZigTypeIdPointer && op1->value.type->data.pointer.ptr_len == PtrLenSingle && + op1->value.type->data.pointer.child_type->id == ZigTypeIdArray) + { + array_type = op1->value.type->data.pointer.child_type; + IrInstruction *array_inst = ir_get_deref(ira, op1, op1, nullptr); + if (type_is_invalid(array_inst->value.type)) + return ira->codegen->invalid_instruction; + array_val = ir_resolve_const(ira, array_inst, UndefOk); + if (array_val == nullptr) + return ira->codegen->invalid_instruction; + want_ptr_to_array = true; + } else { + ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value.type->name))); return ira->codegen->invalid_instruction; + } uint64_t mult_amt; if (!ir_resolve_usize(ira, op2, &mult_amt)) return ira->codegen->invalid_instruction; - ZigType *array_type = op1->value.type; - if (array_type->id != ZigTypeIdArray) { - ir_add_error(ira, op1, buf_sprintf("expected array type, found '%s'", buf_ptr(&op1->value.type->name))); - return ira->codegen->invalid_instruction; - } - uint64_t old_array_len = array_type->data.array.len; uint64_t new_array_len; @@ -14975,42 +15389,58 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * } ZigType *child_type = array_type->data.array.child_type; + ZigType *result_array_type = get_array_type(ira->codegen, child_type, new_array_len, + array_type->data.array.sentinel); - IrInstruction *result = ir_const(ira, &instruction->base, - get_array_type(ira->codegen, child_type, new_array_len)); - ConstExprValue *out_val = &result->value; - if (array_val->data.x_array.special == ConstArraySpecialUndef) { - out_val->data.x_array.special = ConstArraySpecialUndef; - return result; - } + IrInstruction *array_result; + if (array_val->special == ConstValSpecialUndef || array_val->data.x_array.special == ConstArraySpecialUndef) { + array_result = ir_const_undef(ira, &instruction->base, result_array_type); + } else { + array_result = ir_const(ira, &instruction->base, result_array_type); + ConstExprValue *out_val = &array_result->value; - switch (type_has_one_possible_value(ira->codegen, result->value.type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_instruction; - case OnePossibleValueYes: - return result; - case OnePossibleValueNo: - break; - } + switch (type_has_one_possible_value(ira->codegen, result_array_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + goto skip_computation; + case OnePossibleValueNo: + break; + } - // TODO optimize the buf case - expand_undef_array(ira->codegen, array_val); - out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len); + // TODO optimize the buf case + expand_undef_array(ira->codegen, array_val); + size_t extra_null_term = (array_type->data.array.sentinel != nullptr) ? 1 : 0; + out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len + extra_null_term); - uint64_t i = 0; - for (uint64_t x = 0; x < mult_amt; x += 1) { - for (uint64_t y = 0; y < old_array_len; y += 1) { + uint64_t i = 0; + for (uint64_t x = 0; x < mult_amt; x += 1) { + for (uint64_t y = 0; y < old_array_len; y += 1) { + ConstExprValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; + copy_const_val(elem_dest_val, &array_val->data.x_array.data.s_none.elements[y], false); + elem_dest_val->parent.id = ConstParentIdArray; + elem_dest_val->parent.data.p_array.array_val = out_val; + elem_dest_val->parent.data.p_array.elem_index = i; + i += 1; + } + } + assert(i == new_array_len); + + if (array_type->data.array.sentinel != nullptr) { ConstExprValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; - copy_const_val(elem_dest_val, &array_val->data.x_array.data.s_none.elements[y], false); + copy_const_val(elem_dest_val, array_type->data.array.sentinel, false); elem_dest_val->parent.id = ConstParentIdArray; elem_dest_val->parent.data.p_array.array_val = out_val; elem_dest_val->parent.data.p_array.elem_index = i; i += 1; } } - assert(i == new_array_len); - - return result; +skip_computation: + if (want_ptr_to_array) { + return ir_get_ref(ira, &instruction->base, array_result, true, false); + } else { + return array_result; + } } static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira, @@ -15909,7 +16339,19 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe if (!type_has_bits(value_type)) { parent_ptr_align = 0; } - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value_type, + // If we're casting from a sentinel-terminated array to a non-sentinel-terminated array, + // we actually need the result location pointer to *not* have a sentinel. Otherwise the generated + // memcpy will write an extra byte to the destination, and THAT'S NO GOOD. + ZigType *ptr_elem_type; + if (value_type->id == ZigTypeIdArray && value_type->data.array.sentinel != nullptr && + dest_type->id == ZigTypeIdArray && dest_type->data.array.sentinel == nullptr) + { + ptr_elem_type = get_array_type(ira->codegen, value_type->data.array.child_type, + value_type->data.array.len, nullptr); + } else { + ptr_elem_type = value_type; + } + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, ptr_elem_type, parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); @@ -17283,6 +17725,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source assert(out_val->type != nullptr); ConstExprValue *pointee = const_ptr_pointee_unchecked(codegen, ptr_val); + src_assert(pointee->type != nullptr, source_node); if ((err = type_resolve(codegen, pointee->type, ResolveStatusSizeKnown))) return ErrorSemanticAnalyzeFail; @@ -17293,7 +17736,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source size_t dst_size = type_size(codegen, out_val->type); if (dst_size <= src_size) { - if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { + if (src_size == dst_size && types_have_same_zig_comptime_repr(codegen, out_val->type, pointee->type)) { copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut != ConstPtrMutComptimeVar); return ErrorNone; } @@ -17882,13 +18325,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) { @@ -18044,6 +18490,12 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint); if (array_type->id == ZigTypeIdArray) { uint64_t array_len = array_type->data.array.len; + if (index == array_len && array_type->data.array.sentinel != nullptr) { + ZigType *elem_type = array_type->data.array.child_type; + IrInstruction *sentinel_elem = ir_const(ira, &elem_ptr_instruction->base, elem_type); + copy_const_val(&sentinel_elem->value, array_type->data.array.sentinel, false); + return ir_get_ref(ira, &elem_ptr_instruction->base, sentinel_elem, true, false); + } if (index >= array_len) { ir_add_error_node(ira, elem_ptr_instruction->base.source_node, buf_sprintf("index %" ZIG_PRI_u64 " outside array of size %" ZIG_PRI_u64, @@ -18059,7 +18511,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, elem_ptr_instruction->ptr_len, get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, (uint32_t)index, - nullptr); + nullptr, nullptr); } else if (return_type->data.pointer.explicit_alignment != 0) { // figure out the largest alignment possible @@ -18166,18 +18618,37 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct case ConstPtrSpecialDiscard: zig_unreachable(); case ConstPtrSpecialRef: - mem_size = 1; - old_size = 1; - new_index = index; + if (array_ptr_val->data.x_ptr.data.ref.pointee->type->id == ZigTypeIdArray) { + ConstExprValue *array_val = array_ptr_val->data.x_ptr.data.ref.pointee; + new_index = index; + ZigType *array_type = array_val->type; + mem_size = array_type->data.array.len; + if (array_type->data.array.sentinel != nullptr) { + mem_size += 1; + } + old_size = mem_size; - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee; + out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; + out_val->data.x_ptr.data.base_array.array_val = array_val; + out_val->data.x_ptr.data.base_array.elem_index = new_index; + } else { + mem_size = 1; + old_size = 1; + new_index = index; + + out_val->data.x_ptr.special = ConstPtrSpecialRef; + out_val->data.x_ptr.data.ref.pointee = array_ptr_val->data.x_ptr.data.ref.pointee; + } break; case ConstPtrSpecialBaseArray: { size_t offset = array_ptr_val->data.x_ptr.data.base_array.elem_index; new_index = offset + index; - mem_size = array_ptr_val->data.x_ptr.data.base_array.array_val->type->data.array.len; + ZigType *array_type = array_ptr_val->data.x_ptr.data.base_array.array_val->type; + mem_size = array_type->data.array.len; + if (array_type->data.array.sentinel != nullptr) { + mem_size += 1; + } old_size = mem_size - offset; assert(array_ptr_val->data.x_ptr.data.base_array.array_val); @@ -18186,8 +18657,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct out_val->data.x_ptr.data.base_array.array_val = array_ptr_val->data.x_ptr.data.base_array.array_val; out_val->data.x_ptr.data.base_array.elem_index = new_index; - out_val->data.x_ptr.data.base_array.is_cstr = - array_ptr_val->data.x_ptr.data.base_array.is_cstr; break; } @@ -18225,8 +18694,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)); @@ -18245,14 +18717,17 @@ 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; out_val->data.x_ptr.data.base_array.elem_index = new_index; - out_val->data.x_ptr.data.base_array.is_cstr = - ptr_field->data.x_ptr.data.base_array.is_cstr; break; } case ConstPtrSpecialBaseStruct: @@ -18301,7 +18776,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, elem_ptr_instruction->ptr_len, get_ptr_align(ira->codegen, ptr_type), 0, host_vec_len, false, VECTOR_INDEX_RUNTIME, - nullptr); + nullptr, nullptr); } else { // runtime known element index switch (type_requires_comptime(ira->codegen, return_type)) { @@ -18505,7 +18980,7 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n ZigType *elem_type = ira->codegen->builtin_types.entry_var; ZigType *field_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, container_ptr_type->data.pointer.is_const, container_ptr_type->data.pointer.is_volatile, - PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field); + PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field, nullptr); if (instr_is_comptime(container_ptr)) { IrInstruction *result = ir_const(ira, source_instr, field_ptr_type); @@ -19287,6 +19762,12 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, return ira->codegen->invalid_instruction; } + if (slice_type_instruction->sentinel != nullptr) { + lazy_slice_type->sentinel = slice_type_instruction->sentinel->child; + if (ir_resolve_const(ira, lazy_slice_type->sentinel, LazyOk) == nullptr) + return ira->codegen->invalid_instruction; + } + lazy_slice_type->elem_type = slice_type_instruction->child_type->child; if (ir_resolve_type_lazy(ira, lazy_slice_type->elem_type) == nullptr) return ira->codegen->invalid_instruction; @@ -19368,6 +19849,22 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, ZigType *child_type = ir_resolve_type(ira, child_type_value); if (type_is_invalid(child_type)) return ira->codegen->invalid_instruction; + + ConstExprValue *sentinel_val; + if (array_type_instruction->sentinel != nullptr) { + IrInstruction *uncasted_sentinel = array_type_instruction->sentinel->child; + if (type_is_invalid(uncasted_sentinel->value.type)) + return ira->codegen->invalid_instruction; + IrInstruction *sentinel = ir_implicit_cast(ira, uncasted_sentinel, child_type); + if (type_is_invalid(sentinel->value.type)) + return ira->codegen->invalid_instruction; + sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); + if (sentinel_val == nullptr) + return ira->codegen->invalid_instruction; + } else { + sentinel_val = nullptr; + } + switch (child_type->id) { case ZigTypeIdInvalid: // handled above zig_unreachable(); @@ -19403,7 +19900,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, { if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; - ZigType *result_type = get_array_type(ira->codegen, child_type, size); + ZigType *result_type = get_array_type(ira->codegen, child_type, size, sentinel_val); return ir_const_type(ira, &array_type_instruction->base, result_type); } } @@ -19476,13 +19973,24 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns return ir_analyze_test_non_null(ira, &instruction->base, value); } +static ZigType *get_ptr_elem_type(CodeGen *g, IrInstruction *ptr) { + ir_assert(ptr->value.type->id == ZigTypeIdPointer, ptr); + ZigType *elem_type = ptr->value.type->data.pointer.child_type; + if (elem_type != g->builtin_types.entry_var) + return elem_type; + + if (ir_resolve_lazy(g, ptr->source_node, &ptr->value)) + return g->builtin_types.entry_invalid; + + assert(value_is_comptime(&ptr->value)); + ConstExprValue *pointee = const_ptr_pointee_unchecked(g, &ptr->value); + return pointee->type; +} + static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing) { - ZigType *ptr_type = base_ptr->value.type; - assert(ptr_type->id == ZigTypeIdPointer); - - ZigType *type_entry = ptr_type->data.pointer.child_type; + ZigType *type_entry = get_ptr_elem_type(ira->codegen, base_ptr); if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; @@ -19520,9 +20028,10 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr ZigType *child_type = type_entry->data.maybe.child_type; ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, - ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false); + base_ptr->value.type->data.pointer.is_const, base_ptr->value.type->data.pointer.is_volatile, + PtrLenSingle, 0, 0, 0, false); - bool same_comptime_repr = types_have_same_zig_comptime_repr(type_entry, child_type); + bool same_comptime_repr = types_have_same_zig_comptime_repr(ira->codegen, child_type, type_entry); if (instr_is_comptime(base_ptr)) { ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); @@ -20479,7 +20988,7 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, if (container_type->id == ZigTypeIdArray) { ZigType *child_type = container_type->data.array.child_type; if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); + ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count, nullptr); ir_add_error(ira, &instruction->base, buf_sprintf("expected %s literal, found %s literal", @@ -20657,7 +21166,7 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct return ira->codegen->invalid_instruction; ErrorTableEntry *err = casted_value->value.data.x_err_set; if (!err->cached_error_name_val) { - ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); + ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name)->data.x_ptr.data.ref.pointee; err->cached_error_name_val = create_const_slice(ira->codegen, array_val, 0, buf_len(&err->name), true); } IrInstruction *result = ir_const(ira, &instruction->base, nullptr); @@ -20686,7 +21195,7 @@ static IrInstruction *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIns if ((err = type_resolve(ira->codegen, target->value.type, ResolveStatusZeroBitsKnown))) return ira->codegen->invalid_instruction; TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint); - ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name); + ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name)->data.x_ptr.data.ref.pointee; IrInstruction *result = ir_const(ira, &instruction->base, nullptr); init_const_slice(ira->codegen, &result->value, array_val, 0, buf_len(field->name), true); return result; @@ -20966,7 +21475,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr ConstExprValue *declaration_array = create_const_vals(1); declaration_array->special = ConstValSpecialStatic; - declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count); + declaration_array->type = get_array_type(ira->codegen, type_info_declaration_type, declaration_count, nullptr); declaration_array->data.x_array.special = ConstArraySpecialNone; declaration_array->data.x_array.data.s_none.elements = create_const_vals(declaration_count); init_const_slice(ira->codegen, out_val, declaration_array, 0, declaration_count, false); @@ -20991,7 +21500,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr declaration_val->type = type_info_declaration_type; ConstExprValue **inner_fields = alloc_const_vals_ptrs(3); - ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key); + ConstExprValue *name = create_const_str_lit(ira->codegen, curr_entry->key)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(curr_entry->key), true); inner_fields[1]->special = ConstValSpecialStatic; inner_fields[1]->type = ira->codegen->builtin_types.entry_bool; @@ -21094,7 +21603,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr fn_decl_fields[6]->type = get_optional_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); if (fn_node->is_extern && fn_node->lib_name != nullptr && buf_len(fn_node->lib_name) > 0) { fn_decl_fields[6]->data.x_optional = create_const_vals(1); - ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name); + ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, fn_decl_fields[6]->data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true); } else { @@ -21111,7 +21620,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr ConstExprValue *fn_arg_name_array = create_const_vals(1); fn_arg_name_array->special = ConstValSpecialStatic; fn_arg_name_array->type = get_array_type(ira->codegen, - get_slice_type(ira->codegen, u8_ptr), fn_arg_count); + get_slice_type(ira->codegen, u8_ptr), fn_arg_count, nullptr); fn_arg_name_array->data.x_array.special = ConstArraySpecialNone; fn_arg_name_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); @@ -21121,7 +21630,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index); ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index]; ConstExprValue *arg_name = create_const_str_lit(ira->codegen, - buf_create_from_str(arg_var->name)); + buf_create_from_str(arg_var->name))->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, strlen(arg_var->name), true); fn_arg_name_val->parent.id = ConstParentIdArray; fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array; @@ -21210,7 +21719,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty result->special = ConstValSpecialStatic; result->type = type_info_pointer_type; - ConstExprValue **fields = alloc_const_vals_ptrs(6); + ConstExprValue **fields = alloc_const_vals_ptrs(7); result->data.x_struct.fields = fields; // size: Size @@ -21246,6 +21755,16 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty fields[5]->special = ConstValSpecialStatic; fields[5]->type = ira->codegen->builtin_types.entry_bool; fields[5]->data.x_bool = attrs_type->data.pointer.allow_zero; + // sentinel: var + ensure_field_index(result->type, "sentinel", 6); + fields[6]->special = ConstValSpecialStatic; + if (attrs_type->data.pointer.sentinel != nullptr) { + fields[6]->type = get_optional_type(ira->codegen, attrs_type->data.pointer.child_type); + fields[6]->data.x_optional = attrs_type->data.pointer.sentinel; + } else { + fields[6]->type = ira->codegen->builtin_types.entry_null; + fields[6]->data.x_optional = nullptr; + } return result; }; @@ -21260,7 +21779,7 @@ static void make_enum_field_val(IrAnalyze *ira, ConstExprValue *enum_field_val, inner_fields[1]->special = ConstValSpecialStatic; inner_fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; - ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name); + ConstExprValue *name = create_const_str_lit(ira->codegen, enum_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(enum_field->name), true); bigint_init_bigint(&inner_fields[1]->data.x_bigint, &enum_field->value); @@ -21353,7 +21872,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr result->special = ConstValSpecialStatic; result->type = ir_type_info_get_type(ira, "Array", nullptr); - ConstExprValue **fields = alloc_const_vals_ptrs(2); + ConstExprValue **fields = alloc_const_vals_ptrs(3); result->data.x_struct.fields = fields; // len: usize @@ -21366,7 +21885,10 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr fields[1]->special = ConstValSpecialStatic; fields[1]->type = ira->codegen->builtin_types.entry_type; fields[1]->data.x_type = type_entry->data.array.child_type; - + // sentinel: var + fields[2]->special = ConstValSpecialStatic; + fields[2]->type = get_optional_type(ira->codegen, type_entry->data.array.child_type); + fields[2]->data.x_optional = type_entry->data.array.sentinel; break; } case ZigTypeIdVector: { @@ -21453,7 +21975,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr ConstExprValue *enum_field_array = create_const_vals(1); enum_field_array->special = ConstValSpecialStatic; - enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count); + enum_field_array->type = get_array_type(ira->codegen, type_info_enum_field_type, enum_field_count, nullptr); enum_field_array->data.x_array.special = ConstArraySpecialNone; enum_field_array->data.x_array.data.s_none.elements = create_const_vals(enum_field_count); @@ -21501,7 +22023,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr uint32_t error_count = type_entry->data.error_set.err_count; ConstExprValue *error_array = create_const_vals(1); error_array->special = ConstValSpecialStatic; - error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count); + error_array->type = get_array_type(ira->codegen, type_info_error_type, error_count, nullptr); error_array->data.x_array.special = ConstArraySpecialNone; error_array->data.x_array.data.s_none.elements = create_const_vals(error_count); @@ -21521,7 +22043,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr if (error->cached_error_name_val != nullptr) name = error->cached_error_name_val; if (name == nullptr) - name = create_const_str_lit(ira->codegen, &error->name); + name = create_const_str_lit(ira->codegen, &error->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(&error->name), true); bigint_init_unsigned(&inner_fields[1]->data.x_bigint, error->value); @@ -21597,7 +22119,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr ConstExprValue *union_field_array = create_const_vals(1); union_field_array->special = ConstValSpecialStatic; - union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count); + union_field_array->type = get_array_type(ira->codegen, type_info_union_field_type, union_field_count, nullptr); union_field_array->data.x_array.special = ConstArraySpecialNone; union_field_array->data.x_array.data.s_none.elements = create_const_vals(union_field_count); @@ -21627,7 +22149,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr inner_fields[2]->type = ira->codegen->builtin_types.entry_type; inner_fields[2]->data.x_type = union_field->type_entry; - ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name); + ConstExprValue *name = create_const_str_lit(ira->codegen, union_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(union_field->name), true); union_field_val->data.x_struct.fields = inner_fields; @@ -21677,7 +22199,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr ConstExprValue *struct_field_array = create_const_vals(1); struct_field_array->special = ConstValSpecialStatic; - struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count); + struct_field_array->type = get_array_type(ira->codegen, type_info_struct_field_type, struct_field_count, nullptr); struct_field_array->data.x_array.special = ConstArraySpecialNone; struct_field_array->data.x_array.data.s_none.elements = create_const_vals(struct_field_count); @@ -21713,7 +22235,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr inner_fields[2]->type = ira->codegen->builtin_types.entry_type; inner_fields[2]->data.x_type = struct_field->type_entry; - ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name); + ConstExprValue *name = create_const_str_lit(ira->codegen, struct_field->name)->data.x_ptr.data.ref.pointee; init_const_slice(ira->codegen, inner_fields[0], name, 0, buf_len(struct_field->name), true); struct_field_val->data.x_struct.fields = inner_fields; @@ -21780,7 +22302,7 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr ConstExprValue *fn_arg_array = create_const_vals(1); fn_arg_array->special = ConstValSpecialStatic; - fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count); + fn_arg_array->type = get_array_type(ira->codegen, type_info_fn_arg_type, fn_arg_count, nullptr); fn_arg_array->data.x_array.special = ConstArraySpecialNone; fn_arg_array->data.x_array.data.s_none.elements = create_const_vals(fn_arg_count); @@ -21878,6 +22400,20 @@ static ConstExprValue *get_const_field(IrAnalyze *ira, ConstExprValue *struct_va return struct_value->data.x_struct.fields[field_index]; } +static Error get_const_field_sentinel(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *struct_value, + const char *name, size_t field_index, ZigType *elem_type, ConstExprValue **result) +{ + ConstExprValue *field_val = get_const_field(ira, struct_value, name, field_index); + IrInstruction *field_inst = ir_const(ira, source_instr, field_val->type); + IrInstruction *casted_field_inst = ir_implicit_cast(ira, field_inst, + get_optional_type(ira->codegen, elem_type)); + if (type_is_invalid(casted_field_inst->value.type)) + return ErrorSemanticAnalyzeFail; + + *result = casted_field_inst->value.data.x_optional; + return ErrorNone; +} + static bool get_const_field_bool(IrAnalyze *ira, ConstExprValue *struct_value, const char *name, size_t field_index) { ConstExprValue *value = get_const_field(ira, struct_value, name, field_index); @@ -21900,6 +22436,7 @@ static ZigType *get_const_field_meta_type(IrAnalyze *ira, ConstExprValue *struct } static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, ZigTypeId tagTypeId, ConstExprValue *payload) { + Error err; switch (tagTypeId) { case ZigTypeIdInvalid: zig_unreachable(); @@ -21941,27 +22478,43 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInstruction *instruction, Zi assert(size_value->type == ir_type_info_get_type(ira, "Size", type_info_pointer_type)); BuiltinPtrSize size_enum_index = (BuiltinPtrSize)bigint_as_u32(&size_value->data.x_enum_tag); PtrLen ptr_len = size_enum_index_to_ptr_len(size_enum_index); - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, - get_const_field_meta_type(ira, payload, "child", 4), + ZigType *elem_type = get_const_field_meta_type(ira, payload, "child", 4); + ConstExprValue *sentinel; + if ((err = get_const_field_sentinel(ira, instruction, payload, "sentinel", 6, + elem_type, &sentinel))) + { + return nullptr; + } + + ZigType *ptr_type = get_pointer_to_type_extra2(ira->codegen, + elem_type, get_const_field_bool(ira, payload, "is_const", 1), get_const_field_bool(ira, payload, "is_volatile", 2), ptr_len, bigint_as_u32(get_const_field_lit_int(ira, payload, "alignment", 3)), 0, // bit_offset_in_host 0, // host_int_bytes - get_const_field_bool(ira, payload, "is_allowzero", 5) - ); + get_const_field_bool(ira, payload, "is_allowzero", 5), + VECTOR_INDEX_NONE, nullptr, sentinel); if (size_enum_index != 2) return ptr_type; return get_slice_type(ira->codegen, ptr_type); } - case ZigTypeIdArray: + case ZigTypeIdArray: { assert(payload->special == ConstValSpecialStatic); assert(payload->type == ir_type_info_get_type(ira, "Array", nullptr)); + ZigType *elem_type = get_const_field_meta_type(ira, payload, "child", 1); + ConstExprValue *sentinel; + if ((err = get_const_field_sentinel(ira, instruction, payload, "sentinel", 2, + elem_type, &sentinel))) + { + return nullptr; + } return get_array_type(ira->codegen, - get_const_field_meta_type(ira, payload, "child", 1), - bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)) - ); + elem_type, + bigint_as_u64(get_const_field_lit_int(ira, payload, "len", 0)), + sentinel); + } case ZigTypeIdComptimeFloat: return ira->codegen->builtin_types.entry_num_lit_float; case ZigTypeIdComptimeInt: @@ -22343,7 +22896,7 @@ static IrInstruction *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstru } ZigType *result_type = get_array_type(ira->codegen, - ira->codegen->builtin_types.entry_u8, buf_len(file_contents)); + ira->codegen->builtin_types.entry_u8, buf_len(file_contents), nullptr); IrInstruction *result = ir_const(ira, &instruction->base, result_type); init_const_str_lit(ira->codegen, &result->value, file_contents); return result; @@ -25566,6 +26119,12 @@ static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstruct result->value.data.x_lazy = &lazy_ptr_type->base; lazy_ptr_type->base.id = LazyValueIdPtrType; + if (instruction->sentinel != nullptr) { + lazy_ptr_type->sentinel = instruction->sentinel->child; + if (ir_resolve_const(ira, lazy_ptr_type->sentinel, LazyOk) == nullptr) + return ira->codegen->invalid_instruction; + } + lazy_ptr_type->elem_type = instruction->child_type->child; if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) return ira->codegen->invalid_instruction; @@ -26487,7 +27046,7 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns ZigType *dest_type = ir_resolve_type(ira, instruction->result_loc_cast->base.source_instruction->child); if (type_is_invalid(dest_type)) return ira->codegen->invalid_instruction; - return ir_implicit_cast_with_result(ira, &instruction->base, operand, dest_type, nullptr); + return ir_implicit_cast2(ira, &instruction->base, operand, dest_type); } static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInstructionBitCastSrc *instruction) { @@ -27512,6 +28071,20 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { if (type_is_invalid(elem_type)) return ErrorSemanticAnalyzeFail; + ConstExprValue *sentinel_val; + if (lazy_slice_type->sentinel != nullptr) { + if (type_is_invalid(lazy_slice_type->sentinel->value.type)) + return ErrorSemanticAnalyzeFail; + IrInstruction *sentinel = ir_implicit_cast(ira, lazy_slice_type->sentinel, elem_type); + if (type_is_invalid(sentinel->value.type)) + return ErrorSemanticAnalyzeFail; + sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); + if (sentinel_val == nullptr) + return ErrorSemanticAnalyzeFail; + } else { + sentinel_val = nullptr; + } + uint32_t align_bytes = 0; if (lazy_slice_type->align_inst != nullptr) { if (!ir_resolve_align(ira, lazy_slice_type->align_inst, elem_type, &align_bytes)) @@ -27557,9 +28130,12 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; if ((err = type_resolve(ira->codegen, elem_type, needed_status))) return err; - ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, - lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes, - 0, 0, lazy_slice_type->is_allowzero); + ZigType *slice_ptr_type = get_pointer_to_type_extra2(ira->codegen, elem_type, + lazy_slice_type->is_const, lazy_slice_type->is_volatile, + PtrLenUnknown, + align_bytes, + 0, 0, lazy_slice_type->is_allowzero, + VECTOR_INDEX_NONE, nullptr, sentinel_val); val->special = ConstValSpecialStatic; assert(val->type->id == ZigTypeIdMetaType); val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); @@ -27573,6 +28149,20 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { if (type_is_invalid(elem_type)) return ErrorSemanticAnalyzeFail; + ConstExprValue *sentinel_val; + if (lazy_ptr_type->sentinel != nullptr) { + if (type_is_invalid(lazy_ptr_type->sentinel->value.type)) + return ErrorSemanticAnalyzeFail; + IrInstruction *sentinel = ir_implicit_cast(ira, lazy_ptr_type->sentinel, elem_type); + if (type_is_invalid(sentinel->value.type)) + return ErrorSemanticAnalyzeFail; + sentinel_val = ir_resolve_const(ira, sentinel, UndefBad); + if (sentinel_val == nullptr) + return ErrorSemanticAnalyzeFail; + } else { + sentinel_val = nullptr; + } + uint32_t align_bytes = 0; if (lazy_ptr_type->align_inst != nullptr) { if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, elem_type, &align_bytes)) @@ -27615,10 +28205,10 @@ static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { } bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; assert(val->type->id == ZigTypeIdMetaType); - val->data.x_type = get_pointer_to_type_extra(ira->codegen, elem_type, + val->data.x_type = get_pointer_to_type_extra2(ira->codegen, elem_type, lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, - allow_zero); + allow_zero, VECTOR_INDEX_NONE, nullptr, sentinel_val); val->special = ConstValSpecialStatic; return ErrorNone; } diff --git a/src/parser.cpp b/src/parser.cpp index e87c83a27624e311dffafde7abd095f205886b31..429566ecc18ebb53b8795f955ac22e6b0d6da272 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -848,7 +848,12 @@ static AstNode *ast_parse_container_field(ParseContext *pc) { AstNode *type_expr = nullptr; if (eat_token_if(pc, TokenIdColon) != nullptr) { - type_expr = ast_expect(pc, ast_parse_type_expr); + Token *var_tok = eat_token_if(pc, TokenIdKeywordVar); + if (var_tok != nullptr) { + type_expr = ast_create_node(pc, NodeTypeVarFieldType, var_tok); + } else { + type_expr = ast_expect(pc, ast_parse_type_expr); + } } AstNode *align_expr = ast_parse_byte_align(pc); AstNode *expr = nullptr; @@ -1718,7 +1723,6 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { if (string_lit != nullptr) { AstNode *res = ast_create_node(pc, NodeTypeStringLiteral, string_lit); res->data.string_literal.buf = token_buf(string_lit); - res->data.string_literal.c = string_lit->data.str_lit.is_c_str; return res; } @@ -1834,8 +1838,10 @@ static AstNode *ast_parse_labeled_type_expr(ParseContext *pc) { return loop; } - if (label != nullptr) - ast_invalid_token_error(pc, peek_token(pc)); + if (label != nullptr) { + put_back_token(pc); + put_back_token(pc); + } return nullptr; } @@ -1932,15 +1938,11 @@ static AstNode *ast_parse_asm_output(ParseContext *pc) { // AsmOutputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { - Token *sym_name = eat_token_if(pc, TokenIdBracketUnderscoreBracket); - if (sym_name == nullptr) { - if (eat_token_if(pc, TokenIdLBracket) == nullptr) { - return nullptr; - } else { - sym_name = expect_token(pc, TokenIdSymbol); - expect_token(pc, TokenIdRBracket); - } - } + if (eat_token_if(pc, TokenIdLBracket) == nullptr) + return nullptr; + + Token *sym_name = expect_token(pc, TokenIdSymbol); + expect_token(pc, TokenIdRBracket); Token *str = expect_token(pc, TokenIdStringLiteral); expect_token(pc, TokenIdLParen); @@ -1955,7 +1957,7 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { expect_token(pc, TokenIdRParen); AsmOutput *res = allocate(1); - res->asm_symbolic_name = (sym_name->id == TokenIdBracketUnderscoreBracket) ? buf_create_from_str("_") : token_buf(sym_name); + res->asm_symbolic_name = token_buf(sym_name); res->constraint = token_buf(str); res->variable_name = token_buf(var_name); res->return_type = return_type; @@ -1978,15 +1980,11 @@ static AstNode *ast_parse_asm_input(ParseContext *pc) { // AsmInputItem <- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { - Token *sym_name = eat_token_if(pc, TokenIdBracketUnderscoreBracket); - if (sym_name == nullptr) { - if (eat_token_if(pc, TokenIdLBracket) == nullptr) { - return nullptr; - } else { - sym_name = expect_token(pc, TokenIdSymbol); - expect_token(pc, TokenIdRBracket); - } - } + if (eat_token_if(pc, TokenIdLBracket) == nullptr) + return nullptr; + + Token *sym_name = expect_token(pc, TokenIdSymbol); + expect_token(pc, TokenIdRBracket); Token *constraint = expect_token(pc, TokenIdStringLiteral); expect_token(pc, TokenIdLParen); @@ -1994,7 +1992,7 @@ static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { expect_token(pc, TokenIdRParen); AsmInput *res = allocate(1); - res->asm_symbolic_name = (sym_name->id == TokenIdBracketUnderscoreBracket) ? buf_create_from_str("_") : token_buf(sym_name); + res->asm_symbolic_name = token_buf(sym_name); res->constraint = token_buf(constraint); res->expr = expr; return res; @@ -2614,37 +2612,28 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { put_back_token(pc); } - AstNode *array = ast_parse_array_type_start(pc); - if (array != nullptr) { - assert(array->type == NodeTypeArrayType); - while (true) { - Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); - if (allowzero_token != nullptr) { - array->data.array_type.allow_zero_token = allowzero_token; - continue; + Token *arr_init_lbracket = eat_token_if(pc, TokenIdLBracket); + if (arr_init_lbracket != nullptr) { + Token *underscore = eat_token_if(pc, TokenIdSymbol); + if (underscore == nullptr) { + put_back_token(pc); + } else if (!buf_eql_str(token_buf(underscore), "_")) { + put_back_token(pc); + put_back_token(pc); + } else { + AstNode *sentinel = nullptr; + Token *colon = eat_token_if(pc, TokenIdColon); + if (colon != nullptr) { + sentinel = ast_expect(pc, ast_parse_expr); } - - AstNode *align_expr = ast_parse_byte_align(pc); - if (align_expr != nullptr) { - array->data.array_type.align_expr = align_expr; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordConst) != nullptr) { - array->data.array_type.is_const = true; - continue; - } - - if (eat_token_if(pc, TokenIdKeywordVolatile) != nullptr) { - array->data.array_type.is_volatile = true; - continue; - } - break; + expect_token(pc, TokenIdRBracket); + AstNode *node = ast_create_node(pc, NodeTypeInferredArrayType, arr_init_lbracket); + node->data.inferred_array_type.sentinel = sentinel; + return node; } - - return array; } + AstNode *ptr = ast_parse_ptr_type_start(pc); if (ptr != nullptr) { assert(ptr->type == NodeTypePointerType); @@ -2690,9 +2679,35 @@ static AstNode *ast_parse_prefix_type_op(ParseContext *pc) { return ptr; } - Token *arr_init = eat_token_if(pc, TokenIdBracketUnderscoreBracket); - if (arr_init != nullptr) { - return ast_create_node(pc, NodeTypeInferredArrayType, arr_init); + AstNode *array = ast_parse_array_type_start(pc); + if (array != nullptr) { + assert(array->type == NodeTypeArrayType); + while (true) { + Token *allowzero_token = eat_token_if(pc, TokenIdKeywordAllowZero); + if (allowzero_token != nullptr) { + array->data.array_type.allow_zero_token = allowzero_token; + continue; + } + + AstNode *align_expr = ast_parse_byte_align(pc); + if (align_expr != nullptr) { + array->data.array_type.align_expr = align_expr; + continue; + } + + if (eat_token_if(pc, TokenIdKeywordConst) != nullptr) { + array->data.array_type.is_const = true; + continue; + } + + if (eat_token_if(pc, TokenIdKeywordVolatile) != nullptr) { + array->data.array_type.is_volatile = true; + continue; + } + break; + } + + return array; } @@ -2766,9 +2781,15 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) { return nullptr; AstNode *size = ast_parse_expr(pc); + AstNode *sentinel = nullptr; + Token *colon = eat_token_if(pc, TokenIdColon); + if (colon != nullptr) { + sentinel = ast_expect(pc, ast_parse_expr); + } expect_token(pc, TokenIdRBracket); AstNode *res = ast_create_node(pc, NodeTypeArrayType, lbracket); res->data.array_type.size = size; + res->data.array_type.sentinel = sentinel; return res; } @@ -2778,35 +2799,63 @@ static AstNode *ast_parse_array_type_start(ParseContext *pc) { // / PTRUNKNOWN // / PTRC static AstNode *ast_parse_ptr_type_start(ParseContext *pc) { + AstNode *sentinel = nullptr; + Token *asterisk = eat_token_if(pc, TokenIdStar); if (asterisk != nullptr) { + Token *colon = eat_token_if(pc, TokenIdColon); + if (colon != nullptr) { + sentinel = ast_expect(pc, ast_parse_expr); + } AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk); res->data.pointer_type.star_token = asterisk; + res->data.pointer_type.sentinel = sentinel; return res; } Token *asterisk2 = eat_token_if(pc, TokenIdStarStar); if (asterisk2 != nullptr) { + Token *colon = eat_token_if(pc, TokenIdColon); + if (colon != nullptr) { + sentinel = ast_expect(pc, ast_parse_expr); + } AstNode *res = ast_create_node(pc, NodeTypePointerType, asterisk2); AstNode *res2 = ast_create_node(pc, NodeTypePointerType, asterisk2); res->data.pointer_type.star_token = asterisk2; res2->data.pointer_type.star_token = asterisk2; + res2->data.pointer_type.sentinel = sentinel; res->data.pointer_type.op_expr = res2; return res; } - Token *multptr = eat_token_if(pc, TokenIdBracketStarBracket); - if (multptr != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypePointerType, multptr); - res->data.pointer_type.star_token = multptr; - return res; - } + Token *lbracket = eat_token_if(pc, TokenIdLBracket); + if (lbracket != nullptr) { + Token *star = eat_token_if(pc, TokenIdStar); + if (star == nullptr) { + put_back_token(pc); + } else { + Token *c_tok = eat_token_if(pc, TokenIdSymbol); + if (c_tok != nullptr) { + if (!buf_eql_str(token_buf(c_tok), "c")) { + put_back_token(pc); // c symbol + } else { + expect_token(pc, TokenIdRBracket); + AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket); + res->data.pointer_type.star_token = c_tok; + return res; + } + } - Token *cptr = eat_token_if(pc, TokenIdBracketStarCBracket); - if (cptr != nullptr) { - AstNode *res = ast_create_node(pc, NodeTypePointerType, cptr); - res->data.pointer_type.star_token = cptr; - return res; + Token *colon = eat_token_if(pc, TokenIdColon); + if (colon != nullptr) { + sentinel = ast_expect(pc, ast_parse_expr); + } + expect_token(pc, TokenIdRBracket); + AstNode *res = ast_create_node(pc, NodeTypePointerType, lbracket); + res->data.pointer_type.star_token = lbracket; + res->data.pointer_type.sentinel = sentinel; + return res; + } } return nullptr; @@ -3084,10 +3133,12 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont break; case NodeTypeArrayType: visit_field(&node->data.array_type.size, visit, context); + visit_field(&node->data.array_type.sentinel, visit, context); visit_field(&node->data.array_type.child_type, visit, context); visit_field(&node->data.array_type.align_expr, visit, context); break; case NodeTypeInferredArrayType: + visit_field(&node->data.array_type.sentinel, visit, context); visit_field(&node->data.array_type.child_type, visit, context); break; case NodeTypeAnyFrameType: @@ -3097,6 +3148,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont // none break; case NodeTypePointerType: + visit_field(&node->data.pointer_type.sentinel, visit, context); visit_field(&node->data.pointer_type.align_expr, visit, context); visit_field(&node->data.pointer_type.op_expr, visit, context); break; @@ -3116,6 +3168,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.suspend.block, visit, context); break; case NodeTypeEnumLiteral: + case NodeTypeVarFieldType: break; } } diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 7ece5ff3fe1a996d26c9aa347a127bd340eb0ffc..f8b5059bf145496116cd3c81eecf0868f623ccf8 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -33,10 +33,10 @@ '0': \ case DIGIT_NON_ZERO -#define ALPHA_EXCEPT_C \ +#define ALPHA \ 'a': \ case 'b': \ - /*case 'c':*/ \ + case 'c': \ case 'd': \ case 'e': \ case 'f': \ @@ -87,10 +87,6 @@ case 'Y': \ case 'Z' -#define ALPHA \ - ALPHA_EXCEPT_C: \ - case 'c' - #define SYMBOL_CHAR \ ALPHA: \ case DIGIT: \ @@ -180,7 +176,6 @@ static bool is_symbol_char(uint8_t c) { enum TokenizeState { TokenizeStateStart, TokenizeStateSymbol, - TokenizeStateSymbolFirstC, TokenizeStateZero, // "0", which might lead to "0x" TokenizeStateNumber, // "123", "0x123" TokenizeStateNumberDot, @@ -227,10 +222,6 @@ enum TokenizeState { TokenizeStateSawAtSign, TokenizeStateCharCode, TokenizeStateError, - TokenizeStateLBracket, - TokenizeStateLBracketStar, - TokenizeStateLBracketStarC, - TokenizeStateLBracketUnderscore, }; @@ -279,7 +270,6 @@ static void set_token_id(Tokenize *t, Token *token, TokenId id) { } else if (id == TokenIdStringLiteral || id == TokenIdSymbol) { memset(&token->data.str_lit.str, 0, sizeof(Buf)); buf_resize(&token->data.str_lit.str, 0); - token->data.str_lit.is_c_str = false; } } @@ -429,12 +419,7 @@ void tokenize(Buf *buf, Tokenization *out) { switch (c) { case WHITESPACE: break; - case 'c': - t.state = TokenizeStateSymbolFirstC; - begin_token(&t, TokenIdSymbol); - buf_append_char(&t.cur_tok->data.str_lit.str, c); - break; - case ALPHA_EXCEPT_C: + case ALPHA: case '_': t.state = TokenizeStateSymbol; begin_token(&t, TokenIdSymbol); @@ -491,8 +476,8 @@ void tokenize(Buf *buf, Tokenization *out) { end_token(&t); break; case '[': - t.state = TokenizeStateLBracket; begin_token(&t, TokenIdLBracket); + end_token(&t); break; case ']': begin_token(&t, TokenIdRBracket); @@ -786,62 +771,6 @@ void tokenize(Buf *buf, Tokenization *out) { continue; } break; - case TokenizeStateLBracket: - switch (c) { - case '*': - t.state = TokenizeStateLBracketStar; - break; - case '_': - t.state = TokenizeStateLBracketUnderscore; - break; - default: - // reinterpret as just an lbracket - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateLBracketUnderscore: - switch (c) { - case ']': - set_token_id(&t, t.cur_tok, TokenIdBracketUnderscoreBracket); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - // reinterpret as just an lbracket - t.pos -= 2; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; - case TokenizeStateLBracketStar: - switch (c) { - case 'c': - t.state = TokenizeStateLBracketStarC; - set_token_id(&t, t.cur_tok, TokenIdBracketStarCBracket); - break; - case ']': - set_token_id(&t, t.cur_tok, TokenIdBracketStarBracket); - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - invalid_char_error(&t, c); - } - break; - case TokenizeStateLBracketStarC: - switch (c) { - case ']': - end_token(&t); - t.state = TokenizeStateStart; - break; - default: - invalid_char_error(&t, c); - } - break; case TokenizeStateSawPlusPercent: switch (c) { case '=': @@ -1007,19 +936,7 @@ void tokenize(Buf *buf, Tokenization *out) { switch (c) { case WHITESPACE: break; - case 'c': - if (!t.cur_tok->data.str_lit.is_c_str) { - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - break; - } - t.state = TokenizeStateLineStringContinueC; - break; case '\\': - if (t.cur_tok->data.str_lit.is_c_str) { - invalid_char_error(&t, c); - } t.state = TokenizeStateLineStringContinue; break; default: @@ -1084,29 +1001,6 @@ void tokenize(Buf *buf, Tokenization *out) { break; } break; - case TokenizeStateSymbolFirstC: - switch (c) { - case '"': - set_token_id(&t, t.cur_tok, TokenIdStringLiteral); - t.cur_tok->data.str_lit.is_c_str = true; - t.state = TokenizeStateString; - break; - case '\\': - set_token_id(&t, t.cur_tok, TokenIdStringLiteral); - t.cur_tok->data.str_lit.is_c_str = true; - t.state = TokenizeStateSawBackslash; - break; - case SYMBOL_CHAR: - t.state = TokenizeStateSymbol; - buf_append_char(&t.cur_tok->data.str_lit.str, c); - break; - default: - t.pos -= 1; - end_token(&t); - t.state = TokenizeStateStart; - continue; - } - break; case TokenizeStateSawAtSign: switch (c) { case '"': @@ -1544,7 +1438,6 @@ void tokenize(Buf *buf, Tokenization *out) { tokenize_error(&t, "unterminated character literal"); break; case TokenizeStateSymbol: - case TokenizeStateSymbolFirstC: case TokenizeStateZero: case TokenizeStateNumber: case TokenizeStateFloatFraction: @@ -1572,7 +1465,6 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateLineString: case TokenizeStateLineStringEnd: case TokenizeStateSawBarBar: - case TokenizeStateLBracket: case TokenizeStateDocComment: case TokenizeStateContainerDocComment: end_token(&t); @@ -1581,9 +1473,6 @@ void tokenize(Buf *buf, Tokenization *out) { case TokenizeStateSawBackslash: case TokenizeStateLineStringContinue: case TokenizeStateLineStringContinueC: - case TokenizeStateLBracketStar: - case TokenizeStateLBracketStarC: - case TokenizeStateLBracketUnderscore: tokenize_error(&t, "unexpected EOF"); break; case TokenizeStateLineComment: @@ -1623,8 +1512,6 @@ const char * token_name(TokenId id) { case TokenIdBitShiftRight: return ">>"; case TokenIdBitShiftRightEq: return ">>="; case TokenIdBitXorEq: return "^="; - case TokenIdBracketStarBracket: return "[*]"; - case TokenIdBracketStarCBracket: return "[*c]"; case TokenIdCharLiteral: return "CharLiteral"; case TokenIdCmpEq: return "=="; case TokenIdCmpGreaterOrEq: return ">="; @@ -1728,7 +1615,6 @@ const char * token_name(TokenId id) { case TokenIdTimesPercent: return "*%"; case TokenIdTimesPercentEq: return "*%="; case TokenIdBarBarEq: return "||="; - case TokenIdBracketUnderscoreBracket: return "[_]"; case TokenIdCount: zig_unreachable(); } diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 149e58b6a7fd2a1b59873a5e2a56d46e127d11b5..084512a5760594b1ddbbabde646d0939ee6712a8 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -28,9 +28,6 @@ enum TokenId { TokenIdBitShiftRight, TokenIdBitShiftRightEq, TokenIdBitXorEq, - TokenIdBracketStarBracket, - TokenIdBracketStarCBracket, - TokenIdBracketUnderscoreBracket, TokenIdCharLiteral, TokenIdCmpEq, TokenIdCmpGreaterOrEq, @@ -149,7 +146,6 @@ struct TokenIntLit { struct TokenStrLit { Buf str; - bool is_c_str; }; struct TokenCharLit { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 3acfb05e853ffa09aae2c095f8c6159378b1e978..3fe5fced07bc7956854b4ed157afab5b47e263dd 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -291,9 +291,9 @@ static TokenId ptr_len_to_token_id(PtrLen ptr_len) { case PtrLenSingle: return TokenIdStar; case PtrLenUnknown: - return TokenIdBracketStarBracket; + return TokenIdLBracket; case PtrLenC: - return TokenIdBracketStarCBracket; + return TokenIdSymbol; } zig_unreachable(); } @@ -321,17 +321,9 @@ static AstNode *trans_create_node_bool(Context *c, bool value) { return bool_node; } -static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { +static AstNode *trans_create_node_str_lit(Context *c, Buf *buf) { AstNode *node = trans_create_node(c, NodeTypeStringLiteral); node->data.string_literal.buf = buf; - node->data.string_literal.c = true; - return node; -} - -static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) { - AstNode *node = trans_create_node(c, NodeTypeStringLiteral); - node->data.string_literal.buf = buf; - node->data.string_literal.c = false; return node; } @@ -630,7 +622,7 @@ static AstNode *qual_type_to_log2_int_ref(Context *c, const ZigClangQualType qt, // zig_type_node AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); - import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std"))); + import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit(c, buf_create_from_str("std"))); AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); @@ -3389,7 +3381,7 @@ static AstNode *trans_string_literal(Context *c, ResultUsed result_used, TransSc case ZigClangStringLiteral_StringKind_UTF8: { size_t str_len; const char *str_ptr = ZigClangStringLiteral_getString_bytes_begin_size(stmt, &str_len); - AstNode *node = trans_create_node_str_lit_c(c, buf_create_from_mem(str_ptr, str_len)); + AstNode *node = trans_create_node_str_lit(c, buf_create_from_mem(str_ptr, str_len)); return maybe_suppress_result(c, result_used, node); } case ZigClangStringLiteral_StringKind_UTF16: @@ -4888,7 +4880,7 @@ static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok return trans_create_node_unsigned(c, tok->data.char_lit); case CTokIdStrLit: *tok_i += 1; - return trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit)); + return trans_create_node_str_lit(c, buf_create_from_buf(&tok->data.str_lit)); case CTokIdMinus: *tok_i += 1; return parse_ctok_num_lit(c, ctok, tok_i, true); @@ -4935,7 +4927,7 @@ static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok // (dest)(x) AstNode *import_builtin = trans_create_node_builtin_fn_call_str(c, "import"); - import_builtin->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("builtin"))); + import_builtin->data.fn_call_expr.params.append(trans_create_node_str_lit(c, buf_create_from_str("builtin"))); AstNode *typeid_type = trans_create_node_field_access_str(c, import_builtin, "TypeId"); AstNode *typeid_pointer = trans_create_node_field_access_str(c, typeid_type, "Pointer"); AstNode *typeid_integer = trans_create_node_field_access_str(c, typeid_type, "Int"); diff --git a/test/cli.zig b/test/cli.zig index 6095536422e4fa050ceda6c81a4fcd2cfc749797..e6d8d08e847187b808feb834c0d5b14eb64787cc 100644 --- a/test/cli.zig +++ b/test/cli.zig @@ -87,7 +87,7 @@ fn exec(cwd: []const u8, argv: []const []const u8) !ChildProcess.ExecResult { fn testZigInitLib(zig_exe: []const u8, dir_path: []const u8) !void { _ = try exec(dir_path, [_][]const u8{ zig_exe, "init-lib" }); const test_result = try exec(dir_path, [_][]const u8{ zig_exe, "build", "test" }); - testing.expect(std.mem.endsWith(u8, test_result.stderr, "All tests passed.\n")); + testing.expect(std.mem.endsWith(u8, test_result.stderr, "All 1 tests passed.\n")); } fn testZigInitExe(zig_exe: []const u8, dir_path: []const u8) !void { diff --git a/test/compare_output.zig b/test/compare_output.zig index 0842fc46298730d6aacaf3e9bd6dcdd382664cf6..1535d0ae5236ec5fd974d54fc256b71ef1ef65f2 100644 --- a/test/compare_output.zig +++ b/test/compare_output.zig @@ -7,7 +7,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { cases.addC("hello world with libc", \\const c = @cImport(@cInclude("stdio.h")); \\export fn main(argc: c_int, argv: [*][*]u8) c_int { - \\ _ = c.puts(c"Hello, world!"); + \\ _ = c.puts("Hello, world!"); \\ return 0; \\} , "Hello, world!" ++ std.cstr.line_sep); @@ -144,75 +144,75 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ // we want actual \n, not \r\n \\ _ = c._setmode(1, c._O_BINARY); \\ } - \\ _ = c.printf(c"0: %llu\n", + \\ _ = c.printf("0: %llu\n", \\ @as(u64, 0)); - \\ _ = c.printf(c"320402575052271: %llu\n", + \\ _ = c.printf("320402575052271: %llu\n", \\ @as(u64, 320402575052271)); - \\ _ = c.printf(c"0x01236789abcdef: %llu\n", + \\ _ = c.printf("0x01236789abcdef: %llu\n", \\ @as(u64, 0x01236789abcdef)); - \\ _ = c.printf(c"0xffffffffffffffff: %llu\n", + \\ _ = c.printf("0xffffffffffffffff: %llu\n", \\ @as(u64, 0xffffffffffffffff)); - \\ _ = c.printf(c"0x000000ffffffffffffffff: %llu\n", + \\ _ = c.printf("0x000000ffffffffffffffff: %llu\n", \\ @as(u64, 0x000000ffffffffffffffff)); - \\ _ = c.printf(c"0o1777777777777777777777: %llu\n", + \\ _ = c.printf("0o1777777777777777777777: %llu\n", \\ @as(u64, 0o1777777777777777777777)); - \\ _ = c.printf(c"0o0000001777777777777777777777: %llu\n", + \\ _ = c.printf("0o0000001777777777777777777777: %llu\n", \\ @as(u64, 0o0000001777777777777777777777)); - \\ _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", + \\ _ = c.printf("0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", \\ @as(u64, 0b1111111111111111111111111111111111111111111111111111111111111111)); - \\ _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", + \\ _ = c.printf("0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", \\ @as(u64, 0b0000001111111111111111111111111111111111111111111111111111111111111111)); \\ - \\ _ = c.printf(c"\n"); + \\ _ = c.printf("\n"); \\ - \\ _ = c.printf(c"0.0: %.013a\n", + \\ _ = c.printf("0.0: %.013a\n", \\ @as(f64, 0.0)); - \\ _ = c.printf(c"0e0: %.013a\n", + \\ _ = c.printf("0e0: %.013a\n", \\ @as(f64, 0e0)); - \\ _ = c.printf(c"0.0e0: %.013a\n", + \\ _ = c.printf("0.0e0: %.013a\n", \\ @as(f64, 0.0e0)); - \\ _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n", + \\ _ = c.printf("000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n", \\ @as(f64, 000000000000000000000000000000000000000000000000000000000.0e0)); - \\ _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n", + \\ _ = c.printf("0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n", \\ @as(f64, 0.000000000000000000000000000000000000000000000000000000000e0)); - \\ _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n", + \\ _ = c.printf("0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n", \\ @as(f64, 0.0e000000000000000000000000000000000000000000000000000000000)); - \\ _ = c.printf(c"1.0: %.013a\n", + \\ _ = c.printf("1.0: %.013a\n", \\ @as(f64, 1.0)); - \\ _ = c.printf(c"10.0: %.013a\n", + \\ _ = c.printf("10.0: %.013a\n", \\ @as(f64, 10.0)); - \\ _ = c.printf(c"10.5: %.013a\n", + \\ _ = c.printf("10.5: %.013a\n", \\ @as(f64, 10.5)); - \\ _ = c.printf(c"10.5e5: %.013a\n", + \\ _ = c.printf("10.5e5: %.013a\n", \\ @as(f64, 10.5e5)); - \\ _ = c.printf(c"10.5e+5: %.013a\n", + \\ _ = c.printf("10.5e+5: %.013a\n", \\ @as(f64, 10.5e+5)); - \\ _ = c.printf(c"50.0e-2: %.013a\n", + \\ _ = c.printf("50.0e-2: %.013a\n", \\ @as(f64, 50.0e-2)); - \\ _ = c.printf(c"50e-2: %.013a\n", + \\ _ = c.printf("50e-2: %.013a\n", \\ @as(f64, 50e-2)); \\ - \\ _ = c.printf(c"\n"); + \\ _ = c.printf("\n"); \\ - \\ _ = c.printf(c"0x1.0: %.013a\n", + \\ _ = c.printf("0x1.0: %.013a\n", \\ @as(f64, 0x1.0)); - \\ _ = c.printf(c"0x10.0: %.013a\n", + \\ _ = c.printf("0x10.0: %.013a\n", \\ @as(f64, 0x10.0)); - \\ _ = c.printf(c"0x100.0: %.013a\n", + \\ _ = c.printf("0x100.0: %.013a\n", \\ @as(f64, 0x100.0)); - \\ _ = c.printf(c"0x103.0: %.013a\n", + \\ _ = c.printf("0x103.0: %.013a\n", \\ @as(f64, 0x103.0)); - \\ _ = c.printf(c"0x103.7: %.013a\n", + \\ _ = c.printf("0x103.7: %.013a\n", \\ @as(f64, 0x103.7)); - \\ _ = c.printf(c"0x103.70: %.013a\n", + \\ _ = c.printf("0x103.70: %.013a\n", \\ @as(f64, 0x103.70)); - \\ _ = c.printf(c"0x103.70p4: %.013a\n", + \\ _ = c.printf("0x103.70p4: %.013a\n", \\ @as(f64, 0x103.70p4)); - \\ _ = c.printf(c"0x103.70p5: %.013a\n", + \\ _ = c.printf("0x103.70p5: %.013a\n", \\ @as(f64, 0x103.70p5)); - \\ _ = c.printf(c"0x103.70p+5: %.013a\n", + \\ _ = c.printf("0x103.70p+5: %.013a\n", \\ @as(f64, 0x103.70p+5)); - \\ _ = c.printf(c"0x103.70p-5: %.013a\n", + \\ _ = c.printf("0x103.70p-5: %.013a\n", \\ @as(f64, 0x103.70p-5)); \\ \\ return 0; @@ -323,7 +323,7 @@ pub fn addCases(cases: *tests.CompareOutputContext) void { \\ const x: f64 = small; \\ const y = @floatToInt(i32, x); \\ const z = @intToFloat(f64, y); - \\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, @as(f64, -0.4)); + \\ _ = c.printf("%.2f\n%d\n%.2f\n%.2f\n", x, y, z, @as(f64, -0.4)); \\ return 0; \\} , "3.25\n3\n3.00\n-0.40\n"); diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 9e47d2a458910a5887bc2383f263561203138126..dd0f80b255b07728569c95893b33f1a647510561 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,33 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "incompatible sentinels", + \\export fn entry1(ptr: [*:255]u8) [*:0]u8 { + \\ return ptr; + \\} + \\export fn entry2(ptr: [*]u8) [*:0]u8 { + \\ return ptr; + \\} + \\export fn entry3() void { + \\ var array: [2:0]u8 = [_:255]u8{1, 2}; + \\} + \\export fn entry4() void { + \\ var array: [2:0]u8 = [_]u8{1, 2}; + \\} + , + "tmp.zig:2:12: error: expected type '[*:0]u8', found '[*:255]u8'", + "tmp.zig:2:12: note: destination pointer requires a terminating '0' sentinel, but source pointer has a terminating '255' sentinel", + "tmp.zig:5:12: error: expected type '[*:0]u8', found '[*]u8'", + "tmp.zig:5:12: note: destination pointer requires a terminating '0' sentinel", + + "tmp.zig:8:35: error: expected type '[2:0]u8', found '[2:255]u8'", + "tmp.zig:8:35: note: destination array requires a terminating '0' sentinel, but source array has a terminating '255' sentinel", + "tmp.zig:11:31: error: expected type '[2:0]u8', found '[2]u8'", + "tmp.zig:11:31: note: destination array requires a terminating '0' sentinel", + + ); + cases.add( "empty switch on an integer", \\export fn entry() void { @@ -99,6 +126,18 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:9:27: error: @atomicRmw on enum only works with .Xchg", ); + cases.add( + "disallow coercion from non-null-terminated pointer to null-terminated pointer", + \\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 '[*:0]const u8', found '[*]const u8'", + ); + cases.add( "atomic orderings of atomicStore Acquire or AcqRel", \\export fn entry() void { @@ -183,7 +222,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "using an unknown len ptr type instead of array", \\const resolutions = [*][*]const u8{ - \\ c"[320 240 ]", + \\ "[320 240 ]", \\ null, \\}; \\comptime { @@ -800,10 +839,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "peer cast then implicit cast const pointer to mutable C pointer", \\export fn func() void { \\ var strValue: [*c]u8 = undefined; - \\ strValue = strValue orelse c""; + \\ strValue = strValue orelse ""; \\} , - "tmp.zig:3:32: error: cast discards const qualifier", + "tmp.zig:3:32: error: expected type '[*c]u8', found '*const [0:0]u8'", + "tmp.zig:3:32: note: cast discards const qualifier", ); cases.add( @@ -1134,7 +1174,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "libc headers note", \\const c = @cImport(@cInclude("stdio.h")); \\export fn entry() void { - \\ _ = c.printf(c"hello, world!\n"); + \\ _ = c.printf("hello, world!\n"); \\} , "tmp.zig:1:11: error: C import failed", @@ -1342,7 +1382,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ ptr_opt_many_ptr = c_ptr; \\} \\export fn entry2() void { - \\ var buf: [4]u8 = "aoeu"; + \\ var buf: [4]u8 = "aoeu".*; \\ var slice: []u8 = &buf; \\ var opt_many_ptr: [*]u8 = slice.ptr; \\ var ptr_opt_many_ptr = &opt_many_ptr; @@ -1537,7 +1577,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "reading past end of pointer casted array", \\comptime { - \\ const array = "aoeu"; + \\ const array: [4]u8 = "aoeu".*; \\ const slice = array[1..]; \\ const int_ptr = @ptrCast(*const u24, slice.ptr); \\ const deref = int_ptr.*; @@ -2460,12 +2500,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( @@ -3371,11 +3412,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "variable has wrong type", \\export fn f() i32 { - \\ const a = c"a"; + \\ const a = "a"; \\ return a; \\} , - "tmp.zig:3:12: error: expected type 'i32', found '[*]const u8'", + "tmp.zig:3:12: error: expected type 'i32', found '*const [1:0]u8'", ); cases.add( @@ -3846,12 +3887,12 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "array concatenation with wrong type", \\const src = "aoeu"; - \\const derp = @as(usize, 1234); + \\const derp: usize = 1234; \\const a = derp ++ "foo"; \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } , - "tmp.zig:3:11: error: expected array or C string literal, found 'usize'", + "tmp.zig:3:11: error: expected array, found 'usize'", ); cases.add( @@ -4805,7 +4846,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "assign through constant pointer", \\export fn f() void { - \\ var cstr = c"Hat"; + \\ var cstr = "Hat"; \\ cstr[0] = 'W'; \\} , @@ -6226,11 +6267,11 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { cases.add( "calling var args extern function, passing array instead of pointer", \\export fn entry() void { - \\ foo("hello",); + \\ foo("hello".*,); \\} \\pub extern fn foo(format: *const u8, ...) void; , - "tmp.zig:2:9: error: expected type '*const u8', found '[5]u8'", + "tmp.zig:2:16: error: expected type '*const u8', found '[5:0]u8'", ); cases.add( @@ -6796,7 +6837,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\} , "tmp.zig:4:22: error: expected type '*[1]i32', found '*const i32'", - "tmp.zig:4:22: note: pointer type child 'i32' cannot cast into pointer type child '[1]i32'", + "tmp.zig:4:22: note: cast discards const qualifier", ); cases.add( diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index 3a9c9a7655115d4fbbe15634d4b2e1dc6e58fe95..47e74cd310c3a94d4c2fe83e5cce719239d4b798 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -132,9 +132,16 @@ test "single-item pointer to array indexing and slicing" { } fn testSingleItemPtrArrayIndexSlice() void { - var array = "aaaa"; - doSomeMangling(&array); - expect(mem.eql(u8, "azya", array)); + { + var array: [4]u8 = "aaaa".*; + doSomeMangling(&array); + expect(mem.eql(u8, "azya", &array)); + } + { + var array = "aaaa".*; + doSomeMangling(&array); + expect(mem.eql(u8, "azya", &array)); + } } fn doSomeMangling(array: *[4]u8) void { @@ -294,9 +301,16 @@ test "read/write through global variable array of struct fields initialized via } test "implicit cast zero sized array ptr to slice" { - var b = ""; - const c: []const u8 = &b; - expect(c.len == 0); + { + var b = "".*; + const c: []const u8 = &b; + expect(c.len == 0); + } + { + var b: [0]u8 = "".*; + const c: []const u8 = &b; + expect(c.len == 0); + } } test "anonymous list literal syntax" { @@ -333,3 +347,16 @@ test "anonymous literal in array" { S.doTheTest(); comptime S.doTheTest(); } + +test "access the null element of a null terminated array" { + const S = struct { + fn doTheTest() void { + var array: [4:0]u8 = .{'a', 'o', 'e', 'u'}; + comptime expect(array[4] == 0); + var len: usize = 4; + expect(array[len] == 0); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/bugs/1076.zig b/test/stage1/behavior/bugs/1076.zig index 550ee9703a0fdab2193e8fb1b109662d2c7dc206..fa3caf0df813b776f2e53cbd4e76e672761c8aed 100644 --- a/test/stage1/behavior/bugs/1076.zig +++ b/test/stage1/behavior/bugs/1076.zig @@ -8,8 +8,16 @@ test "comptime code should not modify constant data" { } fn testCastPtrOfArrayToSliceAndPtr() void { - var array = "aoeu"; - const x: [*]u8 = &array; - x[0] += 1; - expect(mem.eql(u8, array[0..], "boeu")); + { + var array = "aoeu".*; + const x: [*]u8 = &array; + x[0] += 1; + expect(mem.eql(u8, array[0..], "boeu")); + } + { + var array: [4]u8 = "aoeu".*; + const x: [*]u8 = &array; + x[0] += 1; + expect(mem.eql(u8, array[0..], "boeu")); + } } diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 98d987a73f2126893cf3841e5f6a74db7083d4b9..fec4494ad9f01a29fd658eae19ebc6c129d64b41 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -179,18 +179,24 @@ fn gimmeErrOrSlice() anyerror![]u8 { } test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { - { - var data = "hi"; - const slice = data[0..]; - expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } - comptime { - var data = "hi"; - const slice = data[0..]; - expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } + const S = struct { + fn doTheTest() anyerror!void { + { + var data = "hi".*; + const slice = data[0..]; + expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + } + { + var data: [2]u8 = "hi".*; + const slice = data[0..]; + expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); + expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); + } + } + }; + try S.doTheTest(); + try comptime S.doTheTest(); } fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { if (a) { @@ -217,11 +223,20 @@ test "implicit cast from &const [N]T to []const T" { } fn testCastConstArrayRefToConstSlice() void { - const blah = "aoeu"; - const const_array_ref = &blah; - expect(@typeOf(const_array_ref) == *const [4]u8); - const slice: []const u8 = const_array_ref; - expect(mem.eql(u8, slice, "aoeu")); + { + const blah = "aoeu".*; + const const_array_ref = &blah; + expect(@typeOf(const_array_ref) == *const [4:0]u8); + const slice: []const u8 = const_array_ref; + expect(mem.eql(u8, slice, "aoeu")); + } + { + const blah: [4]u8 = "aoeu".*; + const const_array_ref = &blah; + expect(@typeOf(const_array_ref) == *const [4]u8); + const slice: []const u8 = const_array_ref; + expect(mem.eql(u8, slice, "aoeu")); + } } test "peer type resolution: error and [N]T" { @@ -310,19 +325,30 @@ test "single-item pointer of array to slice and to unknown length pointer" { } fn testCastPtrOfArrayToSliceAndPtr() void { - var array = "aoeu"; - const x: [*]u8 = &array; - x[0] += 1; - expect(mem.eql(u8, array[0..], "boeu")); - const y: []u8 = &array; - y[0] += 1; - expect(mem.eql(u8, array[0..], "coeu")); + { + var array = "aoeu".*; + const x: [*]u8 = &array; + x[0] += 1; + expect(mem.eql(u8, array[0..], "boeu")); + const y: []u8 = &array; + y[0] += 1; + expect(mem.eql(u8, array[0..], "coeu")); + } + { + var array: [4]u8 = "aoeu".*; + const x: [*]u8 = &array; + x[0] += 1; + expect(mem.eql(u8, array[0..], "boeu")); + const y: []u8 = &array; + y[0] += 1; + expect(mem.eql(u8, array[0..], "coeu")); + } } 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; - expect(mem.eql(u8, std.mem.toSliceConst(u8, x[0].?), "window name")); + expect(mem.eql(u8, std.mem.toSliceConst(u8, @ptrCast([*:0]const u8, x[0].?)), "window name")); } test "@intCast comptime_int" { @@ -545,7 +571,7 @@ test "implicit cast *[0]T to E![]const u8" { } test "peer cast *[0]T to E![]const T" { - var buffer: [5]u8 = "abcde"; + var buffer: [5]u8 = "abcde".*; var buf: anyerror![]const u8 = buffer[0..]; var b = false; var y = if (b) &[0]u8{} else buf; @@ -553,7 +579,7 @@ test "peer cast *[0]T to E![]const T" { } test "peer cast *[0]T to []const T" { - var buffer: [5]u8 = "abcde"; + var buffer: [5]u8 = "abcde".*; var buf: []const u8 = buffer[0..]; var b = false; var y = if (b) &[0]u8{} else buf; @@ -565,3 +591,86 @@ test "cast from array reference to fn" { const f = @ptrCast(extern fn () void, &global_array); expect(@ptrToInt(f) == @ptrToInt(&global_array)); } + +test "*const [N]null u8 to ?[]const u8" { + const S = struct { + fn doTheTest() void { + var a = "Hello"; + var b: ?[]const u8 = a; + expect(mem.eql(u8, b.?, "Hello")); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "peer resolution of string literals" { + const S = struct { + const E = extern enum { a, b, c, d}; + + fn doTheTest(e: E) void { + const cmd = switch (e) { + .a => "one", + .b => "two", + .c => "three", + .d => "four", + }; + expect(mem.eql(u8, cmd, "two")); + } + }; + S.doTheTest(.b); + comptime S.doTheTest(.b); +} + +test "type coercion related to sentinel-termination" { + const S = struct { + fn doTheTest() void { + // [:x]T to []T + { + var array = [4:0]i32{1,2,3,4}; + var slice: [:0]i32 = &array; + var dest: []i32 = slice; + expect(mem.eql(i32, dest, &[_]i32{1,2,3,4})); + } + + // [*:x]T to [*]T + { + var array = [4:99]i32{1,2,3,4}; + var dest: [*]i32 = &array; + expect(dest[0] == 1); + expect(dest[1] == 2); + expect(dest[2] == 3); + expect(dest[3] == 4); + expect(dest[4] == 99); + } + + // [N:x]T to [N]T + { + var array = [4:0]i32{1,2,3,4}; + var dest: [4]i32 = array; + expect(mem.eql(i32, dest, &[_]i32{1,2,3,4})); + } + + // *[N:x]T to *[N]T + { + var array = [4:0]i32{1,2,3,4}; + var dest: *[4]i32 = &array; + expect(mem.eql(i32, dest, &[_]i32{1,2,3,4})); + } + + // [:x]T to [*:x]T + { + var array = [4:0]i32{1,2,3,4}; + var slice: [:0]i32 = &array; + var dest: [*:0]i32 = slice; + expect(dest[0] == 1); + expect(dest[1] == 2); + expect(dest[2] == 3); + expect(dest[3] == 4); + expect(dest[4] == 0); + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/const_slice_child.zig b/test/stage1/behavior/const_slice_child.zig index 13713e1ee781b3b0ef71ca7eca022d3a29ffb5f6..6720667187c5434de124fa0e0e1ebc96c2393140 100644 --- a/test/stage1/behavior/const_slice_child.zig +++ b/test/stage1/behavior/const_slice_child.zig @@ -6,12 +6,11 @@ var argv: [*]const [*]const u8 = undefined; test "const slice child" { const strs = [_][*]const u8{ - c"one", - c"two", - c"three", + "one", + "two", + "three", }; - // TODO this should implicitly cast - argv = @ptrCast([*]const [*]const u8, &strs); + argv = &strs; bar(strs.len); } diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index fa899d0cb212fb34c7c072c642752090ef7373b1..b7bce26568fa256dbb33e7ea86560645966c437f 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -736,7 +736,7 @@ test "comptime pointer cast array and then slice" { test "slice bounds in comptime concatenation" { const bs = comptime blk: { - const b = c"........1........"; + const b = "........1........"; break :blk b[8..9]; }; const str = "" ++ bs; diff --git a/test/stage1/behavior/if.zig b/test/stage1/behavior/if.zig index 9e93ceb656c7e512b209eed49b9ec4351e8c6f06..63c31fb03ee8dbc4c3b1583c0eac8a82a784eeaa 100644 --- a/test/stage1/behavior/if.zig +++ b/test/stage1/behavior/if.zig @@ -81,6 +81,10 @@ test "if prongs cast to expected type instead of peer type resolution" { var x: i32 = 0; x = if (f) 1 else 2; expect(x == 2); + + var b = true; + const y: i32 = if (b) 1 else 2; + expect(y == 1); } }; S.doTheTest(false); diff --git a/test/stage1/behavior/misc.zig b/test/stage1/behavior/misc.zig index 1a227a5b935cbbf7e2d7ad3917af384757b25a60..6ac745f5c50b478102eb59e505cc3e0318230c8c 100644 --- a/test/stage1/behavior/misc.zig +++ b/test/stage1/behavior/misc.zig @@ -204,11 +204,11 @@ test "multiline string" { test "multiline C string" { const s1 = - c\\one - c\\two) - c\\three + \\one + \\two) + \\three ; - const s2 = c"one\ntwo)\nthree"; + const s2 = "one\ntwo)\nthree"; expect(std.cstr.cmp(s1, s2) == 0); } @@ -358,9 +358,12 @@ fn ptrEql(a: *const []const u8, b: *const []const u8) bool { return a == b; } -test "C string concatenation" { - const a = c"OK" ++ c" IT " ++ c"WORKED"; - const b = c"OK IT WORKED"; +test "string concatenation" { + const a = "OK" ++ " IT " ++ "WORKED"; + const b = "OK IT WORKED"; + + comptime expect(@typeOf(a) == *const [12:0]u8); + comptime expect(@typeOf(b) == *const [12:0]u8); const len = mem.len(u8, b); const len_with_null = len + 1; diff --git a/test/stage1/behavior/pointers.zig b/test/stage1/behavior/pointers.zig index bf292bad0d27da9281cd9486e7ce2491024b5b98..58a46b539c3ce6d5a58cab934fb01f6f57fcf5de 100644 --- a/test/stage1/behavior/pointers.zig +++ b/test/stage1/behavior/pointers.zig @@ -15,7 +15,7 @@ fn testDerefPtr() void { } test "pointer arithmetic" { - var ptr = c"abcd"; + var ptr: [*]const u8 = "abcd"; expect(ptr[0] == 'a'); ptr += 1; @@ -200,3 +200,65 @@ test "assign null directly to C pointer and test null equality" { } comptime expect((y1 orelse &othery) == y1); } + +test "null terminated pointer" { + const S = struct { + fn doTheTest() void { + var array_with_zero = [_:0]u8{'h', 'e', 'l', 'l', 'o'}; + var zero_ptr: [*:0]const u8 = @ptrCast([*:0]const u8, &array_with_zero); + var no_zero_ptr: [*]const u8 = zero_ptr; + var zero_ptr_again = @ptrCast([*:0]const u8, no_zero_ptr); + expect(std.mem.eql(u8, std.mem.toSliceConst(u8, zero_ptr_again), "hello")); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "allow any sentinel" { + const S = struct { + fn doTheTest() void { + var array = [_:std.math.minInt(i32)]i32{1, 2, 3, 4}; + var ptr: [*:std.math.minInt(i32)]i32 = &array; + expect(ptr[4] == std.math.minInt(i32)); + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "pointer sentinel with enums" { + const S = struct { + const Number = enum{one, two, sentinel}; + + fn doTheTest() void { + var ptr: [*:.sentinel]Number = &[_:.sentinel]Number{.one, .two, .two, .one}; + expect(ptr[4] == .sentinel); // TODO this should be comptime expect, see #3731 + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "pointer sentinel with optional element" { + const S = struct { + fn doTheTest() void { + var ptr: [*:null]?i32 = &[_:null]?i32{1, 2, 3, 4}; + expect(ptr[4] == null); // TODO this should be comptime expect, see #3731 + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +test "pointer sentinel with +inf" { + const S = struct { + fn doTheTest() void { + const inf = std.math.inf_f32; + var ptr: [*:inf]f32 = &[_:inf]f32{1.1, 2.2, 3.3, 4.4}; + expect(ptr[4] == inf); // TODO this should be comptime expect, see #3731 + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index bf928882146e050a3d5d62aab70b2b5806998866..ddb5a63eeeb5d05896216ce04138f976e04f21f2 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -60,7 +60,7 @@ test "comptime ptrcast keeps larger alignment" { } test "implicit optional pointer to optional c_void pointer" { - var buf: [4]u8 = "aoeu"; + var buf: [4]u8 = "aoeu".*; var x: ?[*]u8 = &buf; var y: ?*c_void = x; var z = @ptrCast(*[4]u8, y); diff --git a/test/stage1/behavior/slice.zig b/test/stage1/behavior/slice.zig index d4a8353ca726bd64e8d196408cfaa8033207e1e1..3c394e39a164fa2780fd45280a2dd1531153e8c5 100644 --- a/test/stage1/behavior/slice.zig +++ b/test/stage1/behavior/slice.zig @@ -36,7 +36,7 @@ fn assertLenIsZero(msg: []const u8) void { } test "C pointer" { - var buf: [*c]const u8 = c"kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; + var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf"; var len: u32 = 10; var slice = buf[0..len]; expectEqualSlices(u8, "kjdhfkjdhf", slice); @@ -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(); +} diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 722f44d352e28742396575e7ffb2b69b20d1c4db..7c2e58f2cb68b5fb30d698a91db1feeb0a6d0e49 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -493,7 +493,7 @@ test "non-byte-aligned array inside packed struct" { fn doTheTest() void { var foo = Foo{ .a = true, - .b = "abcdefghijklmnopqurstu", + .b = "abcdefghijklmnopqurstu".*, }; bar(foo.b); } @@ -777,3 +777,16 @@ test "anonymous struct literal assigned to variable" { vec.@"1" += 1; expect(vec.@"1" == 56); } + +test "struct with var field" { + const Point = struct { + x: var, + y: var, + }; + const pt = Point { + .x = 1, + .y = 2, + }; + expect(pt.x == 1); + expect(pt.y == 2); +} diff --git a/test/stage1/behavior/type.zig b/test/stage1/behavior/type.zig index b84369a16490dfbfd6b2ecaa0a06ca3062484e56..f083359d1d57a44d9d1da3ae99423d244eb74cfe 100644 --- a/test/stage1/behavior/type.zig +++ b/test/stage1/behavior/type.zig @@ -11,103 +11,122 @@ fn testTypes(comptime types: []const type) void { } test "Type.MetaType" { - testing.expect(type == @Type(TypeInfo { .Type = undefined })); - testTypes([_]type {type}); + testing.expect(type == @Type(TypeInfo{ .Type = undefined })); + testTypes([_]type{type}); } test "Type.Void" { - testing.expect(void == @Type(TypeInfo { .Void = undefined })); - testTypes([_]type {void}); + testing.expect(void == @Type(TypeInfo{ .Void = undefined })); + testTypes([_]type{void}); } test "Type.Bool" { - testing.expect(bool == @Type(TypeInfo { .Bool = undefined })); - testTypes([_]type {bool}); + testing.expect(bool == @Type(TypeInfo{ .Bool = undefined })); + testTypes([_]type{bool}); } test "Type.NoReturn" { - testing.expect(noreturn == @Type(TypeInfo { .NoReturn = undefined })); - testTypes([_]type {noreturn}); + testing.expect(noreturn == @Type(TypeInfo{ .NoReturn = undefined })); + testTypes([_]type{noreturn}); } test "Type.Int" { - testing.expect(u1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 1 } })); - testing.expect(i1 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 1 } })); - testing.expect(u8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 8 } })); - testing.expect(i8 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 8 } })); - testing.expect(u64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = false, .bits = 64 } })); - testing.expect(i64 == @Type(TypeInfo { .Int = TypeInfo.Int { .is_signed = true, .bits = 64 } })); - testTypes([_]type {u8,u32,i64}); + testing.expect(u1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 1 } })); + testing.expect(i1 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 1 } })); + testing.expect(u8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 8 } })); + testing.expect(i8 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 8 } })); + testing.expect(u64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = false, .bits = 64 } })); + testing.expect(i64 == @Type(TypeInfo{ .Int = TypeInfo.Int{ .is_signed = true, .bits = 64 } })); + testTypes([_]type{ u8, u32, i64 }); } test "Type.Float" { - testing.expect(f16 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 16 } })); - testing.expect(f32 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 32 } })); - testing.expect(f64 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 64 } })); - testing.expect(f128 == @Type(TypeInfo { .Float = TypeInfo.Float { .bits = 128 } })); - testTypes([_]type {f16, f32, f64, f128}); + testing.expect(f16 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 16 } })); + testing.expect(f32 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 32 } })); + testing.expect(f64 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 64 } })); + testing.expect(f128 == @Type(TypeInfo{ .Float = TypeInfo.Float{ .bits = 128 } })); + testTypes([_]type{ f16, f32, f64, f128 }); } test "Type.Pointer" { - testTypes([_]type { + testTypes([_]type{ // One Value Pointer Types - *u8, *const u8, - *volatile u8, *const volatile u8, - *align(4) u8, *const align(4) u8, - *volatile align(4) u8, *const volatile align(4) u8, - *align(8) u8, *const align(8) u8, - *volatile align(8) u8, *const volatile align(8) u8, - *allowzero u8, *const allowzero u8, - *volatile allowzero u8, *const volatile allowzero u8, - *align(4) allowzero u8, *const align(4) allowzero u8, - *volatile align(4) allowzero u8, *const volatile align(4) allowzero u8, + *u8, *const u8, + *volatile u8, *const volatile u8, + *align(4) u8, *align(4) const u8, + *align(4) volatile u8, *align(4) const volatile u8, + *align(8) u8, *align(8) const u8, + *align(8) volatile u8, *align(8) const volatile u8, + *allowzero u8, *allowzero const u8, + *allowzero volatile u8, *allowzero const volatile u8, + *allowzero align(4) u8, *allowzero align(4) const u8, + *allowzero align(4) volatile u8, *allowzero align(4) const volatile u8, // Many Values Pointer Types - [*]u8, [*]const u8, - [*]volatile u8, [*]const volatile u8, - [*]align(4) u8, [*]const align(4) u8, - [*]volatile align(4) u8, [*]const volatile align(4) u8, - [*]align(8) u8, [*]const align(8) u8, - [*]volatile align(8) u8, [*]const volatile align(8) u8, - [*]allowzero u8, [*]const allowzero u8, - [*]volatile allowzero u8, [*]const volatile allowzero u8, - [*]align(4) allowzero u8, [*]const align(4) allowzero u8, - [*]volatile align(4) allowzero u8, [*]const volatile align(4) allowzero u8, + [*]u8, [*]const u8, + [*]volatile u8, [*]const volatile u8, + [*]align(4) u8, [*]align(4) const u8, + [*]align(4) volatile u8, [*]align(4) const volatile u8, + [*]align(8) u8, [*]align(8) const u8, + [*]align(8) volatile u8, [*]align(8) const volatile u8, + [*]allowzero u8, [*]allowzero const u8, + [*]allowzero volatile u8, [*]allowzero const volatile u8, + [*]allowzero align(4) u8, [*]allowzero align(4) const u8, + [*]allowzero align(4) volatile u8, [*]allowzero align(4) const volatile u8, // Slice Types - []u8, []const u8, - []volatile u8, []const volatile u8, - []align(4) u8, []const align(4) u8, - []volatile align(4) u8, []const volatile align(4) u8, - []align(8) u8, []const align(8) u8, - []volatile align(8) u8, []const volatile align(8) u8, - []allowzero u8, []const allowzero u8, - []volatile allowzero u8, []const volatile allowzero u8, - []align(4) allowzero u8, []const align(4) allowzero u8, - []volatile align(4) allowzero u8, []const volatile align(4) allowzero u8, + []u8, []const u8, + []volatile u8, []const volatile u8, + []align(4) u8, []align(4) const u8, + []align(4) volatile u8, []align(4) const volatile u8, + []align(8) u8, []align(8) const u8, + []align(8) volatile u8, []align(8) const volatile u8, + []allowzero u8, []allowzero const u8, + []allowzero volatile u8, []allowzero const volatile u8, + []allowzero align(4) u8, []allowzero align(4) const u8, + []allowzero align(4) volatile u8, []allowzero align(4) const volatile u8, // C Pointer Types - [*c]u8, [*c]const u8, - [*c]volatile u8, [*c]const volatile u8, - [*c]align(4) u8, [*c]const align(4) u8, - [*c]volatile align(4) u8, [*c]const volatile align(4) u8, - [*c]align(8) u8, [*c]const align(8) u8, - [*c]volatile align(8) u8, [*c]const volatile align(8) u8, + [*c]u8, [*c]const u8, + [*c]volatile u8, [*c]const volatile u8, + [*c]align(4) u8, [*c]align(4) const u8, + [*c]align(4) volatile u8, [*c]align(4) const volatile u8, + [*c]align(8) u8, [*c]align(8) const u8, + [*c]align(8) volatile u8, [*c]align(8) const volatile u8, }); } test "Type.Array" { - testing.expect([123]u8 == @Type(TypeInfo { .Array = TypeInfo.Array { .len = 123, .child = u8 } })); - testing.expect([2]u32 == @Type(TypeInfo { .Array = TypeInfo.Array { .len = 2, .child = u32 } })); - testTypes([_]type {[1]u8, [30]usize, [7]bool}); + testing.expect([123]u8 == @Type(TypeInfo{ + .Array = TypeInfo.Array{ + .len = 123, + .child = u8, + .sentinel = null, + }, + })); + testing.expect([2]u32 == @Type(TypeInfo{ + .Array = TypeInfo.Array{ + .len = 2, + .child = u32, + .sentinel = null, + }, + })); + testing.expect([2:0]u32 == @Type(TypeInfo{ + .Array = TypeInfo.Array{ + .len = 2, + .child = u32, + .sentinel = 0, + }, + })); + testTypes([_]type{ [1]u8, [30]usize, [7]bool }); } test "Type.ComptimeFloat" { - testTypes([_]type {comptime_float}); + testTypes([_]type{comptime_float}); } test "Type.ComptimeInt" { - testTypes([_]type {comptime_int}); + testTypes([_]type{comptime_int}); } test "Type.Undefined" { - testTypes([_]type {@typeOf(undefined)}); + testTypes([_]type{@typeOf(undefined)}); } test "Type.Null" { - testTypes([_]type {@typeOf(null)}); + testTypes([_]type{@typeOf(null)}); } diff --git a/test/stage1/behavior/type_info.zig b/test/stage1/behavior/type_info.zig index ed64e3e4300622502e4ca8d20283704121451eb7..598bbca6bee3bdc48c30dc9abec0ee27dfb643e8 100644 --- a/test/stage1/behavior/type_info.zig +++ b/test/stage1/behavior/type_info.zig @@ -46,6 +46,7 @@ fn testPointer() void { expect(u32_ptr_info.Pointer.is_volatile == false); expect(u32_ptr_info.Pointer.alignment == @alignOf(u32)); expect(u32_ptr_info.Pointer.child == u32); + expect(u32_ptr_info.Pointer.sentinel == null); } test "type info: unknown length pointer type info" { @@ -55,14 +56,34 @@ test "type info: unknown length pointer type info" { fn testUnknownLenPtr() void { const u32_ptr_info = @typeInfo([*]const volatile f64); - expect(@as(TypeId,u32_ptr_info) == TypeId.Pointer); + expect(@as(TypeId, u32_ptr_info) == TypeId.Pointer); expect(u32_ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); expect(u32_ptr_info.Pointer.is_const == true); expect(u32_ptr_info.Pointer.is_volatile == true); + expect(u32_ptr_info.Pointer.sentinel == null); expect(u32_ptr_info.Pointer.alignment == @alignOf(f64)); expect(u32_ptr_info.Pointer.child == f64); } +test "type info: null terminated pointer type info" { + testNullTerminatedPtr(); + comptime testNullTerminatedPtr(); +} + +fn testNullTerminatedPtr() void { + const ptr_info = @typeInfo([*:0]u8); + expect(@as(TypeId, ptr_info) == TypeId.Pointer); + expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.Many); + expect(ptr_info.Pointer.is_const == false); + expect(ptr_info.Pointer.is_volatile == false); + expect(ptr_info.Pointer.sentinel.? == 0); + + expect(@typeInfo([:0]u8).Pointer.sentinel != null); + expect(@typeInfo([10:0]u8).Array.sentinel != null); + expect(@typeInfo([10:0]u8).Array.len == 10); + expect(@sizeOf([10:0]u8) == 11); +} + test "type info: C pointer type info" { testCPtr(); comptime testCPtr(); @@ -70,7 +91,7 @@ test "type info: C pointer type info" { fn testCPtr() void { const ptr_info = @typeInfo([*c]align(4) const i8); - expect(@as(TypeId,ptr_info) == TypeId.Pointer); + expect(@as(TypeId, ptr_info) == TypeId.Pointer); expect(ptr_info.Pointer.size == TypeInfo.Pointer.Size.C); expect(ptr_info.Pointer.is_const); expect(!ptr_info.Pointer.is_volatile); @@ -288,13 +309,13 @@ test "type info: anyframe and anyframe->T" { fn testAnyFrame() void { { const anyframe_info = @typeInfo(anyframe->i32); - expect(@as(TypeId,anyframe_info) == .AnyFrame); + expect(@as(TypeId, anyframe_info) == .AnyFrame); expect(anyframe_info.AnyFrame.child.? == i32); } { const anyframe_info = @typeInfo(anyframe); - expect(@as(TypeId,anyframe_info) == .AnyFrame); + expect(@as(TypeId, anyframe_info) == .AnyFrame); expect(anyframe_info.AnyFrame.child == null); } } @@ -334,7 +355,7 @@ test "type info: extern fns with and without lib names" { if (std.mem.eql(u8, decl.name, "bar1")) { expect(decl.data.Fn.lib_name == null); } else { - std.testing.expectEqual(@as([]const u8,"cool"), decl.data.Fn.lib_name.?); + std.testing.expectEqual(@as([]const u8, "cool"), decl.data.Fn.lib_name.?); } } } diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index 70688aa09cf875850cce7211b810aaec1d8c710b..f9de9fecb7f4665cf9bc4739663981f88ba3280b 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -119,7 +119,7 @@ export fn zig_bool(x: bool) void { extern fn c_array([10]u8) void; test "C ABI array" { - var array: [10]u8 = "1234567890"; + var array: [10]u8 = "1234567890".*; c_array(array); } diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index fdc3d491450fae26cb35f0864bfd8dc0ed260da4..a86811b27b4ea9ca60a96278fb2a5bf2a75b4282 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -6,7 +6,7 @@ pub fn addCases(ctx: *TestContext) !void { try ctx.testCompareOutputLibC( \\extern fn puts([*]const u8) void; \\export fn main() c_int { - \\ puts(c"Hello, world!"); + \\ puts("Hello, world!"); \\ return 0; \\} , "Hello, world!" ++ std.cstr.line_sep); @@ -15,7 +15,7 @@ pub fn addCases(ctx: *TestContext) !void { try ctx.testCompareOutputLibC( \\extern fn puts(s: [*]const u8) void; \\export fn main() c_int { - \\ return foo(c"OK"); + \\ return foo("OK"); \\} \\fn foo(s: [*]const u8) c_int { \\ puts(s); diff --git a/test/standalone/hello_world/hello_libc.zig b/test/standalone/hello_world/hello_libc.zig index 05356bf5294f5f61986738fd770ec770c2c59100..c6f290f70ee976134eb280ecbbccef9f0e6087e8 100644 --- a/test/standalone/hello_world/hello_libc.zig +++ b/test/standalone/hello_world/hello_libc.zig @@ -5,7 +5,7 @@ const c = @cImport({ @cInclude("string.h"); }); -const msg = c"Hello, world!\n"; +const msg = "Hello, world!\n"; export fn main(argc: c_int, argv: **u8) c_int { if (c.printf(msg) != @intCast(c_int, c.strlen(msg))) return -1; diff --git a/test/translate_c.zig b/test/translate_c.zig index f78e2181ebad9eac3d56570e88195724d423a4b7..f543fbc74e35f531d7d66b78ff41c96cef1b7050 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -47,7 +47,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn foo() void { \\ var a: c_int = undefined; \\ _ = 1; - \\ _ = c"hey"; + \\ _ = "hey"; \\ _ = (1 + 1); \\ _ = (1 - 1); \\ a = 1; @@ -213,9 +213,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub fn foo() void { - \\ _ = c"foo"; - \\ _ = c"foo"; - \\ _ = c"void foo(void)"; + \\ _ = "foo"; + \\ _ = "foo"; + \\ _ = "void foo(void)"; \\} ); @@ -232,7 +232,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub fn foo() void { \\ var a: c_int = undefined; \\ _ = 1; - \\ _ = c"hey"; + \\ _ = "hey"; \\ _ = (1 + 1); \\ _ = (1 - 1); \\ a = 1; @@ -543,7 +543,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("#define string", \\#define foo "a string" , - \\pub const foo = c"a string"; + \\pub const foo = "a string"; ); cases.add("__cdecl doesn't mess up function pointers", @@ -617,9 +617,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define FOO2 "aoeu\x0007a derp" \\#define FOO_CHAR '\xfF' , - \\pub const FOO = c"aoeu\xab derp"; + \\pub const FOO = "aoeu\xab derp"; , - \\pub const FOO2 = c"aoeuz derp"; + \\pub const FOO2 = "aoeuz derp"; , \\pub const FOO_CHAR = 255; ); @@ -629,9 +629,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define FOO2 "aoeu\0234 derp" \\#define FOO_CHAR '\077' , - \\pub const FOO = c"aoeu\x13 derp"; + \\pub const FOO = "aoeu\x13 derp"; , - \\pub const FOO2 = c"aoeu\x134 derp"; + \\pub const FOO2 = "aoeu\x134 derp"; , \\pub const FOO_CHAR = 63; ); @@ -1351,7 +1351,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub fn foo() [*c]const u8 { - \\ return c"bar"; + \\ return "bar"; \\} ); @@ -1523,7 +1523,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { cases.add("const ptr initializer", \\static const char *v0 = "0.0.0"; , - \\pub var v0: [*c]const u8 = c"0.0.0"; + \\pub var v0: [*c]const u8 = "0.0.0"; ); cases.add("static incomplete array inside function", @@ -1532,7 +1532,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} , \\pub fn foo() void { - \\ const v2: [*c]const u8 = c"2.2.2"; + \\ const v2: [*c]const u8 = "2.2.2"; \\} ); @@ -1809,7 +1809,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ var i: u8 = @as(u8, '\x0b'); \\ var j: u8 = @as(u8, '\x00'); \\ var k: u8 = @as(u8, '\"'); - \\ return c"\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; + \\ return "\'\\\x07\x08\x0c\n\r\t\x0b\x00\""; \\} \\ );