diff --git a/build.zig b/build.zig index a8b167bef9..8e8b12358d 100644 --- a/build.zig +++ b/build.zig @@ -11,6 +11,7 @@ pub fn build(b: &Builder) { run_tests_cmd.step.dependOn(&run_tests_exe.step); const self_hosted_tests = b.step("test-self-hosted", "Run the self-hosted tests"); + test_step.dependOn(self_hosted_tests); for ([]bool{false, true}) |release| { for ([]bool{false, true}) |link_libc| { const these_tests = b.addTest("test/self_hosted.zig"); @@ -24,9 +25,24 @@ pub fn build(b: &Builder) { } } - test_step.dependOn(self_hosted_tests); + const std_lib_tests = b.step("test-std", "Run the standard library tests"); + test_step.dependOn(std_lib_tests); + for ([]bool{false, true}) |release| { + for ([]bool{false, true}) |link_libc| { + const these_tests = b.addTest("std/index.zig"); + // TODO add prefix to test names + // TODO pass test_filter to these_tests + these_tests.setRelease(release); + if (link_libc) { + these_tests.linkLibrary("c"); + } + std_lib_tests.dependOn(&these_tests.step); + } + } + //test_step.dependOn(&run_tests_cmd.step); test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); + test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig new file mode 100644 index 0000000000..199d60b184 --- /dev/null +++ b/test/compile_errors.zig @@ -0,0 +1,1812 @@ +const std = @import("std"); +const debug = std.debug; +const build = std.build; +const os = std.os; +const StdIo = os.ChildProcess.StdIo; +const Term = os.ChildProcess.Term; +const Buffer0 = std.cstr.Buffer0; +const io = std.io; +const mem = std.mem; +const fmt = std.fmt; +const List = std.list.List; + +error TestFailed; + +pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { + const cases = %%b.allocator.create(CompileErrorContext); + *cases = CompileErrorContext { + .b = b, + .step = b.step("test-compile-errors", "Run the compile error tests"), + .test_index = 0, + .test_filter = test_filter, + }; + + cases.add("implicit semicolon - block statement", + \\export fn entry() { + \\ {} + \\ var good = {}; + \\ ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - block expr", + \\export fn entry() { + \\ _ = {}; + \\ var good = {}; + \\ _ = {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - comptime statement", + \\export fn entry() { + \\ comptime {} + \\ var good = {}; + \\ comptime ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - comptime expression", + \\export fn entry() { + \\ _ = comptime {}; + \\ var good = {}; + \\ _ = comptime {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - defer", + \\export fn entry() { + \\ defer {} + \\ var good = {}; + \\ defer ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: expected token ';', found 'var'"); + + cases.add("implicit semicolon - if statement", + \\export fn entry() { + \\ if(true) {} + \\ var good = {}; + \\ if(true) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if expression", + \\export fn entry() { + \\ _ = if(true) {}; + \\ var good = {}; + \\ _ = if(true) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if-else statement", + \\export fn entry() { + \\ if(true) {} else {} + \\ var good = {}; + \\ if(true) ({}) else ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if-else expression", + \\export fn entry() { + \\ _ = if(true) {} else {}; + \\ var good = {}; + \\ _ = if(true) {} else {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if-else-if statement", + \\export fn entry() { + \\ if(true) {} else if(true) {} + \\ var good = {}; + \\ if(true) ({}) else if(true) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if-else-if expression", + \\export fn entry() { + \\ _ = if(true) {} else if(true) {}; + \\ var good = {}; + \\ _ = if(true) {} else if(true) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if-else-if-else statement", + \\export fn entry() { + \\ if(true) {} else if(true) {} else {} + \\ var good = {}; + \\ if(true) ({}) else if(true) ({}) else ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if-else-if-else expression", + \\export fn entry() { + \\ _ = if(true) {} else if(true) {} else {}; + \\ var good = {}; + \\ _ = if(true) {} else if(true) {} else {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var) statement", + \\export fn entry() { + \\ if(_=foo()) {} + \\ var good = {}; + \\ if(_=foo()) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var) expression", + \\export fn entry() { + \\ _ = if(_=foo()) {}; + \\ var good = {}; + \\ _ = if(_=foo()) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var)-else statement", + \\export fn entry() { + \\ if(_=foo()) {} else {} + \\ var good = {}; + \\ if(_=foo()) ({}) else ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var)-else expression", + \\export fn entry() { + \\ _ = if(_=foo()) {} else {}; + \\ var good = {}; + \\ _ = if(_=foo()) {} else {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var)-else-if(var) statement", + \\export fn entry() { + \\ if(_=foo()) {} else if(_=foo()) {} + \\ var good = {}; + \\ if(_=foo()) ({}) else if(_=foo()) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var)-else-if(var) expression", + \\export fn entry() { + \\ _ = if(_=foo()) {} else if(_=foo()) {}; + \\ var good = {}; + \\ _ = if(_=foo()) {} else if(_=foo()) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var)-else-if(var)-else statement", + \\export fn entry() { + \\ if(_=foo()) {} else if(_=foo()) {} else {} + \\ var good = {}; + \\ if(_=foo()) ({}) else if(_=foo()) ({}) else ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - if(var)-else-if(var)-else expression", + \\export fn entry() { + \\ _ = if(_=foo()) {} else if(_=foo()) {} else {}; + \\ var good = {}; + \\ _ = if(_=foo()) {} else if(_=foo()) {} else {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - try statement", + \\export fn entry() { + \\ try (_ = foo()) {} + \\ var good = {}; + \\ try (_ = foo()) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - try expression", + \\export fn entry() { + \\ _ = try (_ = foo()) {}; + \\ var good = {}; + \\ _ = try (_ = foo()) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - while statement", + \\export fn entry() { + \\ while(true) {} + \\ var good = {}; + \\ while(true) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - while expression", + \\export fn entry() { + \\ _ = while(true) {}; + \\ var good = {}; + \\ _ = while(true) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - while-continue statement", + \\export fn entry() { + \\ while(true;{}) {} + \\ var good = {}; + \\ while(true;{}) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - while-continue expression", + \\export fn entry() { + \\ _ = while(true;{}) {}; + \\ var good = {}; + \\ _ = while(true;{}) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - for statement", + \\export fn entry() { + \\ for(foo()) {} + \\ var good = {}; + \\ for(foo()) ({}) + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("implicit semicolon - for expression", + \\export fn entry() { + \\ _ = for(foo()) {}; + \\ var good = {}; + \\ _ = for(foo()) {} + \\ var bad = {}; + \\} + , ".tmp_source.zig:5:5: error: invalid token: 'var'"); + + cases.add("multiple function definitions", + \\fn a() {} + \\fn a() {} + \\export fn entry() { a(); } + , ".tmp_source.zig:2:1: error: redefinition of 'a'"); + + cases.add("unreachable with return", + \\fn a() -> noreturn {return;} + \\export fn entry() { a(); } + , ".tmp_source.zig:1:21: error: expected type 'noreturn', found 'void'"); + + cases.add("control reaches end of non-void function", + \\fn a() -> i32 {} + \\export fn entry() { _ = a(); } + , ".tmp_source.zig:1:15: error: expected type 'i32', found 'void'"); + + cases.add("undefined function call", + \\export fn a() { + \\ b(); + \\} + , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); + + cases.add("wrong number of arguments", + \\export fn a() { + \\ b(1); + \\} + \\fn b(a: i32, b: i32, c: i32) { } + , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1"); + + cases.add("invalid type", + \\fn a() -> bogus {} + \\export fn entry() { _ = a(); } + , ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'"); + + cases.add("pointer to unreachable", + \\fn a() -> &noreturn {} + \\export fn entry() { _ = a(); } + , ".tmp_source.zig:1:12: error: pointer to unreachable not allowed"); + + cases.add("unreachable code", + \\export fn a() { + \\ return; + \\ b(); + \\} + \\ + \\fn b() {} + , ".tmp_source.zig:3:6: error: unreachable code"); + + cases.add("bad import", + \\const bogus = @import("bogus-does-not-exist.zig"); + \\export fn entry() { bogus.bogo(); } + , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'"); + + cases.add("undeclared identifier", + \\export fn a() { + \\ b + + \\ c + \\} + , + ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'", + ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'"); + + cases.add("parameter redeclaration", + \\fn f(a : i32, a : i32) { + \\} + \\export fn entry() { f(1, 2); } + , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'"); + + cases.add("local variable redeclaration", + \\export fn f() { + \\ const a : i32 = 0; + \\ const a = 0; + \\} + , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); + + cases.add("local variable redeclares parameter", + \\fn f(a : i32) { + \\ const a = 0; + \\} + \\export fn entry() { f(1); } + , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'"); + + cases.add("variable has wrong type", + \\export fn f() -> i32 { + \\ const a = c"a"; + \\ a + \\} + , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'"); + + cases.add("if condition is bool, not int", + \\export fn f() { + \\ if (0) {} + \\} + , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'"); + + cases.add("assign unreachable", + \\export fn f() { + \\ const a = return; + \\} + , ".tmp_source.zig:2:5: error: unreachable code"); + + cases.add("unreachable variable", + \\export fn f() { + \\ const a: noreturn = {}; + \\} + , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed"); + + cases.add("unreachable parameter", + \\fn f(a: noreturn) {} + \\export fn entry() { f(); } + , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed"); + + cases.add("bad assignment target", + \\export fn f() { + \\ 3 = 3; + \\} + , ".tmp_source.zig:2:7: error: cannot assign to constant"); + + cases.add("assign to constant variable", + \\export fn f() { + \\ const a = 3; + \\ a = 4; + \\} + , ".tmp_source.zig:3:7: error: cannot assign to constant"); + + cases.add("use of undeclared identifier", + \\export fn f() { + \\ b = 3; + \\} + , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'"); + + cases.add("const is a statement, not an expression", + \\export fn f() { + \\ (const a = 0); + \\} + , ".tmp_source.zig:2:6: error: invalid token: 'const'"); + + cases.add("array access of undeclared identifier", + \\export fn f() { + \\ i[i] = i[i]; + \\} + , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'", + ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'"); + + cases.add("array access of non array", + \\export fn f() { + \\ var bad : bool = undefined; + \\ bad[bad] = bad[bad]; + \\} + , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'", + ".tmp_source.zig:3:19: error: array access of non-array type 'bool'"); + + cases.add("array access with non integer index", + \\export fn f() { + \\ var array = "aoeu"; + \\ var bad = false; + \\ array[bad] = array[bad]; + \\} + , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'", + ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'"); + + cases.add("write to const global variable", + \\const x : i32 = 99; + \\fn f() { + \\ x = 1; + \\} + \\export fn entry() { f(); } + , ".tmp_source.zig:3:7: error: cannot assign to constant"); + + + cases.add("missing else clause", + \\fn f(b: bool) { + \\ const x : i32 = if (b) { 1 }; + \\ const y = if (b) { i32(1) }; + \\} + \\export fn entry() { f(true); } + , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'", + ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'"); + + cases.add("direct struct loop", + \\const A = struct { a : A, }; + \\export fn entry() -> usize { @sizeOf(A) } + , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); + + cases.add("indirect struct loop", + \\const A = struct { b : B, }; + \\const B = struct { c : C, }; + \\const C = struct { a : A, }; + \\export fn entry() -> usize { @sizeOf(A) } + , ".tmp_source.zig:1:11: error: struct 'A' contains itself"); + + cases.add("invalid struct field", + \\const A = struct { x : i32, }; + \\export fn f() { + \\ var a : A = undefined; + \\ a.foo = 1; + \\ const y = a.bar; + \\} + , + ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'", + ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'"); + + cases.add("redefinition of struct", + \\const A = struct { x : i32, }; + \\const A = struct { y : i32, }; + , ".tmp_source.zig:2:1: error: redefinition of 'A'"); + + cases.add("redefinition of enums", + \\const A = enum {}; + \\const A = enum {}; + , ".tmp_source.zig:2:1: error: redefinition of 'A'"); + + cases.add("redefinition of global variables", + \\var a : i32 = 1; + \\var a : i32 = 2; + , + ".tmp_source.zig:2:1: error: redefinition of 'a'", + ".tmp_source.zig:1:1: note: previous definition is here"); + + cases.add("byvalue struct parameter in exported function", + \\const A = struct { x : i32, }; + \\export fn f(a : A) {} + , ".tmp_source.zig:2:13: error: byvalue types not yet supported on extern function parameters"); + + cases.add("byvalue struct return value in exported function", + \\const A = struct { x: i32, }; + \\export fn f() -> A { + \\ A {.x = 1234 } + \\} + , ".tmp_source.zig:2:18: error: byvalue types not yet supported on extern function return values"); + + cases.add("duplicate field in struct value expression", + \\const A = struct { + \\ x : i32, + \\ y : i32, + \\ z : i32, + \\}; + \\export fn f() { + \\ const a = A { + \\ .z = 1, + \\ .y = 2, + \\ .x = 3, + \\ .z = 4, + \\ }; + \\} + , ".tmp_source.zig:11:9: error: duplicate field"); + + cases.add("missing field in struct value expression", + \\const A = struct { + \\ x : i32, + \\ y : i32, + \\ z : i32, + \\}; + \\export fn f() { + \\ // we want the error on the '{' not the 'A' because + \\ // the A could be a complicated expression + \\ const a = A { + \\ .z = 4, + \\ .y = 2, + \\ }; + \\} + , ".tmp_source.zig:9:17: error: missing field: 'x'"); + + cases.add("invalid field in struct value expression", + \\const A = struct { + \\ x : i32, + \\ y : i32, + \\ z : i32, + \\}; + \\export fn f() { + \\ const a = A { + \\ .z = 4, + \\ .y = 2, + \\ .foo = 42, + \\ }; + \\} + , ".tmp_source.zig:10:9: error: no member named 'foo' in 'A'"); + + cases.add("invalid break expression", + \\export fn f() { + \\ break; + \\} + , ".tmp_source.zig:2:5: error: 'break' expression outside loop"); + + cases.add("invalid continue expression", + \\export fn f() { + \\ continue; + \\} + , ".tmp_source.zig:2:5: error: 'continue' expression outside loop"); + + cases.add("invalid maybe type", + \\export fn f() { + \\ if (const x ?= true) { } + \\} + , ".tmp_source.zig:2:20: error: expected nullable type, found 'bool'"); + + cases.add("cast unreachable", + \\fn f() -> i32 { + \\ i32(return 1) + \\} + \\export fn entry() { _ = f(); } + , ".tmp_source.zig:2:8: error: unreachable code"); + + cases.add("invalid builtin fn", + \\fn f() -> @bogus(foo) { + \\} + \\export fn entry() { _ = f(); } + , ".tmp_source.zig:1:11: error: invalid builtin function: 'bogus'"); + + cases.add("top level decl dependency loop", + \\const a : @typeOf(b) = 0; + \\const b : @typeOf(a) = 0; + \\export fn entry() { + \\ const c = a + b; + \\} + , ".tmp_source.zig:1:1: error: 'a' depends on itself"); + + cases.add("noalias on non pointer param", + \\fn f(noalias x: i32) {} + \\export fn entry() { f(1234); } + , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter"); + + cases.add("struct init syntax for array", + \\const foo = []u16{.x = 1024,}; + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax"); + + cases.add("type variables must be constant", + \\var foo = u8; + \\export fn entry() -> foo { + \\ return 1; + \\} + , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant"); + + + cases.add("variables shadowing types", + \\const Foo = struct {}; + \\const Bar = struct {}; + \\ + \\fn f(Foo: i32) { + \\ var Bar : i32 = undefined; + \\} + \\ + \\export fn entry() { + \\ f(1234); + \\} + , + ".tmp_source.zig:4:6: error: redefinition of 'Foo'", + ".tmp_source.zig:1:1: note: previous definition is here", + ".tmp_source.zig:5:5: error: redefinition of 'Bar'", + ".tmp_source.zig:2:1: note: previous definition is here"); + + cases.add("multiple else prongs in a switch", + \\fn f(x: u32) { + \\ const value: bool = switch (x) { + \\ 1234 => false, + \\ else => true, + \\ else => true, + \\ }; + \\} + \\export fn entry() { + \\ f(1234); + \\} + , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression"); + + cases.add("global variable initializer must be constant expression", + \\extern fn foo() -> i32; + \\const x = foo(); + \\export fn entry() -> i32 { x } + , ".tmp_source.zig:2:11: error: unable to evaluate constant expression"); + + cases.add("array concatenation with wrong type", + \\const src = "aoeu"; + \\const derp = usize(1234); + \\const a = derp ++ "foo"; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'"); + + cases.add("non compile time array concatenation", + \\fn f() -> []u8 { + \\ s ++ "foo" + \\} + \\var s: [10]u8 = undefined; + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:2:5: error: unable to evaluate constant expression"); + + cases.add("@cImport with bogus include", + \\const c = @cImport(@cInclude("bogus.h")); + \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } + , ".tmp_source.zig:1:11: error: C import failed", + ".h:1:10: note: 'bogus.h' file not found"); + + cases.add("address of number literal", + \\const x = 3; + \\const y = &x; + \\fn foo() -> &const i32 { y } + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'"); + + cases.add("integer overflow error", + \\const x : u8 = 300; + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); + + cases.add("incompatible number literals", + \\const x = 2 == 2.0; + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); + + cases.add("missing function call param", + \\const Foo = struct { + \\ a: i32, + \\ b: i32, + \\ + \\ fn member_a(foo: &const Foo) -> i32 { + \\ return foo.a; + \\ } + \\ fn member_b(foo: &const Foo) -> i32 { + \\ return foo.b; + \\ } + \\}; + \\ + \\const member_fn_type = @typeOf(Foo.member_a); + \\const members = []member_fn_type { + \\ Foo.member_a, + \\ Foo.member_b, + \\}; + \\ + \\fn f(foo: &const Foo, index: usize) { + \\ const result = members[index](); + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0"); + + cases.add("missing function name and param name", + \\fn () {} + \\fn f(i32) {} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , + ".tmp_source.zig:1:1: error: missing function name", + ".tmp_source.zig:2:6: error: missing parameter name"); + + cases.add("wrong function type", + \\const fns = []fn(){ a, b, c }; + \\fn a() -> i32 {0} + \\fn b() -> i32 {1} + \\fn c() -> i32 {2} + \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } + , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'"); + + cases.add("extern function pointer mismatch", + \\const fns = [](fn(i32)->i32){ a, b, c }; + \\pub fn a(x: i32) -> i32 {x + 0} + \\pub fn b(x: i32) -> i32 {x + 1} + \\export fn c(x: i32) -> i32 {x + 2} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) } + , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); + + + cases.add("implicit cast from f64 to f32", + \\const x : f64 = 1.0; + \\const y : f32 = x; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'"); + + + cases.add("colliding invalid top level functions", + \\fn func() -> bogus {} + \\fn func() -> bogus {} + \\export fn entry() -> usize { @sizeOf(@typeOf(func)) } + , + ".tmp_source.zig:2:1: error: redefinition of 'func'", + ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'"); + + + cases.add("bogus compile var", + \\const x = @compileVar("bogus"); + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + , ".tmp_source.zig:1:23: error: unrecognized compile variable: 'bogus'"); + + + cases.add("non constant expression in array size outside function", + \\const Foo = struct { + \\ y: [get()]u8, + \\}; + \\var global_var: usize = 1; + \\fn get() -> usize { global_var } + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } + , + ".tmp_source.zig:5:21: error: unable to evaluate constant expression", + ".tmp_source.zig:2:12: note: called from here", + ".tmp_source.zig:2:8: note: called from here"); + + + cases.add("addition with non numbers", + \\const Foo = struct { + \\ field: i32, + \\}; + \\const x = Foo {.field = 1} + Foo {.field = 2}; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); + + + cases.add("division by zero", + \\const lit_int_x = 1 / 0; + \\const lit_float_x = 1.0 / 0.0; + \\const int_x = i32(1) / i32(0); + \\const float_x = f32(1.0) / f32(0.0); + \\ + \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } + \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } + \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } + \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } + , + ".tmp_source.zig:1:21: error: division by zero is undefined", + ".tmp_source.zig:2:25: error: division by zero is undefined", + ".tmp_source.zig:3:22: error: division by zero is undefined", + ".tmp_source.zig:4:26: error: division by zero is undefined"); + + + cases.add("missing switch prong", + \\const Number = enum { + \\ One, + \\ Two, + \\ Three, + \\ Four, + \\}; + \\fn f(n: Number) -> i32 { + \\ switch (n) { + \\ Number.One => 1, + \\ Number.Two => 2, + \\ Number.Three => i32(3), + \\ } + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch"); + + cases.add("normal string with newline", + \\const foo = "a + \\b"; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:1:13: error: newline not allowed in string literal"); + + cases.add("invalid comparison for function pointers", + \\fn foo() {} + \\const invalid = foo > foo; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } + , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'"); + + cases.add("generic function instance with non-constant expression", + \\fn foo(comptime x: i32, y: i32) -> i32 { return x + y; } + \\fn test1(a: i32, b: i32) -> i32 { + \\ return foo(a, b); + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) } + , ".tmp_source.zig:3:16: error: unable to evaluate constant expression"); + + cases.add("goto jumping into block", + \\export fn f() { + \\ { + \\a_label: + \\ } + \\ goto a_label; + \\} + , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'"); + + cases.add("goto jumping past a defer", + \\fn f(b: bool) { + \\ if (b) goto label; + \\ defer derp(); + \\label: + \\} + \\fn derp(){} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:2:12: error: no label in scope named 'label'"); + + cases.add("assign null to non-nullable pointer", + \\const a: &u8 = null; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'"); + + cases.add("indexing an array of size zero", + \\const array = []u8{}; + \\export fn foo() { + \\ const pointer = &array[0]; + \\} + , ".tmp_source.zig:3:27: error: index 0 outside array of size 0"); + + cases.add("compile time division by zero", + \\const y = foo(0); + \\fn foo(x: i32) -> i32 { + \\ 1 / x + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + , + ".tmp_source.zig:3:7: error: division by zero is undefined", + ".tmp_source.zig:1:14: note: called from here"); + + cases.add("branch on undefined value", + \\const x = if (undefined) true else false; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(x)) } + , ".tmp_source.zig:1:15: error: use of undefined value"); + + + cases.add("endless loop in function evaluation", + \\const seventh_fib_number = fibbonaci(7); + \\fn fibbonaci(x: i32) -> i32 { + \\ return fibbonaci(x - 1) + fibbonaci(x - 2); + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } + , + ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches", + ".tmp_source.zig:3:21: note: called from here"); + + cases.add("@embedFile with bogus file", + \\const resource = @embedFile("bogus.txt"); + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) } + , ".tmp_source.zig:1:29: error: unable to find '", "/bogus.txt'"); + + cases.add("non-const expression in struct literal outside function", + \\const Foo = struct { + \\ x: i32, + \\}; + \\const a = Foo {.x = get_it()}; + \\extern fn get_it() -> i32; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + , ".tmp_source.zig:4:21: error: unable to evaluate constant expression"); + + cases.add("non-const expression function call with struct return value outside function", + \\const Foo = struct { + \\ x: i32, + \\}; + \\const a = get_it(); + \\fn get_it() -> Foo { + \\ global_side_effect = true; + \\ Foo {.x = 13} + \\} + \\var global_side_effect = false; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + , + ".tmp_source.zig:6:24: error: unable to evaluate constant expression", + ".tmp_source.zig:4:17: note: called from here"); + + cases.add("undeclared identifier error should mark fn as impure", + \\export fn foo() { + \\ test_a_thing(); + \\} + \\fn test_a_thing() { + \\ bad_fn_call(); + \\} + , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'"); + + cases.add("illegal comparison of types", + \\fn bad_eql_1(a: []u8, b: []u8) -> bool { + \\ a == b + \\} + \\const EnumWithData = enum { + \\ One, + \\ Two: i32, + \\}; + \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool { + \\ *a == *b + \\} + \\ + \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } + \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } + , + ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'", + ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'"); + + cases.add("non-const switch number literal", + \\export fn foo() { + \\ const x = switch (bar()) { + \\ 1, 2 => 1, + \\ 3, 4 => 2, + \\ else => 3, + \\ }; + \\} + \\fn bar() -> i32 { + \\ 2 + \\} + , ".tmp_source.zig:2:15: error: unable to infer expression type"); + + cases.add("atomic orderings of cmpxchg - failure stricter than success", + \\export fn f() { + \\ var x: i32 = 1234; + \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} + \\} + , ".tmp_source.zig:3:72: error: failure atomic ordering must be no stricter than success"); + + cases.add("atomic orderings of cmpxchg - success Monotonic or stricter", + \\export fn f() { + \\ var x: i32 = 1234; + \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} + \\} + , ".tmp_source.zig:3:49: error: success atomic ordering must be Monotonic or stricter"); + + cases.add("negation overflow in function evaluation", + \\const y = neg(-128); + \\fn neg(x: i8) -> i8 { + \\ -x + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + , + ".tmp_source.zig:3:5: error: negation caused overflow", + ".tmp_source.zig:1:14: note: called from here"); + + cases.add("add overflow in function evaluation", + \\const y = add(65530, 10); + \\fn add(a: u16, b: u16) -> u16 { + \\ a + b + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + , + ".tmp_source.zig:3:7: error: operation caused overflow", + ".tmp_source.zig:1:14: note: called from here"); + + + cases.add("sub overflow in function evaluation", + \\const y = sub(10, 20); + \\fn sub(a: u16, b: u16) -> u16 { + \\ a - b + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + , + ".tmp_source.zig:3:7: error: operation caused overflow", + ".tmp_source.zig:1:14: note: called from here"); + + cases.add("mul overflow in function evaluation", + \\const y = mul(300, 6000); + \\fn mul(a: u16, b: u16) -> u16 { + \\ a * b + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(y)) } + , + ".tmp_source.zig:3:7: error: operation caused overflow", + ".tmp_source.zig:1:14: note: called from here"); + + cases.add("truncate sign mismatch", + \\fn f() -> i8 { + \\ const x: u32 = 10; + \\ @truncate(i8, x) + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'"); + + cases.add("%return in function with non error return type", + \\export fn f() { + \\ %return something(); + \\} + \\fn something() -> %void { } + , + ".tmp_source.zig:2:5: error: expected type 'void', found 'error'"); + + cases.add("wrong return type for main", + \\pub fn main() { } + , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'"); + + cases.add("double ?? on main return value", + \\pub fn main() -> ??void { + \\} + , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'"); + + cases.add("invalid pointer for var type", + \\extern fn ext() -> usize; + \\var bytes: [ext()]u8 = undefined; + \\export fn f() { + \\ for (bytes) |*b, i| { + \\ *b = u8(i); + \\ } + \\} + , ".tmp_source.zig:2:13: error: unable to evaluate constant expression"); + + cases.add("export function with comptime parameter", + \\export fn foo(comptime x: i32, y: i32) -> i32{ + \\ x + y + \\} + , ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function"); + + cases.add("extern function with comptime parameter", + \\extern fn foo(comptime x: i32, y: i32) -> i32; + \\fn f() -> i32 { + \\ foo(1, 2) + \\} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function"); + + cases.add("convert fixed size array to slice with invalid size", + \\export fn f() { + \\ var array: [5]u8 = undefined; + \\ var foo = ([]const u32)(array)[0]; + \\} + , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch"); + + cases.add("non-pure function returns type", + \\var a: u32 = 0; + \\pub fn List(comptime T: type) -> type { + \\ a += 1; + \\ SmallList(T, 8) + \\} + \\ + \\pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type { + \\ struct { + \\ items: []T, + \\ length: usize, + \\ prealloc_items: [STATIC_SIZE]T, + \\ } + \\} + \\ + \\export fn function_with_return_type_type() { + \\ var list: List(i32) = undefined; + \\ list.length = 10; + \\} + , ".tmp_source.zig:3:7: error: unable to evaluate constant expression", + ".tmp_source.zig:16:19: note: called from here"); + + cases.add("bogus method call on slice", + \\var self = "aoeu"; + \\fn f(m: []const u8) { + \\ m.copy(u8, self[0...], m); + \\} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'"); + + cases.add("wrong number of arguments for method fn call", + \\const Foo = struct { + \\ fn method(self: &const Foo, a: i32) {} + \\}; + \\fn f(foo: &const Foo) { + \\ + \\ foo.method(1, 2); + \\} + \\export fn entry() -> usize { @sizeOf(@typeOf(f)) } + , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3"); + + cases.add("assign through constant pointer", + \\export fn f() { + \\ var cstr = c"Hat"; + \\ cstr[0] = 'W'; + \\} + , ".tmp_source.zig:3:11: error: cannot assign to constant"); + + cases.add("assign through constant slice", + \\export fn f() { + \\ var cstr: []const u8 = "Hat"; + \\ cstr[0] = 'W'; + \\} + , ".tmp_source.zig:3:11: error: cannot assign to constant"); + + cases.add("main function with bogus args type", + \\pub fn main(args: [][]bogus) -> %void {} + , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'"); + + cases.add("for loop missing element param", + \\fn foo(blah: []u8) { + \\ for (blah) { } + \\} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:2:5: error: for loop expression missing element parameter"); + + cases.add("misspelled type with pointer only reference", + \\const JasonHM = u8; + \\const JasonList = &JsonNode; + \\ + \\const JsonOA = enum { + \\ JSONArray: JsonList, + \\ JSONObject: JasonHM, + \\}; + \\ + \\const JsonType = enum { + \\ JSONNull: void, + \\ JSONInteger: isize, + \\ JSONDouble: f64, + \\ JSONBool: bool, + \\ JSONString: []u8, + \\ JSONArray, + \\ JSONObject, + \\}; + \\ + \\pub const JsonNode = struct { + \\ kind: JsonType, + \\ jobject: ?JsonOA, + \\}; + \\ + \\fn foo() { + \\ var jll: JasonList = undefined; + \\ jll.init(1234); + \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'"); + + cases.add("method call with first arg type primitive", + \\const Foo = struct { + \\ x: i32, + \\ + \\ fn init(x: i32) -> Foo { + \\ Foo { + \\ .x = x, + \\ } + \\ } + \\}; + \\ + \\export fn f() { + \\ const derp = Foo.init(3); + \\ + \\ derp.init(); + \\} + , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'"); + + cases.add("method call with first arg type wrong container", + \\pub const List = struct { + \\ len: usize, + \\ allocator: &Allocator, + \\ + \\ pub fn init(allocator: &Allocator) -> List { + \\ List { + \\ .len = 0, + \\ .allocator = allocator, + \\ } + \\ } + \\}; + \\ + \\pub var global_allocator = Allocator { + \\ .field = 1234, + \\}; + \\ + \\pub const Allocator = struct { + \\ field: i32, + \\}; + \\ + \\export fn foo() { + \\ var x = List.init(&global_allocator); + \\ x.init(); + \\} + , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'"); + + cases.add("binary not on number literal", + \\const TINY_QUANTUM_SHIFT = 4; + \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; + \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } + , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'"); + + cases.addCase({ + const tc = cases.create("multiple files with private function error", + \\const foo = @import("foo.zig"); + \\ + \\export fn callPrivFunction() { + \\ foo.privateFunction(); + \\} + , + ".tmp_source.zig:4:8: error: 'privateFunction' is private", + "foo.zig:1:1: note: declared here"); + + tc.addSourceFile("foo.zig", + \\fn privateFunction() { } + ); + + tc + }); + + cases.add("container init with non-type", + \\const zero: i32 = 0; + \\const a = zero{1}; + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(a)) } + , ".tmp_source.zig:2:11: error: expected type, found 'i32'"); + + cases.add("assign to constant field", + \\const Foo = struct { + \\ field: i32, + \\}; + \\export fn derp() { + \\ const f = Foo {.field = 1234,}; + \\ f.field = 0; + \\} + , ".tmp_source.zig:6:13: error: cannot assign to constant"); + + cases.add("return from defer expression", + \\pub fn testTrickyDefer() -> %void { + \\ defer canFail() %% {}; + \\ + \\ defer %return canFail(); + \\ + \\ const a = maybeInt() ?? return; + \\} + \\ + \\fn canFail() -> %void { } + \\ + \\pub fn maybeInt() -> ?i32 { + \\ return 0; + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } + , ".tmp_source.zig:4:11: error: cannot return from defer expression"); + + cases.add("attempt to access var args out of bounds", + \\fn add(args: ...) -> i32 { + \\ args[0] + args[1] + \\} + \\ + \\fn foo() -> i32 { + \\ add(i32(1234)) + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , + ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1", + ".tmp_source.zig:6:8: note: called from here"); + + cases.add("pass integer literal to var args", + \\fn add(args: ...) -> i32 { + \\ var sum = i32(0); + \\ {comptime var i: usize = 0; inline while (i < args.len; i += 1) { + \\ sum += args[i]; + \\ }} + \\ return sum; + \\} + \\ + \\fn bar() -> i32 { + \\ add(1, 2, 3, 4) + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) } + , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime"); + + cases.add("assign too big number to u16", + \\export fn foo() { + \\ var vga_mem: u16 = 0xB8000; + \\} + , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'"); + + cases.add("set global variable alignment to non power of 2", + \\const some_data: [100]u8 = { + \\ @setGlobalAlign(some_data, 3); + \\ undefined + \\}; + \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } + , ".tmp_source.zig:2:32: error: alignment value must be power of 2"); + + cases.add("compile log", + \\export fn foo() { + \\ comptime bar(12, "hi"); + \\} + \\fn bar(a: i32, b: []const u8) { + \\ @compileLog("begin"); + \\ @compileLog("a", a, "b", b); + \\ @compileLog("end"); + \\} + , + ".tmp_source.zig:5:5: error: found compile log statement", + ".tmp_source.zig:2:17: note: called from here", + ".tmp_source.zig:6:5: error: found compile log statement", + ".tmp_source.zig:2:17: note: called from here", + ".tmp_source.zig:7:5: error: found compile log statement", + ".tmp_source.zig:2:17: note: called from here"); + + cases.add("casting bit offset pointer to regular pointer", + \\const u2 = @IntType(false, 2); + \\const u3 = @IntType(false, 3); + \\ + \\const BitField = packed struct { + \\ a: u3, + \\ b: u3, + \\ c: u2, + \\}; + \\ + \\fn foo(bit_field: &const BitField) -> u3 { + \\ return bar(&bit_field.b); + \\} + \\ + \\fn bar(x: &const u3) -> u3 { + \\ return *x; + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:11:26: error: expected type '&const u3', found '&:3:6 const u3'"); + + cases.add("referring to a struct that is invalid", + \\const UsbDeviceRequest = struct { + \\ Type: u8, + \\}; + \\ + \\export fn foo() { + \\ comptime assert(@sizeOf(UsbDeviceRequest) == 0x8); + \\} + \\ + \\fn assert(ok: bool) { + \\ if (!ok) unreachable; + \\} + , + ".tmp_source.zig:10:14: error: unable to evaluate constant expression", + ".tmp_source.zig:6:20: note: called from here"); + + cases.add("control flow uses comptime var at runtime", + \\export fn foo() { + \\ comptime var i = 0; + \\ while (i < 5; i += 1) { + \\ bar(); + \\ } + \\} + \\ + \\fn bar() { } + , + ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime", + ".tmp_source.zig:3:21: note: compile-time variable assigned here"); + + cases.add("ignored return value", + \\export fn foo() { + \\ bar(); + \\} + \\fn bar() -> i32 { 0 } + , ".tmp_source.zig:2:8: error: return value ignored"); + + cases.add("integer literal on a non-comptime var", + \\export fn foo() { + \\ var i = 0; + \\ while (i < 10; i += 1) { } + \\} + , ".tmp_source.zig:2:5: error: unable to infer variable type"); + + cases.add("undefined literal on a non-comptime var", + \\export fn foo() { + \\ var i = undefined; + \\ i = i32(1); + \\} + , ".tmp_source.zig:2:5: error: unable to infer variable type"); + + cases.add("dereference an array", + \\var s_buffer: [10]u8 = undefined; + \\pub fn pass(in: []u8) -> []u8 { + \\ var out = &s_buffer; + \\ *out[0] = in[0]; + \\ return (*out)[0...1]; + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) } + , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'"); + + cases.add("pass const ptr to mutable ptr fn", + \\fn foo() -> bool { + \\ const a = ([]const u8)("a"); + \\ const b = &a; + \\ return ptrEql(b, b); + \\} + \\fn ptrEql(a: &[]const u8, b: &[]const u8) -> bool { + \\ return true; + \\} + \\ + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'"); + + cases.addCase({ + const tc = cases.create("export collision", + \\const foo = @import("foo.zig"); + \\ + \\export fn bar() -> usize { + \\ return foo.baz; + \\} + , + "foo.zig:1:8: error: exported symbol collision: 'bar'", + ".tmp_source.zig:3:8: note: other symbol is here"); + + tc.addSourceFile("foo.zig", + \\export fn bar() {} + \\pub const baz = 1234; + ); + + tc + }); + + cases.add("pass non-copyable type by value to function", + \\const Point = struct { x: i32, y: i32, }; + \\fn foo(p: Point) { } + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value"); + + cases.add("implicit cast from array to mutable slice", + \\var global_array: [10]i32 = undefined; + \\fn foo(param: []i32) {} + \\export fn entry() { + \\ foo(global_array); + \\} + , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'"); + + cases.add("ptrcast to non-pointer", + \\export fn entry(a: &i32) -> usize { + \\ return @ptrcast(usize, a); + \\} + , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'"); + + cases.add("too many error values to cast to small integer", + \\error A; error B; error C; error D; error E; error F; error G; error H; + \\const u2 = @IntType(false, 2); + \\fn foo(e: error) -> u2 { + \\ return u2(e); + \\} + \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) } + , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'"); + + cases.add("asm at compile time", + \\comptime { + \\ doSomeAsm(); + \\} + \\ + \\fn doSomeAsm() { + \\ asm volatile ( + \\ \\.globl aoeu; + \\ \\.type aoeu, @function; + \\ \\.set aoeu, derp; + \\ ); + \\} + , ".tmp_source.zig:6:5: error: unable to evaluate constant expression"); + + cases.add("invalid member of builtin enum", + \\export fn entry() { + \\ const foo = Arch.x86; + \\} + , ".tmp_source.zig:2:21: error: container 'Arch' has no member called 'x86'"); + + cases.add("int to ptr of 0 bits", + \\export fn foo() { + \\ var x: usize = 0x1000; + \\ var y: &void = @intToPtr(&void, x); + \\} + , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information"); + + cases.add("@fieldParentPtr - non struct", + \\const Foo = i32; + \\export fn foo(a: &i32) -> &Foo { + \\ return @fieldParentPtr(Foo, "a", a); + \\} + , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'"); + + cases.add("@fieldParentPtr - bad field name", + \\const Foo = struct { + \\ derp: i32, + \\}; + \\export fn foo(a: &i32) -> &Foo { + \\ return @fieldParentPtr(Foo, "a", a); + \\} + , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'"); + + cases.add("@fieldParentPtr - field pointer is not pointer", + \\const Foo = struct { + \\ a: i32, + \\}; + \\export fn foo(a: i32) -> &Foo { + \\ return @fieldParentPtr(Foo, "a", a); + \\} + , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'"); + + cases.add("@fieldParentPtr - comptime field ptr not based on struct", + \\const Foo = struct { + \\ a: i32, + \\ b: i32, + \\}; + \\const foo = Foo { .a = 1, .b = 2, }; + \\ + \\comptime { + \\ const field_ptr = @intToPtr(&i32, 0x1234); + \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr); + \\} + , ".tmp_source.zig:9:55: error: pointer value not based on parent struct"); + + cases.add("@fieldParentPtr - comptime wrong field index", + \\const Foo = struct { + \\ a: i32, + \\ b: i32, + \\}; + \\const foo = Foo { .a = 1, .b = 2, }; + \\ + \\comptime { + \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a); + \\} + , ".tmp_source.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'"); + + cases.addExe("missing main fn in executable", + \\ + , "error: no member named 'main' in '"); + + cases.addExe("private main fn", + \\fn main() {} + , + "error: 'main' is private", + ".tmp_source.zig:1:1: note: declared here"); + + + + + return cases.step; +} + +const CompileErrorContext = struct { + b: &build.Builder, + step: &build.Step, + test_index: usize, + test_filter: ?[]const u8, + + const TestCase = struct { + name: []const u8, + sources: List(SourceFile), + expected_errors: List([]const u8), + link_libc: bool, + is_exe: bool, + + const SourceFile = struct { + filename: []const u8, + source: []const u8, + }; + + pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) { + %%self.sources.append(SourceFile { + .filename = filename, + .source = source, + }); + } + + pub fn addExpectedError(self: &TestCase, text: []const u8) { + %%self.expected_errors.append(text); + } + }; + + const CompileCmpOutputStep = struct { + step: build.Step, + context: &CompileErrorContext, + name: []const u8, + test_index: usize, + case: &const TestCase, + release: bool, + + pub fn create(context: &CompileErrorContext, name: []const u8, + case: &const TestCase, release: bool) -> &CompileCmpOutputStep + { + const allocator = context.b.allocator; + const ptr = %%allocator.create(CompileCmpOutputStep); + *ptr = CompileCmpOutputStep { + .step = build.Step.init("CompileCmpOutput", allocator, make), + .context = context, + .name = name, + .test_index = context.test_index, + .case = case, + .release = release, + }; + context.test_index += 1; + return ptr; + } + + fn make(step: &build.Step) -> %void { + const self = @fieldParentPtr(CompileCmpOutputStep, "step", step); + const b = self.context.b; + + const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename); + const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o"); + + var zig_args = List([]const u8).init(b.allocator); + %%zig_args.append(if (self.case.is_exe) "build_exe" else "build_obj"); + %%zig_args.append(b.pathFromRoot(root_src)); + + %%zig_args.append("--name"); + %%zig_args.append("test"); + + %%zig_args.append("--output"); + %%zig_args.append(b.pathFromRoot(obj_path)); + + if (self.release) { + %%zig_args.append("--release"); + } + + %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); + + if (b.verbose) { + printInvocation(b.zig_exe, zig_args.toSliceConst()); + } + + var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map, + StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| + { + debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); + }; + + const term = child.wait() %% |err| { + debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err)); + }; + switch (term) { + Term.Clean => |code| { + if (code == 0) { + %%io.stderr.printf("Compilation incorrectly succeeded\n"); + return error.TestFailed; + } + }, + else => { + %%io.stderr.printf("Process {} terminated unexpectedly\n", b.zig_exe); + return error.TestFailed; + }, + }; + + var stdout_buf = %%Buffer0.initEmpty(b.allocator); + var stderr_buf = %%Buffer0.initEmpty(b.allocator); + + %%(??child.stdout).readAll(&stdout_buf); + %%(??child.stderr).readAll(&stderr_buf); + + const stdout = stdout_buf.toSliceConst(); + const stderr = stderr_buf.toSliceConst(); + + if (stdout.len != 0) { + %%io.stderr.printf( + \\ + \\Expected empty stdout, instead found: + \\================================================ + \\{} + \\================================================ + \\ + , stdout); + return error.TestFailed; + } + + for (self.case.expected_errors.toSliceConst()) |expected_error| { + if (mem.indexOf(u8, stderr, expected_error) == null) { + %%io.stderr.printf( + \\ + \\========= Expected this compile error: ========= + \\{} + \\================================================ + \\{} + \\ + , expected_error, stderr); + return error.TestFailed; + } + } + %%io.stderr.printf("OK\n"); + } + }; + + fn printInvocation(exe_path: []const u8, args: []const []const u8) { + %%io.stderr.printf("{}", exe_path); + for (args) |arg| { + %%io.stderr.printf(" {}", arg); + } + %%io.stderr.printf("\n"); + } + + pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8, + expected_lines: ...) -> &TestCase + { + const tc = %%self.b.allocator.create(TestCase); + *tc = TestCase { + .name = name, + .sources = List(TestCase.SourceFile).init(self.b.allocator), + .expected_errors = List([]const u8).init(self.b.allocator), + .link_libc = false, + .is_exe = false, + }; + tc.addSourceFile(".tmp_source.zig", source); + comptime var arg_i = 0; + inline while (arg_i < expected_lines.len; arg_i += 1) { + // TODO mem.dupe is because of issue #336 + tc.addExpectedError(%%mem.dupe(self.b.allocator, u8, expected_lines[arg_i])); + } + return tc; + } + + pub fn addC(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) { + var tc = self.create(name, source, expected_lines); + tc.link_libc = true; + self.addCase(tc); + } + + pub fn addExe(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) { + var tc = self.create(name, source, expected_lines); + tc.is_exe = true; + self.addCase(tc); + } + + pub fn add(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) { + const tc = self.create(name, source, expected_lines); + self.addCase(tc); + } + + pub fn addCase(self: &CompileErrorContext, case: &const TestCase) { + const b = self.b; + + for ([]bool{false, true}) |release| { + const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} ({})", + case.name, if (release) "release" else "debug"); + if (const filter ?= self.test_filter) { + if (mem.indexOf(u8, annotated_case_name, filter) == null) + continue; + } + + const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, release); + self.step.dependOn(&compile_and_cmp_errors.step); + + for (case.sources.toSliceConst()) |src_file| { + const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); + const write_src = b.addWriteFile(expanded_src_path, src_file.source); + compile_and_cmp_errors.step.dependOn(&write_src.step); + } + } + } +}; diff --git a/test/run_tests.cpp b/test/run_tests.cpp index ef89ee81b7..2f960f2440 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -16,8 +16,6 @@ enum TestSpecial { TestSpecialNone, - TestSpecialSelfHosted, - TestSpecialStd, TestSpecialLinkStep, }; @@ -60,37 +58,6 @@ static const char *zig_exe = "./zig"; #define NL "\n" #endif -static void add_source_file(TestCase *test_case, const char *path, const char *source) { - test_case->source_files.add_one(); - test_case->source_files.last().relative_path = path; - test_case->source_files.last().source_code = source; -} - -static TestCase *add_simple_case(const char *case_name, const char *source, const char *output) { - TestCase *test_case = allocate(1); - test_case->case_name = case_name; - test_case->output = output; - - test_case->source_files.resize(1); - test_case->source_files.at(0).relative_path = tmp_source_path; - test_case->source_files.at(0).source_code = source; - - test_case->compiler_args.append("build_exe"); - test_case->compiler_args.append(tmp_source_path); - test_case->compiler_args.append("--name"); - test_case->compiler_args.append("test"); - test_case->compiler_args.append("--output"); - test_case->compiler_args.append(tmp_exe_path); - test_case->compiler_args.append("--release"); - test_case->compiler_args.append("--strip"); - test_case->compiler_args.append("--color"); - test_case->compiler_args.append("on"); - - test_cases.append(test_case); - - return test_case; -} - static TestCase *add_asm_case(const char *case_name, const char *source, const char *output) { TestCase *test_case = allocate(1); test_case->case_name = case_name; @@ -122,77 +89,6 @@ static TestCase *add_asm_case(const char *case_name, const char *source, const c return test_case; } -static TestCase *add_simple_case_libc(const char *case_name, const char *source, const char *output) { - TestCase *tc = add_simple_case(case_name, source, output); - tc->compiler_args.append("--library"); - tc->compiler_args.append("c"); - return tc; -} - -static TestCase *add_compile_fail_case(const char *case_name, const char *source, size_t count, ...) { - va_list ap; - va_start(ap, count); - - TestCase *test_case = allocate(1); - test_case->case_name = case_name; - test_case->source_files.resize(1); - test_case->source_files.at(0).relative_path = tmp_source_path; - test_case->source_files.at(0).source_code = source; - - for (size_t i = 0; i < count; i += 1) { - const char *arg = va_arg(ap, const char *); - test_case->compile_errors.append(arg); - } - - test_case->compiler_args.append("build_obj"); - test_case->compiler_args.append(tmp_source_path); - - test_case->compiler_args.append("--name"); - test_case->compiler_args.append("test"); - - test_case->compiler_args.append("--output"); - test_case->compiler_args.append(tmp_exe_path); - - test_case->compiler_args.append("--release"); - test_case->compiler_args.append("--strip"); - - test_cases.append(test_case); - - return test_case; -} - -static TestCase *add_compile_fail_case_exe(const char *case_name, const char *source, size_t count, ...) { - va_list ap; - va_start(ap, count); - - TestCase *test_case = allocate(1); - test_case->case_name = case_name; - test_case->source_files.resize(1); - test_case->source_files.at(0).relative_path = tmp_source_path; - test_case->source_files.at(0).source_code = source; - - for (size_t i = 0; i < count; i += 1) { - const char *arg = va_arg(ap, const char *); - test_case->compile_errors.append(arg); - } - - test_case->compiler_args.append("build_exe"); - test_case->compiler_args.append(tmp_source_path); - - test_case->compiler_args.append("--name"); - test_case->compiler_args.append("test"); - - test_case->compiler_args.append("--output"); - test_case->compiler_args.append(tmp_exe_path); - - test_case->compiler_args.append("--release"); - test_case->compiler_args.append("--strip"); - - test_cases.append(test_case); - - return test_case; -} - static void add_debug_safety_case(const char *case_name, const char *source) { TestCase *test_case = allocate(1); test_case->is_debug_safety = true; @@ -242,1617 +138,6 @@ static TestCase *add_parseh_case(const char *case_name, AllowWarnings allow_warn va_end(ap); return test_case; } - -static TestCase *add_example_compile_extra(const char *root_source_file, bool libc) { - TestCase *test_case = allocate(1); - test_case->case_name = buf_ptr(buf_sprintf("build example %s", root_source_file)); - test_case->output = nullptr; - test_case->special = TestSpecialNone; - - test_case->compiler_args.append("build_exe"); - test_case->compiler_args.append(buf_ptr(buf_sprintf("../%s", root_source_file))); - - if (libc) { - test_case->compiler_args.append("--library"); - test_case->compiler_args.append("c"); - } - - test_cases.append(test_case); - - return test_case; -} - -static TestCase *add_example_compile(const char *root_source_file) { - return add_example_compile_extra(root_source_file, false); -} - -static TestCase *add_example_compile_libc(const char *root_source_file) { - return add_example_compile_extra(root_source_file, true); -} - -//////////////////////////////////////////////////////////////////////////////////// - - -//////////////////////////////////////////////////////////////////////////////////// - -static void add_compile_failure_test_cases(void) { - add_compile_fail_case("multiple function definitions", R"SOURCE( -fn a() {} -fn a() {} -export fn entry() { a(); } - )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'"); - - add_compile_fail_case("unreachable with return", R"SOURCE( -fn a() -> noreturn {return;} -export fn entry() { a(); } - )SOURCE", 1, ".tmp_source.zig:2:21: error: expected type 'noreturn', found 'void'"); - - add_compile_fail_case("control reaches end of non-void function", R"SOURCE( -fn a() -> i32 {} -export fn entry() { _ = a(); } - )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', found 'void'"); - - add_compile_fail_case("undefined function call", R"SOURCE( -export fn a() { - b(); -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'"); - - add_compile_fail_case("wrong number of arguments", R"SOURCE( -export fn a() { - b(1); -} -fn b(a: i32, b: i32, c: i32) { } - )SOURCE", 1, ".tmp_source.zig:3:6: error: expected 3 arguments, found 1"); - - add_compile_fail_case("invalid type", R"SOURCE( -fn a() -> bogus {} -export fn entry() { _ = a(); } - )SOURCE", 1, ".tmp_source.zig:2:11: error: use of undeclared identifier 'bogus'"); - - add_compile_fail_case("pointer to unreachable", R"SOURCE( -fn a() -> &noreturn {} -export fn entry() { _ = a(); } - )SOURCE", 1, ".tmp_source.zig:2:12: error: pointer to unreachable not allowed"); - - add_compile_fail_case("unreachable code", R"SOURCE( -export fn a() { - return; - b(); -} - -fn b() {} - )SOURCE", 1, ".tmp_source.zig:4:6: error: unreachable code"); - - add_compile_fail_case("bad import", R"SOURCE( -const bogus = @import("bogus-does-not-exist.zig"); -export fn entry() { bogus.bogo(); } - )SOURCE", 1, ".tmp_source.zig:2:15: error: unable to find 'bogus-does-not-exist.zig'"); - - add_compile_fail_case("undeclared identifier", R"SOURCE( -export fn a() { - b + - c -} - )SOURCE", 2, - ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'", - ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'"); - - add_compile_fail_case("parameter redeclaration", R"SOURCE( -fn f(a : i32, a : i32) { -} -export fn entry() { f(1, 2); } - )SOURCE", 1, ".tmp_source.zig:2:15: error: redeclaration of variable 'a'"); - - add_compile_fail_case("local variable redeclaration", R"SOURCE( -export fn f() { - const a : i32 = 0; - const a = 0; -} - )SOURCE", 1, ".tmp_source.zig:4:5: error: redeclaration of variable 'a'"); - - add_compile_fail_case("local variable redeclares parameter", R"SOURCE( -fn f(a : i32) { - const a = 0; -} -export fn entry() { f(1); } - )SOURCE", 1, ".tmp_source.zig:3:5: error: redeclaration of variable 'a'"); - - add_compile_fail_case("variable has wrong type", R"SOURCE( -export fn f() -> i32 { - const a = c"a"; - a -} - )SOURCE", 1, ".tmp_source.zig:4:5: error: expected type 'i32', found '&const u8'"); - - add_compile_fail_case("if condition is bool, not int", R"SOURCE( -export fn f() { - if (0) {} -} - )SOURCE", 1, ".tmp_source.zig:3:9: error: integer value 0 cannot be implicitly casted to type 'bool'"); - - add_compile_fail_case("assign unreachable", R"SOURCE( -export fn f() { - const a = return; -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: unreachable code"); - - add_compile_fail_case("unreachable variable", R"SOURCE( -export fn f() { - const a: noreturn = {}; -} - )SOURCE", 1, ".tmp_source.zig:3:14: error: variable of type 'noreturn' not allowed"); - - add_compile_fail_case("unreachable parameter", R"SOURCE( -fn f(a: noreturn) {} -export fn entry() { f(); } - )SOURCE", 1, ".tmp_source.zig:2:9: error: parameter of type 'noreturn' not allowed"); - - add_compile_fail_case("bad assignment target", R"SOURCE( -export fn f() { - 3 = 3; -} - )SOURCE", 1, ".tmp_source.zig:3:7: error: cannot assign to constant"); - - add_compile_fail_case("assign to constant variable", R"SOURCE( -export fn f() { - const a = 3; - a = 4; -} - )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant"); - - add_compile_fail_case("use of undeclared identifier", R"SOURCE( -export fn f() { - b = 3; -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'"); - - add_compile_fail_case("const is a statement, not an expression", R"SOURCE( -export fn f() { - (const a = 0); -} - )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'const'"); - - add_compile_fail_case("array access of undeclared identifier", R"SOURCE( -export fn f() { - i[i] = i[i]; -} - )SOURCE", 2, ".tmp_source.zig:3:5: error: use of undeclared identifier 'i'", - ".tmp_source.zig:3:12: error: use of undeclared identifier 'i'"); - - add_compile_fail_case("array access of non array", R"SOURCE( -export fn f() { - var bad : bool = undefined; - bad[bad] = bad[bad]; -} - )SOURCE", 2, ".tmp_source.zig:4:8: error: array access of non-array type 'bool'", - ".tmp_source.zig:4:19: error: array access of non-array type 'bool'"); - - add_compile_fail_case("array access with non integer index", R"SOURCE( -export fn f() { - var array = "aoeu"; - var bad = false; - array[bad] = array[bad]; -} - )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'", - ".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'"); - - add_compile_fail_case("write to const global variable", R"SOURCE( -const x : i32 = 99; -fn f() { - x = 1; -} -export fn entry() { f(); } - )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant"); - - - add_compile_fail_case("missing else clause", R"SOURCE( -fn f(b: bool) { - const x : i32 = if (b) { 1 }; - const y = if (b) { i32(1) }; -} -export fn entry() { f(true); } - )SOURCE", 2, ".tmp_source.zig:3:30: error: integer value 1 cannot be implicitly casted to type 'void'", - ".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'"); - - add_compile_fail_case("direct struct loop", R"SOURCE( -const A = struct { a : A, }; -export fn entry() -> usize { @sizeOf(A) } - )SOURCE", 1, ".tmp_source.zig:2:11: error: struct 'A' contains itself"); - - add_compile_fail_case("indirect struct loop", R"SOURCE( -const A = struct { b : B, }; -const B = struct { c : C, }; -const C = struct { a : A, }; -export fn entry() -> usize { @sizeOf(A) } - )SOURCE", 1, ".tmp_source.zig:2:11: error: struct 'A' contains itself"); - - add_compile_fail_case("invalid struct field", R"SOURCE( -const A = struct { x : i32, }; -export fn f() { - var a : A = undefined; - a.foo = 1; - const y = a.bar; -} - )SOURCE", 2, - ".tmp_source.zig:5:6: error: no member named 'foo' in 'A'", - ".tmp_source.zig:6:16: error: no member named 'bar' in 'A'"); - - add_compile_fail_case("redefinition of struct", R"SOURCE( -const A = struct { x : i32, }; -const A = struct { y : i32, }; - )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'"); - - add_compile_fail_case("redefinition of enums", R"SOURCE( -const A = enum {}; -const A = enum {}; - )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'"); - - add_compile_fail_case("redefinition of global variables", R"SOURCE( -var a : i32 = 1; -var a : i32 = 2; - )SOURCE", 2, - ".tmp_source.zig:3:1: error: redefinition of 'a'", - ".tmp_source.zig:2:1: note: previous definition is here"); - - add_compile_fail_case("byvalue struct parameter in exported function", R"SOURCE( -const A = struct { x : i32, }; -export fn f(a : A) {} - )SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue types not yet supported on extern function parameters"); - - add_compile_fail_case("byvalue struct return value in exported function", R"SOURCE( -const A = struct { x: i32, }; -export fn f() -> A { - A {.x = 1234 } -} - )SOURCE", 1, ".tmp_source.zig:3:18: error: byvalue types not yet supported on extern function return values"); - - add_compile_fail_case("duplicate field in struct value expression", R"SOURCE( -const A = struct { - x : i32, - y : i32, - z : i32, -}; -export fn f() { - const a = A { - .z = 1, - .y = 2, - .x = 3, - .z = 4, - }; -} - )SOURCE", 1, ".tmp_source.zig:12:9: error: duplicate field"); - - add_compile_fail_case("missing field in struct value expression", R"SOURCE( -const A = struct { - x : i32, - y : i32, - z : i32, -}; -export fn f() { - // we want the error on the '{' not the 'A' because - // the A could be a complicated expression - const a = A { - .z = 4, - .y = 2, - }; -} - )SOURCE", 1, ".tmp_source.zig:10:17: error: missing field: 'x'"); - - add_compile_fail_case("invalid field in struct value expression", R"SOURCE( -const A = struct { - x : i32, - y : i32, - z : i32, -}; -export fn f() { - const a = A { - .z = 4, - .y = 2, - .foo = 42, - }; -} - )SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'"); - - add_compile_fail_case("invalid break expression", R"SOURCE( -export fn f() { - break; -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression outside loop"); - - add_compile_fail_case("invalid continue expression", R"SOURCE( -export fn f() { - continue; -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression outside loop"); - - add_compile_fail_case("invalid maybe type", R"SOURCE( -export fn f() { - if (const x ?= true) { } -} - )SOURCE", 1, ".tmp_source.zig:3:20: error: expected nullable type, found 'bool'"); - - add_compile_fail_case("cast unreachable", R"SOURCE( -fn f() -> i32 { - i32(return 1) -} -export fn entry() { _ = f(); } - )SOURCE", 1, ".tmp_source.zig:3:8: error: unreachable code"); - - add_compile_fail_case("invalid builtin fn", R"SOURCE( -fn f() -> @bogus(foo) { -} -export fn entry() { _ = f(); } - )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid builtin function: 'bogus'"); - - add_compile_fail_case("top level decl dependency loop", R"SOURCE( -const a : @typeOf(b) = 0; -const b : @typeOf(a) = 0; -export fn entry() { - const c = a + b; -} - )SOURCE", 1, ".tmp_source.zig:2:1: error: 'a' depends on itself"); - - add_compile_fail_case("noalias on non pointer param", R"SOURCE( -fn f(noalias x: i32) {} -export fn entry() { f(1234); } - )SOURCE", 1, ".tmp_source.zig:2:6: error: noalias on non-pointer parameter"); - - add_compile_fail_case("struct init syntax for array", R"SOURCE( -const foo = []u16{.x = 1024,}; -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:2:18: error: type '[]u16' does not support struct initialization syntax"); - - add_compile_fail_case("type variables must be constant", R"SOURCE( -var foo = u8; -export fn entry() -> foo { - return 1; -} - )SOURCE", 1, ".tmp_source.zig:2:1: error: variable of type 'type' must be constant"); - - - add_compile_fail_case("variables shadowing types", R"SOURCE( -const Foo = struct {}; -const Bar = struct {}; - -fn f(Foo: i32) { - var Bar : i32 = undefined; -} - -export fn entry() { - f(1234); -} - )SOURCE", 4, - ".tmp_source.zig:5:6: error: redefinition of 'Foo'", - ".tmp_source.zig:2:1: note: previous definition is here", - ".tmp_source.zig:6:5: error: redefinition of 'Bar'", - ".tmp_source.zig:3:1: note: previous definition is here"); - - add_compile_fail_case("multiple else prongs in a switch", R"SOURCE( -fn f(x: u32) { - const value: bool = switch (x) { - 1234 => false, - else => true, - else => true, - }; -} -export fn entry() { - f(1234); -} - )SOURCE", 1, ".tmp_source.zig:6:9: error: multiple else prongs in switch expression"); - - add_compile_fail_case("global variable initializer must be constant expression", R"SOURCE( -extern fn foo() -> i32; -const x = foo(); -export fn entry() -> i32 { x } - )SOURCE", 1, ".tmp_source.zig:3:11: error: unable to evaluate constant expression"); - - add_compile_fail_case("array concatenation with wrong type", R"SOURCE( -const src = "aoeu"; -const derp = usize(1234); -const a = derp ++ "foo"; - -export fn entry() -> usize { @sizeOf(@typeOf(a)) } - )SOURCE", 1, ".tmp_source.zig:4:11: error: expected array or C string literal, found 'usize'"); - - add_compile_fail_case("non compile time array concatenation", R"SOURCE( -fn f() -> []u8 { - s ++ "foo" -} -var s: [10]u8 = undefined; -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to evaluate constant expression"); - - add_compile_fail_case("@cImport with bogus include", R"SOURCE( -const c = @cImport(@cInclude("bogus.h")); -export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) } - )SOURCE", 2, ".tmp_source.zig:2:11: error: C import failed", - ".h:1:10: note: 'bogus.h' file not found"); - - add_compile_fail_case("address of number literal", R"SOURCE( -const x = 3; -const y = &x; -fn foo() -> &const i32 { y } -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:4:26: error: expected type '&const i32', found '&const (integer literal)'"); - - add_compile_fail_case("integer overflow error", R"SOURCE( -const x : u8 = 300; -export fn entry() -> usize { @sizeOf(@typeOf(x)) } - )SOURCE", 1, ".tmp_source.zig:2:16: error: integer value 300 cannot be implicitly casted to type 'u8'"); - - add_compile_fail_case("incompatible number literals", R"SOURCE( -const x = 2 == 2.0; -export fn entry() -> usize { @sizeOf(@typeOf(x)) } - )SOURCE", 1, ".tmp_source.zig:2:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'"); - - add_compile_fail_case("missing function call param", R"SOURCE( -const Foo = struct { - a: i32, - b: i32, - - fn member_a(foo: &const Foo) -> i32 { - return foo.a; - } - fn member_b(foo: &const Foo) -> i32 { - return foo.b; - } -}; - -const member_fn_type = @typeOf(Foo.member_a); -const members = []member_fn_type { - Foo.member_a, - Foo.member_b, -}; - -fn f(foo: &const Foo, index: usize) { - const result = members[index](); -} - -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:21:34: error: expected 1 arguments, found 0"); - - add_compile_fail_case("missing function name and param name", R"SOURCE( -fn () {} -fn f(i32) {} -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 2, - ".tmp_source.zig:2:1: error: missing function name", - ".tmp_source.zig:3:6: error: missing parameter name"); - - add_compile_fail_case("wrong function type", R"SOURCE( -const fns = []fn(){ a, b, c }; -fn a() -> i32 {0} -fn b() -> i32 {1} -fn c() -> i32 {2} -export fn entry() -> usize { @sizeOf(@typeOf(fns)) } - )SOURCE", 1, ".tmp_source.zig:2:21: error: expected type 'fn()', found 'fn() -> i32'"); - - add_compile_fail_case("extern function pointer mismatch", R"SOURCE( -const fns = [](fn(i32)->i32){ a, b, c }; -pub fn a(x: i32) -> i32 {x + 0} -pub fn b(x: i32) -> i32 {x + 1} -export fn c(x: i32) -> i32 {x + 2} - -export fn entry() -> usize { @sizeOf(@typeOf(fns)) } - )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'"); - - - add_compile_fail_case("implicit cast from f64 to f32", R"SOURCE( -const x : f64 = 1.0; -const y : f32 = x; - -export fn entry() -> usize { @sizeOf(@typeOf(y)) } - )SOURCE", 1, ".tmp_source.zig:3:17: error: expected type 'f32', found 'f64'"); - - - add_compile_fail_case("colliding invalid top level functions", R"SOURCE( -fn func() -> bogus {} -fn func() -> bogus {} -export fn entry() -> usize { @sizeOf(@typeOf(func)) } - )SOURCE", 2, - ".tmp_source.zig:3:1: error: redefinition of 'func'", - ".tmp_source.zig:2:14: error: use of undeclared identifier 'bogus'"); - - - add_compile_fail_case("bogus compile var", R"SOURCE( -const x = @compileVar("bogus"); -export fn entry() -> usize { @sizeOf(@typeOf(x)) } - )SOURCE", 1, ".tmp_source.zig:2:23: error: unrecognized compile variable: 'bogus'"); - - - add_compile_fail_case("non constant expression in array size outside function", R"SOURCE( -const Foo = struct { - y: [get()]u8, -}; -var global_var: usize = 1; -fn get() -> usize { global_var } - -export fn entry() -> usize { @sizeOf(@typeOf(Foo)) } - )SOURCE", 3, - ".tmp_source.zig:6:21: error: unable to evaluate constant expression", - ".tmp_source.zig:3:12: note: called from here", - ".tmp_source.zig:3:8: note: called from here"); - - - add_compile_fail_case("addition with non numbers", R"SOURCE( -const Foo = struct { - field: i32, -}; -const x = Foo {.field = 1} + Foo {.field = 2}; - -export fn entry() -> usize { @sizeOf(@typeOf(x)) } - )SOURCE", 1, ".tmp_source.zig:5:28: error: invalid operands to binary expression: 'Foo' and 'Foo'"); - - - add_compile_fail_case("division by zero", R"SOURCE( -const lit_int_x = 1 / 0; -const lit_float_x = 1.0 / 0.0; -const int_x = i32(1) / i32(0); -const float_x = f32(1.0) / f32(0.0); - -export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) } -export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) } -export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) } -export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) } - )SOURCE", 4, - ".tmp_source.zig:2:21: error: division by zero is undefined", - ".tmp_source.zig:3:25: error: division by zero is undefined", - ".tmp_source.zig:4:22: error: division by zero is undefined", - ".tmp_source.zig:5:26: error: division by zero is undefined"); - - - add_compile_fail_case("missing switch prong", R"SOURCE( -const Number = enum { - One, - Two, - Three, - Four, -}; -fn f(n: Number) -> i32 { - switch (n) { - Number.One => 1, - Number.Two => 2, - Number.Three => i32(3), - } -} - -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:9:5: error: enumeration value 'Number.Four' not handled in switch"); - - add_compile_fail_case("normal string with newline", R"SOURCE( -const foo = "a -b"; - -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:2:13: error: newline not allowed in string literal"); - - add_compile_fail_case("invalid comparison for function pointers", R"SOURCE( -fn foo() {} -const invalid = foo > foo; - -export fn entry() -> usize { @sizeOf(@typeOf(invalid)) } - )SOURCE", 1, ".tmp_source.zig:3:21: error: operator not allowed for type 'fn()'"); - - add_compile_fail_case("generic function instance with non-constant expression", R"SOURCE( -fn foo(comptime x: i32, y: i32) -> i32 { return x + y; } -fn test1(a: i32, b: i32) -> i32 { - return foo(a, b); -} - -export fn entry() -> usize { @sizeOf(@typeOf(test1)) } - )SOURCE", 1, ".tmp_source.zig:4:16: error: unable to evaluate constant expression"); - - add_compile_fail_case("goto jumping into block", R"SOURCE( -export fn f() { - { -a_label: - } - goto a_label; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: no label in scope named 'a_label'"); - - add_compile_fail_case("goto jumping past a defer", R"SOURCE( -fn f(b: bool) { - if (b) goto label; - defer derp(); -label: -} -fn derp(){} - -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:3:12: error: no label in scope named 'label'"); - - add_compile_fail_case("assign null to non-nullable pointer", R"SOURCE( -const a: &u8 = null; - -export fn entry() -> usize { @sizeOf(@typeOf(a)) } - )SOURCE", 1, ".tmp_source.zig:2:16: error: expected type '&u8', found '(null)'"); - - add_compile_fail_case("indexing an array of size zero", R"SOURCE( -const array = []u8{}; -export fn foo() { - const pointer = &array[0]; -} - )SOURCE", 1, ".tmp_source.zig:4:27: error: index 0 outside array of size 0"); - - add_compile_fail_case("compile time division by zero", R"SOURCE( -const y = foo(0); -fn foo(x: i32) -> i32 { - 1 / x -} - -export fn entry() -> usize { @sizeOf(@typeOf(y)) } - )SOURCE", 2, - ".tmp_source.zig:4:7: error: division by zero is undefined", - ".tmp_source.zig:2:14: note: called from here"); - - add_compile_fail_case("branch on undefined value", R"SOURCE( -const x = if (undefined) true else false; - -export fn entry() -> usize { @sizeOf(@typeOf(x)) } - )SOURCE", 1, ".tmp_source.zig:2:15: error: use of undefined value"); - - - add_compile_fail_case("endless loop in function evaluation", R"SOURCE( -const seventh_fib_number = fibbonaci(7); -fn fibbonaci(x: i32) -> i32 { - return fibbonaci(x - 1) + fibbonaci(x - 2); -} - -export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) } - )SOURCE", 2, - ".tmp_source.zig:4:21: error: evaluation exceeded 1000 backwards branches", - ".tmp_source.zig:4:21: note: called from here"); - - add_compile_fail_case("@embedFile with bogus file", R"SOURCE( -const resource = @embedFile("bogus.txt"); - -export fn entry() -> usize { @sizeOf(@typeOf(resource)) } - )SOURCE", 2, ".tmp_source.zig:2:29: error: unable to find '", "/bogus.txt'"); - - add_compile_fail_case("non-const expression in struct literal outside function", R"SOURCE( -const Foo = struct { - x: i32, -}; -const a = Foo {.x = get_it()}; -extern fn get_it() -> i32; - -export fn entry() -> usize { @sizeOf(@typeOf(a)) } - )SOURCE", 1, ".tmp_source.zig:5:21: error: unable to evaluate constant expression"); - - add_compile_fail_case("non-const expression function call with struct return value outside function", R"SOURCE( -const Foo = struct { - x: i32, -}; -const a = get_it(); -fn get_it() -> Foo { - global_side_effect = true; - Foo {.x = 13} -} -var global_side_effect = false; - -export fn entry() -> usize { @sizeOf(@typeOf(a)) } - )SOURCE", 2, - ".tmp_source.zig:7:24: error: unable to evaluate constant expression", - ".tmp_source.zig:5:17: note: called from here"); - - add_compile_fail_case("undeclared identifier error should mark fn as impure", R"SOURCE( -export fn foo() { - test_a_thing(); -} -fn test_a_thing() { - bad_fn_call(); -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: use of undeclared identifier 'bad_fn_call'"); - - add_compile_fail_case("illegal comparison of types", R"SOURCE( -fn bad_eql_1(a: []u8, b: []u8) -> bool { - a == b -} -const EnumWithData = enum { - One, - Two: i32, -}; -fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool { - *a == *b -} - -export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) } -export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) } - )SOURCE", 2, - ".tmp_source.zig:3:7: error: operator not allowed for type '[]u8'", - ".tmp_source.zig:10:8: error: operator not allowed for type 'EnumWithData'"); - - add_compile_fail_case("non-const switch number literal", R"SOURCE( -export fn foo() { - const x = switch (bar()) { - 1, 2 => 1, - 3, 4 => 2, - else => 3, - }; -} -fn bar() -> i32 { - 2 -} - )SOURCE", 1, ".tmp_source.zig:3:15: error: unable to infer expression type"); - - add_compile_fail_case("atomic orderings of cmpxchg - failure stricter than success", R"SOURCE( -export fn f() { - var x: i32 = 1234; - while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {} -} - )SOURCE", 1, ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success"); - - add_compile_fail_case("atomic orderings of cmpxchg - success Monotonic or stricter", R"SOURCE( -export fn f() { - var x: i32 = 1234; - while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {} -} - )SOURCE", 1, ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter"); - - add_compile_fail_case("negation overflow in function evaluation", R"SOURCE( -const y = neg(-128); -fn neg(x: i8) -> i8 { - -x -} - -export fn entry() -> usize { @sizeOf(@typeOf(y)) } - )SOURCE", 2, - ".tmp_source.zig:4:5: error: negation caused overflow", - ".tmp_source.zig:2:14: note: called from here"); - - add_compile_fail_case("add overflow in function evaluation", R"SOURCE( -const y = add(65530, 10); -fn add(a: u16, b: u16) -> u16 { - a + b -} - -export fn entry() -> usize { @sizeOf(@typeOf(y)) } - )SOURCE", 2, - ".tmp_source.zig:4:7: error: operation caused overflow", - ".tmp_source.zig:2:14: note: called from here"); - - - add_compile_fail_case("sub overflow in function evaluation", R"SOURCE( -const y = sub(10, 20); -fn sub(a: u16, b: u16) -> u16 { - a - b -} - -export fn entry() -> usize { @sizeOf(@typeOf(y)) } - )SOURCE", 2, - ".tmp_source.zig:4:7: error: operation caused overflow", - ".tmp_source.zig:2:14: note: called from here"); - - add_compile_fail_case("mul overflow in function evaluation", R"SOURCE( -const y = mul(300, 6000); -fn mul(a: u16, b: u16) -> u16 { - a * b -} - -export fn entry() -> usize { @sizeOf(@typeOf(y)) } - )SOURCE", 2, - ".tmp_source.zig:4:7: error: operation caused overflow", - ".tmp_source.zig:2:14: note: called from here"); - - add_compile_fail_case("truncate sign mismatch", R"SOURCE( -fn f() -> i8 { - const x: u32 = 10; - @truncate(i8, x) -} - -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:4:19: error: expected signed integer type, found 'u32'"); - - add_compile_fail_case("%return in function with non error return type", R"SOURCE( -export fn f() { - %return something(); -} -fn something() -> %void { } - )SOURCE", 1, - ".tmp_source.zig:3:5: error: expected type 'void', found 'error'"); - - add_compile_fail_case("wrong return type for main", R"SOURCE( -pub fn main() { } - )SOURCE", 1, ".tmp_source.zig:2:15: error: expected return type of main to be '%void', instead is 'void'"); - - add_compile_fail_case("double ?? on main return value", R"SOURCE( -pub fn main() -> ??void { -} - )SOURCE", 1, ".tmp_source.zig:2:18: error: expected return type of main to be '%void', instead is '??void'"); - - add_compile_fail_case("invalid pointer for var type", R"SOURCE( -extern fn ext() -> usize; -var bytes: [ext()]u8 = undefined; -export fn f() { - for (bytes) |*b, i| { - *b = u8(i); - } -} - )SOURCE", 1, ".tmp_source.zig:3:13: error: unable to evaluate constant expression"); - - add_compile_fail_case("export function with comptime parameter", R"SOURCE( -export fn foo(comptime x: i32, y: i32) -> i32{ - x + y -} - )SOURCE", 1, ".tmp_source.zig:2:15: error: comptime parameter not allowed in extern function"); - - add_compile_fail_case("extern function with comptime parameter", R"SOURCE( -extern fn foo(comptime x: i32, y: i32) -> i32; -fn f() -> i32 { - foo(1, 2) -} -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:2:15: error: comptime parameter not allowed in extern function"); - - add_compile_fail_case("convert fixed size array to slice with invalid size", R"SOURCE( -export fn f() { - var array: [5]u8 = undefined; - var foo = ([]const u32)(array)[0]; -} - )SOURCE", 1, ".tmp_source.zig:4:28: error: unable to convert [5]u8 to []const u32: size mismatch"); - - add_compile_fail_case("non-pure function returns type", R"SOURCE( -var a: u32 = 0; -pub fn List(comptime T: type) -> type { - a += 1; - SmallList(T, 8) -} - -pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type { - struct { - items: []T, - length: usize, - prealloc_items: [STATIC_SIZE]T, - } -} - -export fn function_with_return_type_type() { - var list: List(i32) = undefined; - list.length = 10; -} - - )SOURCE", 2, - ".tmp_source.zig:4:7: error: unable to evaluate constant expression", - ".tmp_source.zig:17:19: note: called from here"); - - add_compile_fail_case("bogus method call on slice", R"SOURCE( -var self = "aoeu"; -fn f(m: []const u8) { - m.copy(u8, self[0...], m); -} -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:4:6: error: no member named 'copy' in '[]const u8'"); - - add_compile_fail_case("wrong number of arguments for method fn call", R"SOURCE( -const Foo = struct { - fn method(self: &const Foo, a: i32) {} -}; -fn f(foo: &const Foo) { - - foo.method(1, 2); -} -export fn entry() -> usize { @sizeOf(@typeOf(f)) } - )SOURCE", 1, ".tmp_source.zig:7:15: error: expected 2 arguments, found 3"); - - add_compile_fail_case("assign through constant pointer", R"SOURCE( -export fn f() { - var cstr = c"Hat"; - cstr[0] = 'W'; -} - )SOURCE", 1, ".tmp_source.zig:4:11: error: cannot assign to constant"); - - add_compile_fail_case("assign through constant slice", R"SOURCE( -export fn f() { - var cstr: []const u8 = "Hat"; - cstr[0] = 'W'; -} - )SOURCE", 1, ".tmp_source.zig:4:11: error: cannot assign to constant"); - - add_compile_fail_case("main function with bogus args type", R"SOURCE( -pub fn main(args: [][]bogus) -> %void {} - )SOURCE", 1, ".tmp_source.zig:2:23: error: use of undeclared identifier 'bogus'"); - - add_compile_fail_case("for loop missing element param", R"SOURCE( -fn foo(blah: []u8) { - for (blah) { } -} -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:3:5: error: for loop expression missing element parameter"); - - add_compile_fail_case("misspelled type with pointer only reference", R"SOURCE( -const JasonHM = u8; -const JasonList = &JsonNode; - -const JsonOA = enum { - JSONArray: JsonList, - JSONObject: JasonHM, -}; - -const JsonType = enum { - JSONNull: void, - JSONInteger: isize, - JSONDouble: f64, - JSONBool: bool, - JSONString: []u8, - JSONArray, - JSONObject, -}; - -pub const JsonNode = struct { - kind: JsonType, - jobject: ?JsonOA, -}; - -fn foo() { - var jll: JasonList = undefined; - jll.init(1234); - var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} }; -} - -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:6:16: error: use of undeclared identifier 'JsonList'"); - - add_compile_fail_case("method call with first arg type primitive", R"SOURCE( -const Foo = struct { - x: i32, - - fn init(x: i32) -> Foo { - Foo { - .x = x, - } - } -}; - -export fn f() { - const derp = Foo.init(3); - - derp.init(); -} - )SOURCE", 1, ".tmp_source.zig:15:5: error: expected type 'i32', found '&const Foo'"); - - add_compile_fail_case("method call with first arg type wrong container", R"SOURCE( -pub const List = struct { - len: usize, - allocator: &Allocator, - - pub fn init(allocator: &Allocator) -> List { - List { - .len = 0, - .allocator = allocator, - } - } -}; - -pub var global_allocator = Allocator { - .field = 1234, -}; - -pub const Allocator = struct { - field: i32, -}; - -export fn foo() { - var x = List.init(&global_allocator); - x.init(); -} - )SOURCE", 1, ".tmp_source.zig:24:5: error: expected type '&Allocator', found '&List'"); - - add_compile_fail_case("binary not on number literal", R"SOURCE( -const TINY_QUANTUM_SHIFT = 4; -const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT; -var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1); - -export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) } - )SOURCE", 1, ".tmp_source.zig:4:60: error: unable to perform binary not operation on type '(integer literal)'"); - - { - TestCase *tc = add_compile_fail_case("multiple files with private function error", R"SOURCE( -const foo = @import("foo.zig"); - -export fn callPrivFunction() { - foo.privateFunction(); -} - )SOURCE", 2, - ".tmp_source.zig:5:8: error: 'privateFunction' is private", - "foo.zig:2:1: note: declared here"); - - add_source_file(tc, "foo.zig", R"SOURCE( -fn privateFunction() { } - )SOURCE"); - } - - add_compile_fail_case("container init with non-type", R"SOURCE( -const zero: i32 = 0; -const a = zero{1}; - -export fn entry() -> usize { @sizeOf(@typeOf(a)) } - )SOURCE", 1, ".tmp_source.zig:3:11: error: expected type, found 'i32'"); - - add_compile_fail_case("assign to constant field", R"SOURCE( -const Foo = struct { - field: i32, -}; -export fn derp() { - const f = Foo {.field = 1234,}; - f.field = 0; -} - )SOURCE", 1, ".tmp_source.zig:7:13: error: cannot assign to constant"); - - add_compile_fail_case("return from defer expression", R"SOURCE( -pub fn testTrickyDefer() -> %void { - defer canFail() %% {}; - - defer %return canFail(); - - const a = maybeInt() ?? return; -} - -fn canFail() -> %void { } - -pub fn maybeInt() -> ?i32 { - return 0; -} - -export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) } - )SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression"); - - add_compile_fail_case("attempt to access var args out of bounds", R"SOURCE( -fn add(args: ...) -> i32 { - args[0] + args[1] -} - -fn foo() -> i32 { - add(i32(1234)) -} - -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 2, - ".tmp_source.zig:3:19: error: index 1 outside argument list of size 1", - ".tmp_source.zig:7:8: note: called from here"); - - add_compile_fail_case("pass integer literal to var args", R"SOURCE( -fn add(args: ...) -> i32 { - var sum = i32(0); - {comptime var i: usize = 0; inline while (i < args.len; i += 1) { - sum += args[i]; - }} - return sum; -} - -fn bar() -> i32 { - add(1, 2, 3, 4) -} - -export fn entry() -> usize { @sizeOf(@typeOf(bar)) } - )SOURCE", 1, ".tmp_source.zig:11:9: error: parameter of type '(integer literal)' requires comptime"); - - add_compile_fail_case("assign too big number to u16", R"SOURCE( -export fn foo() { - var vga_mem: u16 = 0xB8000; -} - )SOURCE", 1, ".tmp_source.zig:3:24: error: integer value 753664 cannot be implicitly casted to type 'u16'"); - - add_compile_fail_case("set global variable alignment to non power of 2", R"SOURCE( -const some_data: [100]u8 = { - @setGlobalAlign(some_data, 3); - undefined -}; -export fn entry() -> usize { @sizeOf(@typeOf(some_data)) } - )SOURCE", 1, ".tmp_source.zig:3:32: error: alignment value must be power of 2"); - - add_compile_fail_case("compile log", R"SOURCE( -export fn foo() { - comptime bar(12, "hi"); -} -fn bar(a: i32, b: []const u8) { - @compileLog("begin"); - @compileLog("a", a, "b", b); - @compileLog("end"); -} - )SOURCE", 6, - ".tmp_source.zig:6:5: error: found compile log statement", - ".tmp_source.zig:3:17: note: called from here", - ".tmp_source.zig:7:5: error: found compile log statement", - ".tmp_source.zig:3:17: note: called from here", - ".tmp_source.zig:8:5: error: found compile log statement", - ".tmp_source.zig:3:17: note: called from here"); - - add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE( -const u2 = @IntType(false, 2); -const u3 = @IntType(false, 3); - -const BitField = packed struct { - a: u3, - b: u3, - c: u2, -}; - -fn foo(bit_field: &const BitField) -> u3 { - return bar(&bit_field.b); -} - -fn bar(x: &const u3) -> u3 { - return *x; -} - -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:12:26: error: expected type '&const u3', found '&:3:6 const u3'"); - - add_compile_fail_case("referring to a struct that is invalid", R"SOURCE( -const UsbDeviceRequest = struct { - Type: u8, -}; - -export fn foo() { - comptime assert(@sizeOf(UsbDeviceRequest) == 0x8); -} - -fn assert(ok: bool) { - if (!ok) unreachable; -} - )SOURCE", 2, - ".tmp_source.zig:11:14: error: unable to evaluate constant expression", - ".tmp_source.zig:7:20: note: called from here"); - - add_compile_fail_case("control flow uses comptime var at runtime", R"SOURCE( -export fn foo() { - comptime var i = 0; - while (i < 5; i += 1) { - bar(); - } -} - -fn bar() { } - )SOURCE", 2, - ".tmp_source.zig:4:5: error: control flow attempts to use compile-time variable at runtime", - ".tmp_source.zig:4:21: note: compile-time variable assigned here"); - - add_compile_fail_case("ignored return value", R"SOURCE( -export fn foo() { - bar(); -} -fn bar() -> i32 { 0 } - )SOURCE", 1, ".tmp_source.zig:3:8: error: return value ignored"); - - add_compile_fail_case("integer literal on a non-comptime var", R"SOURCE( -export fn foo() { - var i = 0; - while (i < 10; i += 1) { } -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type"); - - add_compile_fail_case("undefined literal on a non-comptime var", R"SOURCE( -export fn foo() { - var i = undefined; - i = i32(1); -} - )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type"); - - add_compile_fail_case("dereference an array", R"SOURCE( -var s_buffer: [10]u8 = undefined; -pub fn pass(in: []u8) -> []u8 { - var out = &s_buffer; - *out[0] = in[0]; - return (*out)[0...1]; -} - -export fn entry() -> usize { @sizeOf(@typeOf(pass)) } - )SOURCE", 1, ".tmp_source.zig:5:5: error: attempt to dereference non pointer type '[10]u8'"); - - add_compile_fail_case("pass const ptr to mutable ptr fn", R"SOURCE( -fn foo() -> bool { - const a = ([]const u8)("a"); - const b = &a; - return ptrEql(b, b); -} -fn ptrEql(a: &[]const u8, b: &[]const u8) -> bool { - return true; -} - -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:5:19: error: expected type '&[]const u8', found '&const []const u8'"); - - { - TestCase *tc = add_compile_fail_case("export collision", R"SOURCE( -const foo = @import("foo.zig"); - -export fn bar() -> usize { - return foo.baz; -} - )SOURCE", 2, - "foo.zig:2:8: error: exported symbol collision: 'bar'", - ".tmp_source.zig:4:8: note: other symbol is here"); - - add_source_file(tc, "foo.zig", R"SOURCE( -export fn bar() {} -pub const baz = 1234; - )SOURCE"); - } - - add_compile_fail_case("pass non-copyable type by value to function", R"SOURCE( -const Point = struct { x: i32, y: i32, }; -fn foo(p: Point) { } -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:3:11: error: type 'Point' is not copyable; cannot pass by value"); - - add_compile_fail_case("implicit cast from array to mutable slice", R"SOURCE( -var global_array: [10]i32 = undefined; -fn foo(param: []i32) {} -export fn entry() { - foo(global_array); -} - )SOURCE", 1, ".tmp_source.zig:5:9: error: expected type '[]i32', found '[10]i32'"); - - add_compile_fail_case("ptrcast to non-pointer", R"SOURCE( -export fn entry(a: &i32) -> usize { - return @ptrcast(usize, a); -} - )SOURCE", 1, ".tmp_source.zig:3:21: error: expected pointer, found 'usize'"); - - add_compile_fail_case("too many error values to cast to small integer", R"SOURCE( -error A; error B; error C; error D; error E; error F; error G; error H; -const u2 = @IntType(false, 2); -fn foo(e: error) -> u2 { - return u2(e); -} -export fn entry() -> usize { @sizeOf(@typeOf(foo)) } - )SOURCE", 1, ".tmp_source.zig:5:14: error: too many error values to fit in 'u2'"); - - add_compile_fail_case("asm at compile time", R"SOURCE( -comptime { - doSomeAsm(); -} - -fn doSomeAsm() { - asm volatile ( - \\.globl aoeu; - \\.type aoeu, @function; - \\.set aoeu, derp; - ); -} - )SOURCE", 1, ".tmp_source.zig:7:5: error: unable to evaluate constant expression"); - - add_compile_fail_case("invalid member of builtin enum", R"SOURCE( -export fn entry() { - const foo = Arch.x86; -} - )SOURCE", 1, ".tmp_source.zig:3:21: error: container 'Arch' has no member called 'x86'"); - - add_compile_fail_case("int to ptr of 0 bits", R"SOURCE( -export fn foo() { - var x: usize = 0x1000; - var y: &void = @intToPtr(&void, x); -} - )SOURCE", 1, ".tmp_source.zig:4:31: error: type '&void' has 0 bits and cannot store information"); - - add_compile_fail_case("@fieldParentPtr - non struct", R"SOURCE( -const Foo = i32; -export fn foo(a: &i32) -> &Foo { - return @fieldParentPtr(Foo, "a", a); -} - )SOURCE", 1, ".tmp_source.zig:4:28: error: expected struct type, found 'i32'"); - - add_compile_fail_case("@fieldParentPtr - bad field name", R"SOURCE( -const Foo = struct { - derp: i32, -}; -export fn foo(a: &i32) -> &Foo { - return @fieldParentPtr(Foo, "a", a); -} - )SOURCE", 1, ".tmp_source.zig:6:33: error: struct 'Foo' has no field 'a'"); - - add_compile_fail_case("@fieldParentPtr - field pointer is not pointer", R"SOURCE( -const Foo = struct { - a: i32, -}; -export fn foo(a: i32) -> &Foo { - return @fieldParentPtr(Foo, "a", a); -} - )SOURCE", 1, ".tmp_source.zig:6:38: error: expected pointer, found 'i32'"); - - add_compile_fail_case("@fieldParentPtr - comptime field ptr not based on struct", R"SOURCE( -const Foo = struct { - a: i32, - b: i32, -}; -const foo = Foo { .a = 1, .b = 2, }; - -comptime { - const field_ptr = @intToPtr(&i32, 0x1234); - const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr); -} - )SOURCE", 1, ".tmp_source.zig:10:55: error: pointer value not based on parent struct"); - - add_compile_fail_case("@fieldParentPtr - comptime wrong field index", R"SOURCE( -const Foo = struct { - a: i32, - b: i32, -}; -const foo = Foo { .a = 1, .b = 2, }; - -comptime { - const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a); -} - )SOURCE", 1, ".tmp_source.zig:9:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'"); - - add_compile_fail_case_exe("missing main fn in executable", R"SOURCE( - )SOURCE", 1, "error: no member named 'main' in '"); - - add_compile_fail_case_exe("private main fn", R"SOURCE( -fn main() {} - )SOURCE", 2, - "error: 'main' is private", - ".tmp_source.zig:2:1: note: declared here"); - -} - -////////////////////////////////////////////////////////////////////////////// - -static void add_parse_error_tests(void) { - add_compile_fail_case("implicit semicolon - block statement", R"SOURCE( -export fn entry() { - {} - var good = {}; - ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - block expr", R"SOURCE( -export fn entry() { - _ = {}; - var good = {}; - _ = {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - comptime statement", R"SOURCE( -export fn entry() { - comptime {} - var good = {}; - comptime ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - comptime expression", R"SOURCE( -export fn entry() { - _ = comptime {}; - var good = {}; - _ = comptime {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - defer", R"SOURCE( -export fn entry() { - defer {} - var good = {}; - defer ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: expected token ';', found 'var'"); - - add_compile_fail_case("implicit semicolon - if statement", R"SOURCE( -export fn entry() { - if(true) {} - var good = {}; - if(true) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if expression", R"SOURCE( -export fn entry() { - _ = if(true) {}; - var good = {}; - _ = if(true) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if-else statement", R"SOURCE( -export fn entry() { - if(true) {} else {} - var good = {}; - if(true) ({}) else ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if-else expression", R"SOURCE( -export fn entry() { - _ = if(true) {} else {}; - var good = {}; - _ = if(true) {} else {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if-else-if statement", R"SOURCE( -export fn entry() { - if(true) {} else if(true) {} - var good = {}; - if(true) ({}) else if(true) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if-else-if expression", R"SOURCE( -export fn entry() { - _ = if(true) {} else if(true) {}; - var good = {}; - _ = if(true) {} else if(true) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if-else-if-else statement", R"SOURCE( -export fn entry() { - if(true) {} else if(true) {} else {} - var good = {}; - if(true) ({}) else if(true) ({}) else ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if-else-if-else expression", R"SOURCE( -export fn entry() { - _ = if(true) {} else if(true) {} else {}; - var good = {}; - _ = if(true) {} else if(true) {} else {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var) statement", R"SOURCE( -export fn entry() { - if(_=foo()) {} - var good = {}; - if(_=foo()) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var) expression", R"SOURCE( -export fn entry() { - _ = if(_=foo()) {}; - var good = {}; - _ = if(_=foo()) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var)-else statement", R"SOURCE( -export fn entry() { - if(_=foo()) {} else {} - var good = {}; - if(_=foo()) ({}) else ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var)-else expression", R"SOURCE( -export fn entry() { - _ = if(_=foo()) {} else {}; - var good = {}; - _ = if(_=foo()) {} else {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var)-else-if(var) statement", R"SOURCE( -export fn entry() { - if(_=foo()) {} else if(_=foo()) {} - var good = {}; - if(_=foo()) ({}) else if(_=foo()) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var)-else-if(var) expression", R"SOURCE( -export fn entry() { - _ = if(_=foo()) {} else if(_=foo()) {}; - var good = {}; - _ = if(_=foo()) {} else if(_=foo()) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var)-else-if(var)-else statement", R"SOURCE( -export fn entry() { - if(_=foo()) {} else if(_=foo()) {} else {} - var good = {}; - if(_=foo()) ({}) else if(_=foo()) ({}) else ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - if(var)-else-if(var)-else expression", R"SOURCE( -export fn entry() { - _ = if(_=foo()) {} else if(_=foo()) {} else {}; - var good = {}; - _ = if(_=foo()) {} else if(_=foo()) {} else {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - try statement", R"SOURCE( -export fn entry() { - try (_ = foo()) {} - var good = {}; - try (_ = foo()) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - try expression", R"SOURCE( -export fn entry() { - _ = try (_ = foo()) {}; - var good = {}; - _ = try (_ = foo()) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - while statement", R"SOURCE( -export fn entry() { - while(true) {} - var good = {}; - while(true) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - while expression", R"SOURCE( -export fn entry() { - _ = while(true) {}; - var good = {}; - _ = while(true) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - while-continue statement", R"SOURCE( -export fn entry() { - while(true;{}) {} - var good = {}; - while(true;{}) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - while-continue expression", R"SOURCE( -export fn entry() { - _ = while(true;{}) {}; - var good = {}; - _ = while(true;{}) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - for statement", R"SOURCE( -export fn entry() { - for(foo()) {} - var good = {}; - for(foo()) ({}) - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); - - add_compile_fail_case("implicit semicolon - for expression", R"SOURCE( -export fn entry() { - _ = for(foo()) {}; - var good = {}; - _ = for(foo()) {} - var bad = {}; -} - )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'"); -} - ////////////////////////////////////////////////////////////////////////////// static void add_debug_safety_test_cases(void) { @@ -2281,95 +566,6 @@ struct comptime { R"(pub const FOO_CHAR = 63;)"); } -static void run_self_hosted_test(bool is_release_mode) { - Buf self_hosted_tests_file = BUF_INIT; - os_path_join(buf_create_from_str(ZIG_TEST_DIR), - buf_create_from_str("self_hosted.zig"), &self_hosted_tests_file); - - Buf zig_stderr = BUF_INIT; - Buf zig_stdout = BUF_INIT; - ZigList args = {0}; - args.append("test"); - args.append(buf_ptr(&self_hosted_tests_file)); - if (is_release_mode) { - args.append("--release"); - } - Termination term; - os_exec_process(zig_exe, args, &term, &zig_stderr, &zig_stdout); - - if (term.how != TerminationIdClean || term.code != 0) { - printf("\nSelf-hosted tests failed:\n"); - printf("./zig"); - for (size_t i = 0; i < args.length; i += 1) { - printf(" %s", args.at(i)); - } - printf("\n%s\n", buf_ptr(&zig_stderr)); - exit(1); - } -} - -static void run_std_lib_test(bool is_release_mode) { - Buf std_index_file = BUF_INIT; - os_path_join(buf_create_from_str(ZIG_STD_DIR), - buf_create_from_str("index.zig"), &std_index_file); - - Buf zig_stderr = BUF_INIT; - Buf zig_stdout = BUF_INIT; - ZigList args = {0}; - args.append("test"); - args.append(buf_ptr(&std_index_file)); - if (is_release_mode) { - args.append("--release"); - } - Termination term; - os_exec_process(zig_exe, args, &term, &zig_stderr, &zig_stdout); - - if (term.how != TerminationIdClean || term.code != 0) { - printf("\nstd lib tests failed:\n"); - printf("./zig"); - for (size_t i = 0; i < args.length; i += 1) { - printf(" %s", args.at(i)); - } - printf("\n%s\n", buf_ptr(&zig_stderr)); - exit(1); - } -} - - -static void add_self_hosted_tests(void) { - { - TestCase *test_case = allocate(1); - test_case->case_name = "self hosted tests (debug)"; - test_case->special = TestSpecialSelfHosted; - test_case->is_release_mode = false; - test_cases.append(test_case); - } - { - TestCase *test_case = allocate(1); - test_case->case_name = "self hosted tests (release)"; - test_case->special = TestSpecialSelfHosted; - test_case->is_release_mode = true; - test_cases.append(test_case); - } -} - -static void add_std_lib_tests(void) { - { - TestCase *test_case = allocate(1); - test_case->case_name = "std (debug)"; - test_case->special = TestSpecialStd; - test_case->is_release_mode = false; - test_cases.append(test_case); - } - { - TestCase *test_case = allocate(1); - test_case->case_name = "std (release)"; - test_case->special = TestSpecialStd; - test_case->is_release_mode = true; - test_cases.append(test_case); - } -} - static void add_asm_tests(void) { #if defined(ZIG_OS_LINUX) && defined(ZIG_ARCH_X86_64) add_asm_case("assemble and link hello world linux x86_64", R"SOURCE( @@ -2423,12 +619,6 @@ static void print_exe_invocation(TestCase *test_case) { } static void run_test(TestCase *test_case) { - if (test_case->special == TestSpecialSelfHosted) { - return run_self_hosted_test(test_case->is_release_mode); - } else if (test_case->special == TestSpecialStd) { - return run_std_lib_test(test_case->is_release_mode); - } - for (size_t i = 0; i < test_case->source_files.length; i += 1) { TestSourceFile *test_source = &test_case->source_files.at(i); os_write_file( @@ -2609,11 +799,7 @@ int main(int argc, char **argv) { } } add_debug_safety_test_cases(); - add_compile_failure_test_cases(); - add_parse_error_tests(); add_parseh_test_cases(); - add_self_hosted_tests(); - add_std_lib_tests(); add_asm_tests(); run_all_tests(grep_text); cleanup(); diff --git a/test/tests.zig b/test/tests.zig index d398133db3..7eccf24232 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1,2 +1,3 @@ pub const addCompareOutputTests = @import("compare_output.zig").addCompareOutputTests; pub const addBuildExampleTests = @import("build_examples.zig").addBuildExampleTests; +pub const addCompileErrorTests = @import("compile_errors.zig").addCompileErrorTests;