Commit 8a859afd58
Changed files (18)
src/ir.cpp
@@ -8536,14 +8536,6 @@ static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstruct
if (!ir_resolve_bool(ira, condition, &cond_is_true))
return ir_unreach_error(ira);
- if (!cond_br_instruction->base.is_gen && !condition->value.depends_on_compile_var &&
- !ir_should_inline(ira->new_irb.exec, cond_br_instruction->base.scope))
- {
- const char *true_or_false = cond_is_true ? "true" : "false";
- ir_add_error(ira, &cond_br_instruction->base,
- buf_sprintf("condition is always %s; unnecessary if statement", true_or_false));
- }
-
IrBasicBlock *old_dest_block = cond_is_true ?
cond_br_instruction->then_block : cond_br_instruction->else_block;
@@ -9060,7 +9052,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
bool ptr_is_const = true;
bool ptr_is_volatile = false;
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
- usize, false, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
+ usize, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
} else {
ir_add_error_node(ira, source_node,
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
@@ -9084,7 +9076,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
bool ptr_is_const = true;
bool ptr_is_volatile = false;
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, len_val,
- usize, false, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
+ usize, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const, ptr_is_volatile);
} else {
ir_add_error_node(ira, source_node,
buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
std/elf.zig
@@ -1,5 +1,4 @@
const io = @import("io.zig");
-const str = @import("str.zig");
const math = @import("math.zig");
const mem = @import("mem.zig");
const debug = @import("debug.zig");
@@ -95,7 +94,7 @@ pub const Elf = struct {
var magic: [4]u8 = undefined;
%return elf.in_stream.readNoEof(magic);
- if (!str.eql(magic, "\x7fELF")) return error.InvalidFormat;
+ if (!mem.eql(magic, "\x7fELF")) return error.InvalidFormat;
elf.is_64 = switch (%return elf.in_stream.readByte()) {
1 => false,
std/index.zig
@@ -2,7 +2,6 @@ pub const rand = @import("rand.zig");
pub const io = @import("io.zig");
pub const os = @import("os.zig");
pub const math = @import("math.zig");
-pub const str = @import("str.zig");
pub const cstr = @import("cstr.zig");
pub const sort = @import("sort.zig");
pub const net = @import("net.zig");
std/io.zig
@@ -61,8 +61,8 @@ error Unseekable;
error Eof;
const buffer_size = 4 * 1024;
-const max_u64_base10_digits = 20;
const max_f64_digits = 65;
+const max_int_digits = 65;
pub const OpenRead = 0b0001;
pub const OpenWrite = 0b0010;
@@ -100,6 +100,7 @@ pub const OutStream = struct {
Start,
OpenBrace,
CloseBrace,
+ Hex: bool,
};
/// Calls print and then flushes the buffer.
@@ -131,6 +132,12 @@ pub const OutStream = struct {
state = State.Start;
start_index = i + 1;
},
+ 'x' => {
+ state = State.Hex { false };
+ },
+ 'X' => {
+ state = State.Hex { true };
+ },
else => @compileError("Unknown format character: " ++ c),
},
State.CloseBrace => switch (c) {
@@ -140,14 +147,25 @@ pub const OutStream = struct {
},
else => @compileError("Single '}' encountered in format string"),
},
+ State.Hex => |uppercase| switch (c) {
+ '}' => {
+ self.printInt(args[next_arg], 16, uppercase);
+ next_arg += 1;
+ state = State.Start;
+ start_index = i + 1;
+ },
+ else => @compileError("Expected '}' after 'x'/'X' in format string"),
+ },
}
}
comptime {
if (args.len != next_arg) {
@compileError("Unused arguments");
}
- if (state != State.Start) {
- @compileError("Incomplete format string: " ++ format);
+ // TODO https://github.com/andrewrk/zig/issues/253
+ switch (state) {
+ State.Start => {},
+ else => @compileError("Incomplete format string: " ++ format),
}
}
if (start_index < format.len) {
@@ -159,7 +177,7 @@ pub const OutStream = struct {
pub fn printValue(self: &OutStream, value: var) -> %void {
const T = @typeOf(value);
if (@isInteger(T)) {
- return self.printInt(T, value);
+ return self.printInt(value, 10, false);
} else if (@isFloat(T)) {
return self.printFloat(T, value);
} else if (@canImplicitCast([]const u8, value)) {
@@ -172,12 +190,11 @@ pub const OutStream = struct {
}
}
- pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %void {
- // TODO replace max_u64_base10_digits with math.log10(math.pow(2, @sizeOf(T)))
- if (self.index + max_u64_base10_digits >= self.buffer.len) {
+ pub fn printInt(self: &OutStream, x: var, base: u8, uppercase: bool) -> %void {
+ if (self.index + max_int_digits >= self.buffer.len) {
%return self.flush();
}
- const amt_printed = bufPrintInt(T, self.buffer[self.index...], x);
+ const amt_printed = bufPrintInt(self.buffer[self.index...], x, base, uppercase);
self.index += amt_printed;
}
@@ -448,39 +465,51 @@ fn charToDigit(c: u8, radix: u8) -> %u8 {
return value;
}
-pub fn bufPrintInt(comptime T: type, out_buf: []u8, x: T) -> usize {
- if (T.is_signed) bufPrintSigned(T, out_buf, x) else bufPrintUnsigned(T, out_buf, x)
+fn digitToChar(digit: u8, uppercase: bool) -> u8 {
+ return switch (digit) {
+ 0 ... 9 => digit + '0',
+ 10 ... 35 => digit + ((if (uppercase) u8('A') else u8('a')) - 10),
+ else => @unreachable(),
+ };
}
-fn bufPrintSigned(comptime T: type, out_buf: []u8, x: T) -> usize {
- const uint = @intType(false, T.bit_count);
+/// Guaranteed to not use more than max_int_digits
+pub fn bufPrintInt(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
+ if (@typeOf(x).is_signed)
+ bufPrintSigned(out_buf, x, base, uppercase)
+ else
+ bufPrintUnsigned(out_buf, x, base, uppercase)
+}
+
+fn bufPrintSigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
+ const uint = @intType(false, @typeOf(x).bit_count);
if (x < 0) {
out_buf[0] = '-';
- return 1 + bufPrintUnsigned(uint, out_buf[1...], uint(-(x + 1)) + 1);
+ return 1 + bufPrintUnsigned(out_buf[1...], uint(-(x + 1)) + 1, base, uppercase);
} else {
- return bufPrintUnsigned(uint, out_buf, uint(x));
+ return bufPrintUnsigned(out_buf, uint(x), base, uppercase);
}
}
-fn bufPrintUnsigned(comptime T: type, out_buf: []u8, x: T) -> usize {
- var buf: [max_u64_base10_digits]u8 = undefined;
+fn bufPrintUnsigned(out_buf: []u8, x: var, base: u8, uppercase: bool) -> usize {
+ // max_int_digits accounts for the minus sign. when printing an unsigned
+ // number we don't need to do that.
+ var buf: [max_int_digits - 1]u8 = undefined;
var a = x;
var index: usize = buf.len;
while (true) {
- const digit = a % 10;
+ const digit = a % base;
index -= 1;
- buf[index] = '0' + u8(digit);
- a /= 10;
+ buf[index] = digitToChar(u8(digit), uppercase);
+ a /= base;
if (a == 0)
break;
}
- const len = buf.len - index;
-
- @memcpy(&out_buf[0], &buf[index], len);
-
- return len;
+ const src_buf = buf[index...];
+ mem.copy(u8, out_buf, src_buf);
+ return src_buf.len;
}
fn parseU64DigitTooBig() {
@@ -505,3 +534,19 @@ pub fn openSelfExe(stream: &InStream) -> %void {
else => @compileError("unsupported os"),
}
}
+
+fn bufPrintIntToSlice(buf: []u8, x: var, base: u8, uppercase: bool) -> []u8 {
+ return buf[0...bufPrintInt(buf, x, base, uppercase)];
+}
+
+fn testBufPrintInt() {
+ @setFnTest(this);
+
+ var buf: [max_int_digits]u8 = undefined;
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 2, false), "-101111000110000101001110"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 10, false), "-12345678"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, false), "-bc614e"));
+ assert(mem.eql(bufPrintIntToSlice(buf, i32(-12345678), 16, true), "-BC614E"));
+
+ assert(mem.eql(bufPrintIntToSlice(buf, u32(12345678), 10, true), "12345678"));
+}
std/math.zig
@@ -29,3 +29,40 @@ pub fn shlOverflow(comptime T: type, a: T, b: T) -> %T {
var answer: T = undefined;
if (@shlWithOverflow(T, a, b, &answer)) error.Overflow else answer
}
+
+pub fn log(comptime base: usize, value: var) -> @typeOf(value) {
+ const T = @typeOf(value);
+ if (@isInteger(T)) {
+ if (base == 2) {
+ return T.bit_count - 1 - @clz(value);
+ } else {
+ @compileError("TODO implement log for non base 2 integers");
+ }
+ } else if (@isFloat(T)) {
+ @compileError("TODO implement log for floats");
+ } else {
+ @compileError("log expects integer or float, found '" ++ @typeName(T) ++ "'");
+ }
+}
+
+/// x must be an integer or a float
+/// Note that this causes undefined behavior if
+/// @typeOf(x).is_signed && x == @minValue(@typeOf(x)).
+pub fn abs(x: var) -> @typeOf(x) {
+ const T = @typeOf(x);
+ if (@isInteger(T)) {
+ return if (x < 0) -x else x;
+ } else if (@isFloat(T)) {
+ @compileError("TODO implement abs for floats");
+ } else {
+ @unreachable();
+ }
+}
+fn getReturnTypeForAbs(comptime T: type) -> type {
+ if (@isInteger(T)) {
+ return @intType(false, T.bit_count);
+ } else {
+ return T;
+ }
+}
+
std/mem.zig
@@ -43,6 +43,9 @@ pub const Allocator = struct {
/// Copy all of source into dest at position 0.
/// dest.len must be >= source.len.
pub fn copy(comptime T: type, dest: []T, source: []const T) {
+ // TODO instead of manually doing this check for the whole array
+ // and turning off debug safety, the compiler should detect loops like
+ // this and automatically omit safety checks for loops
@setDebugSafety(this, false);
assert(dest.len >= source.len);
for (source) |s, i| dest[i] = s;
@@ -82,6 +85,23 @@ pub fn sliceAsInt(buf: []u8, is_be: bool, comptime T: type) -> T {
return result;
}
+/// Compares two slices and returns whether they are equal.
+pub fn eql(a: var, b: var) -> bool {
+ if (a.len != b.len) return false;
+ for (a) |item, index| {
+ if (b[index] != item) return false;
+ }
+ return true;
+}
+
+fn testStringEquality() {
+ @setFnTest(this);
+
+ assert(eql("abcd", "abcd"));
+ assert(!eql("abcdef", "abZdef"));
+ assert(!eql("abcdefg", "abcdef"));
+}
+
fn testSliceAsInt() {
@setFnTest(this);
{
std/sort.zig
@@ -1,5 +1,4 @@
const assert = @import("debug.zig").assert;
-const str = @import("str.zig");
const mem = @import("mem.zig");
const math = @import("math.zig");
@@ -76,7 +75,7 @@ fn testSort() {
const slice = buf[0...case[0].len];
mem.copy(u8, slice, case[0]);
sort(u8, slice, u8asc);
- assert(str.eql(slice, case[1]));
+ assert(mem.eql(slice, case[1]));
}
const i32cases = [][][]i32 {
@@ -93,7 +92,7 @@ fn testSort() {
const slice = buf[0...case[0].len];
mem.copy(i32, slice, case[0]);
sort(i32, slice, i32asc);
- assert(str.sliceEql(i32, slice, case[1]));
+ assert(mem.eql(slice, case[1]));
}
}
@@ -114,6 +113,6 @@ fn testSortDesc() {
const slice = buf[0...case[0].len];
mem.copy(i32, slice, case[0]);
sort(i32, slice, i32desc);
- assert(str.sliceEql(i32, slice, case[1]));
+ assert(mem.eql(slice, case[1]));
}
}
std/str.zig
@@ -1,21 +0,0 @@
-const assert = @import("debug.zig").assert;
-
-pub fn eql(a: []const u8, b: []const u8) -> bool {
- sliceEql(u8, a, b)
-}
-
-pub fn sliceEql(comptime T: type, a: []const T, b: []const T) -> bool {
- if (a.len != b.len) return false;
- for (a) |item, index| {
- if (b[index] != item) return false;
- }
- return true;
-}
-
-fn testStringEquality() {
- @setFnTest(this);
-
- assert(eql("abcd", "abcd"));
- assert(!eql("abcdef", "abZdef"));
- assert(!eql("abcdefg", "abcdef"));
-}
test/cases/array.zig
@@ -1,5 +1,5 @@
const assert = @import("std").debug.assert;
-const str = @import("std").str;
+const mem = @import("std").mem;
fn arrays() {
@setFnTest(this);
@@ -63,10 +63,10 @@ fn nestedArrays() {
const array_of_strings = [][]u8 {"hello", "this", "is", "my", "thing"};
for (array_of_strings) |s, i| {
- if (i == 0) assert(str.eql(s, "hello"));
- if (i == 1) assert(str.eql(s, "this"));
- if (i == 2) assert(str.eql(s, "is"));
- if (i == 3) assert(str.eql(s, "my"));
- if (i == 4) assert(str.eql(s, "thing"));
+ if (i == 0) assert(mem.eql(s, "hello"));
+ if (i == 1) assert(mem.eql(s, "this"));
+ if (i == 2) assert(mem.eql(s, "is"));
+ if (i == 3) assert(mem.eql(s, "my"));
+ if (i == 4) assert(mem.eql(s, "thing"));
}
}
test/cases/enum_with_members.zig
@@ -1,5 +1,5 @@
const assert = @import("std").debug.assert;
-const str = @import("std").str;
+const mem = @import("std").mem;
const io = @import("std").io;
const ET = enum {
@@ -8,8 +8,8 @@ const ET = enum {
pub fn print(a: &const ET, buf: []u8) -> %usize {
return switch (*a) {
- ET.SINT => |x| { io.bufPrintInt(i32, buf, x) },
- ET.UINT => |x| { io.bufPrintInt(u32, buf, x) },
+ ET.SINT => |x| { io.bufPrintInt(buf, x, 10, false) },
+ ET.UINT => |x| { io.bufPrintInt(buf, x, 10, false) },
}
}
};
@@ -22,8 +22,8 @@ fn enumWithMembers() {
var buf: [20]u8 = undefined;
assert(%%a.print(buf) == 3);
- assert(str.eql(buf[0...3], "-42"));
+ assert(mem.eql(buf[0...3], "-42"));
assert(%%b.print(buf) == 2);
- assert(str.eql(buf[0...2], "42"));
+ assert(mem.eql(buf[0...2], "42"));
}
test/cases/error.zig
@@ -1,5 +1,5 @@
const assert = @import("std").debug.assert;
-const str = @import("std").str;
+const mem = @import("std").mem;
pub fn foo() -> %i32 {
const x = %return bar();
@@ -28,8 +28,8 @@ fn gimmeItBroke() -> []const u8 {
fn errorName() {
@setFnTest(this);
- assert(str.eql(@errorName(error.AnError), "AnError"));
- assert(str.eql(@errorName(error.ALongerErrorName), "ALongerErrorName"));
+ assert(mem.eql(@errorName(error.AnError), "AnError"));
+ assert(mem.eql(@errorName(error.ALongerErrorName), "ALongerErrorName"));
}
error AnError;
error ALongerErrorName;
test/cases/eval.zig
@@ -1,5 +1,4 @@
const assert = @import("std").debug.assert;
-const str = @import("std").str;
fn compileTimeRecursion() {
@setFnTest(this);
test/cases/for.zig
@@ -1,6 +1,6 @@
const std = @import("std");
const assert = std.debug.assert;
-const str = std.str;
+const mem = std.mem;
fn continueInForLoop() {
@setFnTest(this);
@@ -24,7 +24,7 @@ fn forLoopWithPointerElemVar() {
var target: [source.len]u8 = undefined;
@memcpy(&target[0], &source[0], source.len);
mangleString(target);
- assert(str.eql(target, "bcdefgh"));
+ assert(mem.eql(target, "bcdefgh"));
}
fn mangleString(s: []u8) {
for (s) |*c| {
test/cases/misc.zig
@@ -1,5 +1,5 @@
const assert = @import("std").debug.assert;
-const str = @import("std").str;
+const mem = @import("std").mem;
const cstr = @import("std").cstr;
// normal comment
@@ -144,7 +144,7 @@ fn first4KeysOfHomeRow() -> []const u8 {
fn ReturnStringFromFunction() {
@setFnTest(this);
- assert(str.eql(first4KeysOfHomeRow(), "aoeu"));
+ assert(mem.eql(first4KeysOfHomeRow(), "aoeu"));
}
const g1 : i32 = 1233 + 1;
@@ -210,31 +210,31 @@ fn emptyFn() {}
fn hexEscape() {
@setFnTest(this);
- assert(str.eql("\x68\x65\x6c\x6c\x6f", "hello"));
+ assert(mem.eql("\x68\x65\x6c\x6c\x6f", "hello"));
}
fn stringConcatenation() {
@setFnTest(this);
- assert(str.eql("OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
+ assert(mem.eql("OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
}
fn arrayMultOperator() {
@setFnTest(this);
- assert(str.eql("ab" ** 5, "ababababab"));
+ assert(mem.eql("ab" ** 5, "ababababab"));
}
fn stringEscapes() {
@setFnTest(this);
- assert(str.eql("\"", "\x22"));
- assert(str.eql("\'", "\x27"));
- assert(str.eql("\n", "\x0a"));
- assert(str.eql("\r", "\x0d"));
- assert(str.eql("\t", "\x09"));
- assert(str.eql("\\", "\x5c"));
- assert(str.eql("\u1234\u0069", "\xe1\x88\xb4\x69"));
+ assert(mem.eql("\"", "\x22"));
+ assert(mem.eql("\'", "\x27"));
+ assert(mem.eql("\n", "\x0a"));
+ assert(mem.eql("\r", "\x0d"));
+ assert(mem.eql("\t", "\x09"));
+ assert(mem.eql("\\", "\x5c"));
+ assert(mem.eql("\u1234\u0069", "\xe1\x88\xb4\x69"));
}
fn multilineString() {
@@ -246,7 +246,7 @@ fn multilineString() {
\\three
;
const s2 = "one\ntwo)\nthree";
- assert(str.eql(s1, s2));
+ assert(mem.eql(s1, s2));
}
fn multilineCString() {
@@ -295,7 +295,7 @@ const some_mem : [100]u8 = undefined;
fn memAlloc(comptime T: type, n: usize) -> %[]T {
return (&T)(&some_mem[0])[0...n];
}
-fn memFree(comptime T: type, mem: []T) { }
+fn memFree(comptime T: type, memory: []T) { }
fn castUndefined() {
@@ -344,8 +344,8 @@ fn pointerDereferencing() {
fn callResultOfIfElseExpression() {
@setFnTest(this);
- assert(str.eql(f2(true), "a"));
- assert(str.eql(f2(false), "b"));
+ assert(mem.eql(f2(true), "a"));
+ assert(mem.eql(f2(false), "b"));
}
fn f2(x: bool) -> []u8 {
return (if (x) fA else fB)();
@@ -562,8 +562,8 @@ fn typeName() {
@setFnTest(this);
comptime {
- assert(str.eql(@typeName(i64), "i64"));
- assert(str.eql(@typeName(&usize), "&usize"));
+ assert(mem.eql(@typeName(i64), "i64"));
+ assert(mem.eql(@typeName(&usize), "&usize"));
}
}
test/cases/void.zig
@@ -0,0 +1,20 @@
+const assert = @import("std").debug.assert;
+
+const Foo = struct {
+ a: void,
+ b: i32,
+ c: void,
+};
+
+fn compareVoidWithVoidCompileTimeKnown() {
+ @setFnTest(this);
+
+ comptime {
+ const foo = Foo {
+ .a = {},
+ .b = 1,
+ .c = {},
+ };
+ assert(foo.a == {});
+ }
+}
test/run_tests.cpp
@@ -471,21 +471,17 @@ const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
const array = []u8 {9, 8, 7, 6};
for (array) |item| {
- %%io.stdout.printInt(@typeOf(item), item);
- %%io.stdout.printf("\n");
+ %%io.stdout.printf("{}\n", item);
}
for (array) |item, index| {
- %%io.stdout.printInt(@typeOf(index), index);
- %%io.stdout.printf("\n");
+ %%io.stdout.printf("{}\n", index);
}
const unknown_size: []u8 = array;
for (unknown_size) |item| {
- %%io.stdout.printInt(@typeOf(item), item);
- %%io.stdout.printf("\n");
+ %%io.stdout.printf("{}\n", item);
}
for (unknown_size) |item, index| {
- %%io.stdout.printInt(@typeOf(index), index);
- %%io.stdout.printf("\n");
+ %%io.stdout.printf("{}\n", index);
}
}
)SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");
@@ -1124,13 +1120,6 @@ fn get() -> usize { global_var }
".tmp_source.zig:3:8: note: called from here");
- add_compile_fail_case("unnecessary if statement", R"SOURCE(
-fn f() {
- if (true) { }
-}
- )SOURCE", 1, ".tmp_source.zig:3:9: error: condition is always true; unnecessary if statement");
-
-
add_compile_fail_case("addition with non numbers", R"SOURCE(
const Foo = struct {
field: i32,
@@ -1588,25 +1577,6 @@ fn derp() {
}
)SOURCE", 1, ".tmp_source.zig:7:13: error: cannot assign to constant");
- add_compile_fail_case("compare void with void is compile time known", R"SOURCE(
-const Foo = struct {
- a: void,
- b: i32,
- c: void,
-};
-
-fn f() {
- const foo = Foo {
- .a = {},
- .b = 1,
- .c = {},
- };
- if (foo.a != {}) {
- @unreachable();
- }
-}
- )SOURCE", 1, ".tmp_source.zig:14:15: error: condition is always false; unnecessary if statement");
-
add_compile_fail_case("return from defer expression", R"SOURCE(
pub fn testTrickyDefer() -> %void {
defer canFail() %% {};
test/self_hosted.zig
@@ -32,4 +32,5 @@ const test_try = @import("cases/try.zig");
const test_typedef = @import("cases/typedef.zig");
const test_undefined = @import("cases/undefined.zig");
const test_var_args = @import("cases/var_args.zig");
+const test_void = @import("cases/void.zig");
const test_while = @import("cases/while.zig");
CMakeLists.txt
@@ -225,7 +225,6 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/panic.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/rand.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/rand_test.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/sort.zig" DESTINATION "${ZIG_STD_DEST}")
-install(FILES "${CMAKE_SOURCE_DIR}/std/str.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig" DESTINATION "${ZIG_STD_DEST}")
install(FILES "${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig" DESTINATION "${ZIG_STD_DEST}")