diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fce41d4cf..a05f8f5fda 100644 --- a/CMakeLists.txt +++ b/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}") diff --git a/src/ir.cpp b/src/ir.cpp index a6add73124..e89f89f89c 100644 --- a/src/ir.cpp +++ b/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), diff --git a/std/elf.zig b/std/elf.zig index 704f1e1870..1ad41bf245 100644 --- a/std/elf.zig +++ b/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, diff --git a/std/index.zig b/std/index.zig index c4a18cbbe8..b4aeb410b2 100644 --- a/std/index.zig +++ b/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"); diff --git a/std/io.zig b/std/io.zig index d0c7f407bd..f726c30cbc 100644 --- a/std/io.zig +++ b/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")); +} diff --git a/std/math.zig b/std/math.zig index 3dbc029a02..d8e4951fa9 100644 --- a/std/math.zig +++ b/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; + } +} + diff --git a/std/mem.zig b/std/mem.zig index 8aa18348b2..45734ce869 100644 --- a/std/mem.zig +++ b/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); { diff --git a/std/sort.zig b/std/sort.zig index 9699773b4f..8c41d87034 100644 --- a/std/sort.zig +++ b/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])); } } diff --git a/std/str.zig b/std/str.zig deleted file mode 100644 index bb891b37ef..0000000000 --- a/std/str.zig +++ /dev/null @@ -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")); -} diff --git a/test/cases/array.zig b/test/cases/array.zig index 79dcf21407..1dc1242d37 100644 --- a/test/cases/array.zig +++ b/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")); } } diff --git a/test/cases/enum_with_members.zig b/test/cases/enum_with_members.zig index 7bcc2ac01f..b338b9b014 100644 --- a/test/cases/enum_with_members.zig +++ b/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")); } diff --git a/test/cases/error.zig b/test/cases/error.zig index 14c4011445..20fba13f90 100644 --- a/test/cases/error.zig +++ b/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; diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 629fb6366b..9f3b1d2fcd 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -1,5 +1,4 @@ const assert = @import("std").debug.assert; -const str = @import("std").str; fn compileTimeRecursion() { @setFnTest(this); diff --git a/test/cases/for.zig b/test/cases/for.zig index 27ace9e063..dd1987d6b9 100644 --- a/test/cases/for.zig +++ b/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| { diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 39de3d1e4f..0984abcae9 100644 --- a/test/cases/misc.zig +++ b/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")); } } diff --git a/test/cases/void.zig b/test/cases/void.zig new file mode 100644 index 0000000000..15b8276b0b --- /dev/null +++ b/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 == {}); + } +} diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 944d687d12..01d16a2543 100644 --- a/test/run_tests.cpp +++ b/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() %% {}; diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 5d8356fe18..7830e67ea4 100644 --- a/test/self_hosted.zig +++ b/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");