authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-20 02:31:28-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-20 02:31:28-04:00
log037a9d937d41552a44f8fd597e14a2d3491cb499
tree398f7b9d18988b61ad12db21aa72e21da3aec4d4
parent237dfdbdc6f83071cff88489cc66cb83a2d65b00
parent8654bc18104d64c7a7f9f80bdba75ed4e0c005fa

Merge branch 'self-hosted-tests'

Now instead of: ``` ./run_tests ``` Do this: ``` ./zig build --build-file ../build.zig test ``` For more options, see: ``` ./zig build --build-file ../build.zig --help ```

30 files changed, 4498 insertions(+), 3200 deletions(-)

CMakeLists.txt+1-16
...@@ -63,14 +63,6 @@ set(ZIG_SOURCES...@@ -63,14 +63,6 @@ set(ZIG_SOURCES
63 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"63 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
64)64)
6565
66set(TEST_SOURCES
67 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
68 "${CMAKE_SOURCE_DIR}/src/util.cpp"
69 "${CMAKE_SOURCE_DIR}/src/os.cpp"
70 "${CMAKE_SOURCE_DIR}/src/error.cpp"
71 "${CMAKE_SOURCE_DIR}/test/run_tests.cpp"
72)
73
74set(C_HEADERS66set(C_HEADERS
75 "${CMAKE_SOURCE_DIR}/c_headers/Intrin.h"67 "${CMAKE_SOURCE_DIR}/c_headers/Intrin.h"
76 "${CMAKE_SOURCE_DIR}/c_headers/__stddef_max_align_t.h"68 "${CMAKE_SOURCE_DIR}/c_headers/__stddef_max_align_t.h"
...@@ -248,19 +240,12 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${Z...@@ -248,19 +240,12 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${Z
248install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")240install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
249install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")241install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")
250242
251add_executable(run_tests ${TEST_SOURCES})
252target_link_libraries(run_tests)
253set_target_properties(run_tests PROPERTIES
254 COMPILE_FLAGS ${EXE_CFLAGS}
255 LINK_FLAGS ${EXE_LDFLAGS}
256)
257
258if (ZIG_TEST_COVERAGE)243if (ZIG_TEST_COVERAGE)
259 add_custom_target(coverage244 add_custom_target(coverage
260 DEPENDS run_tests245 DEPENDS run_tests
261 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}246 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
262 COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1247 COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1
263 COMMAND ./run_tests248 COMMAND ./zig build --build-file ../build.zig test
264 COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1249 COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1
265 COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1250 COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1
266 COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1251 COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1
README.md+3-3
...@@ -45,8 +45,8 @@ compromises backward compatibility....@@ -45,8 +45,8 @@ compromises backward compatibility.
45 * Release mode produces heavily optimized code. What other projects call45 * Release mode produces heavily optimized code. What other projects call
46 "Link Time Optimization" Zig does automatically.46 "Link Time Optimization" Zig does automatically.
47 * Mark functions as tests and automatically run them with `zig test`.47 * Mark functions as tests and automatically run them with `zig test`.
48 * Currently supported architectures: `x86_64`, `i386`48 * Currently supported architectures: `x86_64`
49 * Currently supported operating systems: linux, macosx49 * Currently supported operating systems: linux
50 * Friendly toward package maintainers. Reproducible build, bootstrapping50 * Friendly toward package maintainers. Reproducible build, bootstrapping
51 process carefully documented. Issues filed by package maintainers are51 process carefully documented. Issues filed by package maintainers are
52 considered especially important.52 considered especially important.
...@@ -103,7 +103,7 @@ cd build...@@ -103,7 +103,7 @@ cd build
103cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o))103cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o))
104make104make
105make install105make install
106./run_tests106./zig build --build-file ../build.zig test
107```107```
108108
109### Release / Install Build109### Release / Install Build
build.zig created+23
...@@ -0,0 +1,23 @@
1const Builder = @import("std").build.Builder;
2const tests = @import("test/tests.zig");
3
4pub fn build(b: &Builder) {
5 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
6 const test_step = b.step("test", "Run all the tests");
7
8 const cleanup = b.addRemoveDirTree("test_artifacts");
9 test_step.dependOn(&cleanup.step);
10
11 cleanup.step.dependOn(tests.addPkgTests(b, test_filter,
12 "test/behavior.zig", "behavior", "Run the behavior tests"));
13
14 cleanup.step.dependOn(tests.addPkgTests(b, test_filter,
15 "std/index.zig", "std", "Run the standard library tests"));
16
17 cleanup.step.dependOn(tests.addCompareOutputTests(b, test_filter));
18 cleanup.step.dependOn(tests.addBuildExampleTests(b, test_filter));
19 cleanup.step.dependOn(tests.addCompileErrorTests(b, test_filter));
20 cleanup.step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
21 cleanup.step.dependOn(tests.addDebugSafetyTests(b, test_filter));
22 cleanup.step.dependOn(tests.addParseHTests(b, test_filter));
23}
src/all_types.hpp+3
...@@ -1458,6 +1458,9 @@ struct CodeGen {...@@ -1458,6 +1458,9 @@ struct CodeGen {
1458 ZigList<Buf *> link_objects;1458 ZigList<Buf *> link_objects;
14591459
1460 ZigList<TypeTableEntry *> name_table_enums;1460 ZigList<TypeTableEntry *> name_table_enums;
1461
1462 Buf *test_filter;
1463 Buf *test_name_prefix;
1461};1464};
14621465
1463enum VarLinkage {1466enum VarLinkage {
src/analyze.cpp+8-1
...@@ -1959,7 +1959,14 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope...@@ -1959,7 +1959,14 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
1959 if (import->package != g->root_package)1959 if (import->package != g->root_package)
1960 return;1960 return;
19611961
1962 Buf *test_name = node->data.test_decl.name;1962 Buf *decl_name_buf = node->data.test_decl.name;
1963
1964 Buf *test_name = g->test_name_prefix ?
1965 buf_sprintf("%s%s", buf_ptr(g->test_name_prefix), buf_ptr(decl_name_buf)) : decl_name_buf;
1966
1967 if (g->test_filter != nullptr && strstr(buf_ptr(test_name), buf_ptr(g->test_filter)) == nullptr) {
1968 return;
1969 }
19631970
1964 TldFn *tld_fn = allocate<TldFn>(1);1971 TldFn *tld_fn = allocate<TldFn>(1);
1965 init_tld(&tld_fn->base, TldIdFn, test_name, VisibModPrivate, node, &decls_scope->base);1972 init_tld(&tld_fn->base, TldIdFn, test_name, VisibModPrivate, node, &decls_scope->base);
src/codegen.cpp+8
...@@ -147,6 +147,14 @@ void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt) {...@@ -147,6 +147,14 @@ void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt) {
147 g->omit_zigrt = omit_zigrt;147 g->omit_zigrt = omit_zigrt;
148}148}
149149
150void codegen_set_test_filter(CodeGen *g, Buf *filter) {
151 g->test_filter = filter;
152}
153
154void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix) {
155 g->test_name_prefix = prefix;
156}
157
150void codegen_set_is_test(CodeGen *g, bool is_test_build) {158void codegen_set_is_test(CodeGen *g, bool is_test_build) {
151 g->is_test_build = is_test_build;159 g->is_test_build = is_test_build;
152}160}
src/codegen.hpp+2
...@@ -44,6 +44,8 @@ void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);...@@ -44,6 +44,8 @@ void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);
44void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);44void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);
45void codegen_set_linker_script(CodeGen *g, const char *linker_script);45void codegen_set_linker_script(CodeGen *g, const char *linker_script);
46void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);46void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);
47void codegen_set_test_filter(CodeGen *g, Buf *filter);
48void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
4749
48PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);50PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);
49void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);51void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
src/link.cpp+8
...@@ -770,6 +770,14 @@ void codegen_link(CodeGen *g, const char *out_file) {...@@ -770,6 +770,14 @@ void codegen_link(CodeGen *g, const char *out_file) {
770 if (g->want_h_file) {770 if (g->want_h_file) {
771 codegen_generate_h_file(g);771 codegen_generate_h_file(g);
772 }772 }
773 if (override_out_file) {
774 assert(g->link_objects.length == 1);
775 Buf *o_file_path = g->link_objects.at(0);
776 int err;
777 if ((err = os_rename(o_file_path, &lj.out_file))) {
778 zig_panic("unable to rename object file into final output: %s", err_str(err));
779 }
780 }
773 if (g->verbose) {781 if (g->verbose) {
774 fprintf(stderr, "OK\n");782 fprintf(stderr, "OK\n");
775 }783 }
src/main.cpp+28-5
...@@ -64,6 +64,9 @@ static int usage(const char *arg0) {...@@ -64,6 +64,9 @@ static int usage(const char *arg0) {
64 " -mwindows (windows only) --subsystem windows to the linker\n"64 " -mwindows (windows only) --subsystem windows to the linker\n"
65 " -rdynamic add all symbols to the dynamic symbol table\n"65 " -rdynamic add all symbols to the dynamic symbol table\n"
66 " -rpath [path] add directory to the runtime library search path\n"66 " -rpath [path] add directory to the runtime library search path\n"
67 "Test Options:\n"
68 " --test-filter [text] skip tests that do not match filter\n"
69 " --test-name-prefix [text] add prefix to all tests\n"
67 , arg0);70 , arg0);
68 return EXIT_FAILURE;71 return EXIT_FAILURE;
69}72}
...@@ -151,6 +154,8 @@ int main(int argc, char **argv) {...@@ -151,6 +154,8 @@ int main(int argc, char **argv) {
151 ZigList<const char *> rpath_list = {0};154 ZigList<const char *> rpath_list = {0};
152 bool each_lib_rpath = false;155 bool each_lib_rpath = false;
153 ZigList<const char *> objects = {0};156 ZigList<const char *> objects = {0};
157 const char *test_filter = nullptr;
158 const char *test_name_prefix = nullptr;
154159
155 if (argc >= 2 && strcmp(argv[1], "build") == 0) {160 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
156 const char *zig_exe_path = arg0;161 const char *zig_exe_path = arg0;
...@@ -168,6 +173,7 @@ int main(int argc, char **argv) {...@@ -168,6 +173,7 @@ int main(int argc, char **argv) {
168173
169 ZigList<const char *> args = {0};174 ZigList<const char *> args = {0};
170 args.append(zig_exe_path);175 args.append(zig_exe_path);
176 args.append(NULL); // placeholder
171 for (int i = 2; i < argc; i += 1) {177 for (int i = 2; i < argc; i += 1) {
172 if (strcmp(argv[i], "--debug-build-verbose") == 0) {178 if (strcmp(argv[i], "--debug-build-verbose") == 0) {
173 verbose = true;179 verbose = true;
...@@ -202,6 +208,8 @@ int main(int argc, char **argv) {...@@ -202,6 +208,8 @@ int main(int argc, char **argv) {
202 Buf build_file_dirname = BUF_INIT;208 Buf build_file_dirname = BUF_INIT;
203 os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);209 os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
204210
211 args.items[1] = buf_ptr(&build_file_dirname);
212
205 bool build_file_exists;213 bool build_file_exists;
206 if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {214 if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
207 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err));215 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err));
...@@ -214,11 +222,14 @@ int main(int argc, char **argv) {...@@ -214,11 +222,14 @@ int main(int argc, char **argv) {
214 "Usage: %s build [options]\n"222 "Usage: %s build [options]\n"
215 "\n"223 "\n"
216 "General Options:\n"224 "General Options:\n"
217 " --help Print this help and exit.\n"225 " --help Print this help and exit\n"
218 " --build-file [file] Override path to build.zig.\n"226 " --build-file [file] Override path to build.zig\n"
219 " --verbose Print commands before executing them.\n"227 " --verbose Print commands before executing them\n"
220 " --debug-build-verbose Print verbose debugging information for the build system itself.\n"228 " --debug-build-verbose Print verbose debugging information for the build system itself\n"
221 " --prefix [prefix] Override default install prefix.\n"229 " --prefix [prefix] Override default install prefix\n"
230 "\n"
231 "More options become available when the build file is found.\n"
232 "Run this command with no options to generate a build.zig template.\n"
222 , zig_exe_path);233 , zig_exe_path);
223 return 0;234 return 0;
224 }235 }
...@@ -335,6 +346,10 @@ int main(int argc, char **argv) {...@@ -335,6 +346,10 @@ int main(int argc, char **argv) {
335 linker_script = argv[i];346 linker_script = argv[i];
336 } else if (strcmp(arg, "-rpath") == 0) {347 } else if (strcmp(arg, "-rpath") == 0) {
337 rpath_list.append(argv[i]);348 rpath_list.append(argv[i]);
349 } else if (strcmp(arg, "--test-filter") == 0) {
350 test_filter = argv[i];
351 } else if (strcmp(arg, "--test-name-prefix") == 0) {
352 test_name_prefix = argv[i];
338 } else {353 } else {
339 fprintf(stderr, "Invalid argument: %s\n", arg);354 fprintf(stderr, "Invalid argument: %s\n", arg);
340 return usage(arg0);355 return usage(arg0);
...@@ -556,6 +571,14 @@ int main(int argc, char **argv) {...@@ -556,6 +571,14 @@ int main(int argc, char **argv) {
556 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));571 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
557 }572 }
558573
574 if (test_filter) {
575 codegen_set_test_filter(g, buf_create_from_str(test_filter));
576 }
577
578 if (test_name_prefix) {
579 codegen_set_test_name_prefix(g, buf_create_from_str(test_name_prefix));
580 }
581
559 if (cmd == CmdBuild) {582 if (cmd == CmdBuild) {
560 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);583 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
561 codegen_link(g, out_file);584 codegen_link(g, out_file);
src/os.cpp+7
...@@ -683,3 +683,10 @@ int os_delete_file(Buf *path) {...@@ -683,3 +683,10 @@ int os_delete_file(Buf *path) {
683void os_init(void) {683void os_init(void) {
684 srand((unsigned)time(NULL));684 srand((unsigned)time(NULL));
685}685}
686
687int os_rename(Buf *src_path, Buf *dest_path) {
688 if (rename(buf_ptr(src_path), buf_ptr(dest_path)) == -1) {
689 return ErrorFileSystem;
690 }
691 return 0;
692}
src/os.hpp+2
...@@ -55,6 +55,8 @@ int os_delete_file(Buf *path);...@@ -55,6 +55,8 @@ int os_delete_file(Buf *path);
5555
56int os_file_exists(Buf *full_path, bool *result);56int os_file_exists(Buf *full_path, bool *result);
5757
58int os_rename(Buf *src_path, Buf *dest_path);
59
58#if defined(__APPLE__)60#if defined(__APPLE__)
59#define ZIG_OS_DARWIN61#define ZIG_OS_DARWIN
60#elif defined(_WIN32)62#elif defined(_WIN32)
std/build.zig+619-58
...@@ -10,13 +10,14 @@ const StdIo = os.ChildProcess.StdIo;...@@ -10,13 +10,14 @@ const StdIo = os.ChildProcess.StdIo;
10const Term = os.ChildProcess.Term;10const Term = os.ChildProcess.Term;
11const BufSet = @import("buf_set.zig").BufSet;11const BufSet = @import("buf_set.zig").BufSet;
12const BufMap = @import("buf_map.zig").BufMap;12const BufMap = @import("buf_map.zig").BufMap;
13const fmt = @import("fmt.zig");13const fmt_lib = @import("fmt.zig");
1414
15error ExtraArg;15error ExtraArg;
16error UncleanExit;16error UncleanExit;
17error InvalidStepName;17error InvalidStepName;
18error DependencyLoopDetected;18error DependencyLoopDetected;
19error NoCompilerFound;19error NoCompilerFound;
20error NeedAnObject;
2021
21pub const Builder = struct {22pub const Builder = struct {
22 uninstall_tls: TopLevelStep,23 uninstall_tls: TopLevelStep,
...@@ -38,6 +39,7 @@ pub const Builder = struct {...@@ -38,6 +39,7 @@ pub const Builder = struct {
38 lib_dir: []const u8,39 lib_dir: []const u8,
39 out_dir: []u8,40 out_dir: []u8,
40 installed_files: List([]const u8),41 installed_files: List([]const u8),
42 build_root: []const u8,
4143
42 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);44 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
43 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);45 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
...@@ -73,8 +75,10 @@ pub const Builder = struct {...@@ -73,8 +75,10 @@ pub const Builder = struct {
73 description: []const u8,75 description: []const u8,
74 };76 };
7577
76 pub fn init(allocator: &Allocator) -> Builder {78 pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8) -> Builder {
77 var self = Builder {79 var self = Builder {
80 .zig_exe = zig_exe,
81 .build_root = build_root,
78 .verbose = false,82 .verbose = false,
79 .invalid_user_input = false,83 .invalid_user_input = false,
80 .allocator = allocator,84 .allocator = allocator,
...@@ -85,7 +89,6 @@ pub const Builder = struct {...@@ -85,7 +89,6 @@ pub const Builder = struct {
85 .available_options_map = AvailableOptionsMap.init(allocator),89 .available_options_map = AvailableOptionsMap.init(allocator),
86 .available_options_list = List(AvailableOption).init(allocator),90 .available_options_list = List(AvailableOption).init(allocator),
87 .top_level_steps = List(&TopLevelStep).init(allocator),91 .top_level_steps = List(&TopLevelStep).init(allocator),
88 .zig_exe = undefined,
89 .default_step = undefined,92 .default_step = undefined,
90 .env_map = %%os.getEnvMap(allocator),93 .env_map = %%os.getEnvMap(allocator),
91 .prefix = undefined,94 .prefix = undefined,
...@@ -123,6 +126,36 @@ pub const Builder = struct {...@@ -123,6 +126,36 @@ pub const Builder = struct {
123 return exe;126 return exe;
124 }127 }
125128
129 pub fn addTest(self: &Builder, root_src: []const u8) -> &TestStep {
130 const test_step = %%self.allocator.create(TestStep);
131 *test_step = TestStep.init(self, root_src);
132 return test_step;
133 }
134
135 pub fn addAssemble(self: &Builder, name: []const u8, src: []const u8) -> &AsmStep {
136 const asm_step = %%self.allocator.create(AsmStep);
137 *asm_step = AsmStep.init(self, name, src);
138 return asm_step;
139 }
140
141 pub fn addLinkExecutable(self: &Builder, name: []const u8) -> &LinkStep {
142 const exe = %%self.allocator.create(LinkStep);
143 *exe = LinkStep.initExecutable(self, name);
144 return exe;
145 }
146
147 pub fn addLinkStaticLibrary(self: &Builder, name: []const u8) -> &LinkStep {
148 const exe = %%self.allocator.create(LinkStep);
149 *exe = LinkStep.initStaticLibrary(self, name);
150 return exe;
151 }
152
153 pub fn addLinkSharedLibrary(self: &Builder, name: []const u8, ver: &const Version) -> &LinkStep {
154 const exe = %%self.allocator.create(LinkStep);
155 *exe = LinkStep.initSharedLibrary(self, name, ver);
156 return exe;
157 }
158
126 pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary {159 pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary {
127 const lib = %%self.allocator.create(CLibrary);160 const lib = %%self.allocator.create(CLibrary);
128 *lib = CLibrary.initStatic(self, name);161 *lib = CLibrary.initStatic(self, name);
...@@ -149,6 +182,25 @@ pub const Builder = struct {...@@ -149,6 +182,25 @@ pub const Builder = struct {
149 return cmd;182 return cmd;
150 }183 }
151184
185 pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep {
186 const write_file_step = %%self.allocator.create(WriteFileStep);
187 *write_file_step = WriteFileStep.init(self, file_path, data);
188 return write_file_step;
189 }
190
191 pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) -> &LogStep {
192 const data = self.fmt(format, args);
193 const log_step = %%self.allocator.create(LogStep);
194 *log_step = LogStep.init(self, data);
195 return log_step;
196 }
197
198 pub fn addRemoveDirTree(self: &Builder, dir_path: []const u8) -> &RemoveDirStep {
199 const remove_dir_step = %%self.allocator.create(RemoveDirStep);
200 *remove_dir_step = RemoveDirStep.init(self, dir_path);
201 return remove_dir_step;
202 }
203
152 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {204 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
153 Version {205 Version {
154 .major = major,206 .major = major,
...@@ -197,9 +249,8 @@ pub const Builder = struct {...@@ -197,9 +249,8 @@ pub const Builder = struct {
197 }249 }
198250
199 fn makeUninstall(uninstall_step: &Step) -> %void {251 fn makeUninstall(uninstall_step: &Step) -> %void {
200 // TODO252 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
201 // const self = @fieldParentPtr(Exe, "step", step);253 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
202 const self = @ptrcast(&Builder, uninstall_step);
203254
204 for (self.installed_files.toSliceConst()) |installed_file| {255 for (self.installed_files.toSliceConst()) |installed_file| {
205 _ = os.deleteFile(self.allocator, installed_file);256 _ = os.deleteFile(self.allocator, installed_file);
...@@ -278,7 +329,7 @@ pub const Builder = struct {...@@ -278,7 +329,7 @@ pub const Builder = struct {
278 }329 }
279330
280 pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) -> ?T {331 pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) -> ?T {
281 const type_id = typeToEnum(T);332 const type_id = comptime typeToEnum(T);
282 const available_option = AvailableOption {333 const available_option = AvailableOption {
283 .name = name,334 .name = name,
284 .type_id = type_id,335 .type_id = type_id,
...@@ -313,7 +364,19 @@ pub const Builder = struct {...@@ -313,7 +364,19 @@ pub const Builder = struct {
313 },364 },
314 TypeId.Int => debug.panic("TODO integer options to build script"),365 TypeId.Int => debug.panic("TODO integer options to build script"),
315 TypeId.Float => debug.panic("TODO float options to build script"),366 TypeId.Float => debug.panic("TODO float options to build script"),
316 TypeId.String => debug.panic("TODO string options to build script"),367 TypeId.String => switch (entry.value.value) {
368 UserValue.Flag => {
369 %%io.stderr.printf("Expected -D{} to be a string, but received a boolean.\n", name);
370 self.markInvalidUserInput();
371 return null;
372 },
373 UserValue.List => {
374 %%io.stderr.printf("Expected -D{} to be a string, but received a list.\n", name);
375 self.markInvalidUserInput();
376 return null;
377 },
378 UserValue.Scalar => |s| return s,
379 },
317 TypeId.List => debug.panic("TODO list options to build script"),380 TypeId.List => debug.panic("TODO list options to build script"),
318 }381 }
319 }382 }
...@@ -482,6 +545,14 @@ pub const Builder = struct {...@@ -482,6 +545,14 @@ pub const Builder = struct {
482 debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err));545 debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err));
483 };546 };
484 }547 }
548
549 fn pathFromRoot(self: &Builder, rel_path: []const u8) -> []u8 {
550 return %%os.path.join(self.allocator, self.build_root, rel_path);
551 }
552
553 pub fn fmt(self: &Builder, comptime format: []const u8, args: ...) -> []u8 {
554 return %%fmt_lib.allocPrint(self.allocator, format, args);
555 }
485};556};
486557
487const Version = struct {558const Version = struct {
...@@ -510,6 +581,17 @@ const Target = enum {...@@ -510,6 +581,17 @@ const Target = enum {
510 else => ".o",581 else => ".o",
511 };582 };
512 }583 }
584
585 pub fn exeFileExt(self: &const Target) -> []const u8 {
586 const target_os = switch (*self) {
587 Target.Native => @compileVar("os"),
588 Target.Cross => |t| t.os,
589 };
590 return switch (target_os) {
591 Os.windows => ".exe",
592 else => "",
593 };
594 }
513};595};
514596
515const LinkerScript = enum {597const LinkerScript = enum {
...@@ -518,7 +600,7 @@ const LinkerScript = enum {...@@ -518,7 +600,7 @@ const LinkerScript = enum {
518 Path: []const u8,600 Path: []const u8,
519};601};
520602
521const Exe = struct {603pub const Exe = struct {
522 step: Step,604 step: Step,
523 builder: &Builder,605 builder: &Builder,
524 root_src: []const u8,606 root_src: []const u8,
...@@ -528,6 +610,7 @@ const Exe = struct {...@@ -528,6 +610,7 @@ const Exe = struct {
528 link_libs: BufSet,610 link_libs: BufSet,
529 verbose: bool,611 verbose: bool,
530 release: bool,612 release: bool,
613 output_path: ?[]const u8,
531614
532 pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe {615 pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe {
533 Exe {616 Exe {
...@@ -540,6 +623,7 @@ const Exe = struct {...@@ -540,6 +623,7 @@ const Exe = struct {
540 .linker_script = LinkerScript.None,623 .linker_script = LinkerScript.None,
541 .link_libs = BufSet.init(builder.allocator),624 .link_libs = BufSet.init(builder.allocator),
542 .step = Step.init(name, builder.allocator, make),625 .step = Step.init(name, builder.allocator, make),
626 .output_path = null,
543 }627 }
544 }628 }
545629
...@@ -579,6 +663,10 @@ const Exe = struct {...@@ -579,6 +663,10 @@ const Exe = struct {
579 self.release = value;663 self.release = value;
580 }664 }
581665
666 pub fn setOutputPath(self: &Exe, value: []const u8) {
667 self.output_path = value;
668 }
669
582 fn make(step: &Step) -> %void {670 fn make(step: &Step) -> %void {
583 const exe = @fieldParentPtr(Exe, "step", step);671 const exe = @fieldParentPtr(Exe, "step", step);
584 const builder = exe.builder;672 const builder = exe.builder;
...@@ -586,31 +674,36 @@ const Exe = struct {...@@ -586,31 +674,36 @@ const Exe = struct {
586 var zig_args = List([]const u8).init(builder.allocator);674 var zig_args = List([]const u8).init(builder.allocator);
587 defer zig_args.deinit();675 defer zig_args.deinit();
588676
589 %return zig_args.append("build_exe");677 %%zig_args.append("build_exe");
590 %return zig_args.append(exe.root_src);678 %%zig_args.append(builder.pathFromRoot(exe.root_src));
591679
592 if (exe.verbose) {680 if (exe.verbose) {
593 %return zig_args.append("--verbose");681 %%zig_args.append("--verbose");
594 }682 }
595683
596 if (exe.release) {684 if (exe.release) {
597 %return zig_args.append("--release");685 %%zig_args.append("--release");
598 }686 }
599687
600 %return zig_args.append("--name");688 if (const output_path ?= exe.output_path) {
601 %return zig_args.append(exe.name);689 %%zig_args.append("--output");
690 %%zig_args.append(builder.pathFromRoot(output_path));
691 }
692
693 %%zig_args.append("--name");
694 %%zig_args.append(exe.name);
602695
603 switch (exe.target) {696 switch (exe.target) {
604 Target.Native => {},697 Target.Native => {},
605 Target.Cross => |cross_target| {698 Target.Cross => |cross_target| {
606 %return zig_args.append("--target-arch");699 %%zig_args.append("--target-arch");
607 %return zig_args.append(@enumTagName(cross_target.arch));700 %%zig_args.append(@enumTagName(cross_target.arch));
608701
609 %return zig_args.append("--target-os");702 %%zig_args.append("--target-os");
610 %return zig_args.append(@enumTagName(cross_target.os));703 %%zig_args.append(@enumTagName(cross_target.os));
611704
612 %return zig_args.append("--target-environ");705 %%zig_args.append("--target-environ");
613 %return zig_args.append(@enumTagName(cross_target.environ));706 %%zig_args.append(@enumTagName(cross_target.environ));
614 },707 },
615 }708 }
616709
...@@ -620,12 +713,12 @@ const Exe = struct {...@@ -620,12 +713,12 @@ const Exe = struct {
620 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298713 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
621 io.writeFile(tmp_file_name, script, builder.allocator)714 io.writeFile(tmp_file_name, script, builder.allocator)
622 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));715 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
623 %return zig_args.append("--linker-script");716 %%zig_args.append("--linker-script");
624 %return zig_args.append(tmp_file_name);717 %%zig_args.append(tmp_file_name);
625 },718 },
626 LinkerScript.Path => |path| {719 LinkerScript.Path => |path| {
627 %return zig_args.append("--linker-script");720 %%zig_args.append("--linker-script");
628 %return zig_args.append(path);721 %%zig_args.append(path);
629 },722 },
630 }723 }
631724
...@@ -633,31 +726,432 @@ const Exe = struct {...@@ -633,31 +726,432 @@ const Exe = struct {
633 var it = exe.link_libs.iterator();726 var it = exe.link_libs.iterator();
634 while (true) {727 while (true) {
635 const entry = it.next() ?? break;728 const entry = it.next() ?? break;
636 %return zig_args.append("--library");729 %%zig_args.append("--library");
637 %return zig_args.append(entry.key);730 %%zig_args.append(entry.key);
638 }731 }
639 }732 }
640733
641 for (builder.include_paths.toSliceConst()) |include_path| {734 for (builder.include_paths.toSliceConst()) |include_path| {
642 %return zig_args.append("-isystem");735 %%zig_args.append("-isystem");
643 %return zig_args.append(include_path);736 %%zig_args.append(include_path);
644 }737 }
645738
646 for (builder.rpaths.toSliceConst()) |rpath| {739 for (builder.rpaths.toSliceConst()) |rpath| {
647 %return zig_args.append("-rpath");740 %%zig_args.append("-rpath");
648 %return zig_args.append(rpath);741 %%zig_args.append(rpath);
649 }742 }
650743
651 for (builder.lib_paths.toSliceConst()) |lib_path| {744 for (builder.lib_paths.toSliceConst()) |lib_path| {
652 %return zig_args.append("--library-path");745 %%zig_args.append("--library-path");
653 %return zig_args.append(lib_path);746 %%zig_args.append(lib_path);
654 }747 }
655748
656 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());749 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
657 }750 }
658};751};
659752
660const CLibrary = struct {753pub const AsmStep = struct {
754 step: Step,
755 builder: &Builder,
756 name: []const u8,
757 target: Target,
758 verbose: bool,
759 release: bool,
760 output_path: ?[]const u8,
761 src_path: []const u8,
762
763 pub fn init(builder: &Builder, name: []const u8, src_path: []const u8) -> AsmStep {
764 var self = AsmStep {
765 .step = Step.init(name, builder.allocator, make),
766 .builder = builder,
767 .name = name,
768 .target = Target.Native,
769 .verbose = false,
770 .release = false,
771 .output_path = null,
772 .src_path = src_path,
773 };
774 return self;
775 }
776
777 pub fn setTarget(self: &AsmStep, target_arch: Arch, target_os: Os, target_environ: Environ) {
778 self.target = Target.Cross {
779 CrossTarget {
780 .arch = target_arch,
781 .os = target_os,
782 .environ = target_environ,
783 }
784 };
785 }
786
787 pub fn setVerbose(self: &AsmStep, value: bool) {
788 self.verbose = value;
789 }
790
791 pub fn setRelease(self: &AsmStep, value: bool) {
792 self.release = value;
793 }
794
795 pub fn setOutputPath(self: &AsmStep, value: []const u8) {
796 self.output_path = value;
797 }
798
799 fn make(step: &Step) -> %void {
800 const self = @fieldParentPtr(AsmStep, "step", step);
801 const builder = self.builder;
802
803 var zig_args = List([]const u8).init(builder.allocator);
804 defer zig_args.deinit();
805
806 %%zig_args.append("asm");
807 %%zig_args.append(builder.pathFromRoot(self.src_path));
808
809 if (self.verbose) {
810 %%zig_args.append("--verbose");
811 }
812
813 if (self.release) {
814 %%zig_args.append("--release");
815 }
816
817 if (const output_path ?= self.output_path) {
818 %%zig_args.append("--output");
819 %%zig_args.append(builder.pathFromRoot(output_path));
820 }
821
822 %%zig_args.append("--name");
823 %%zig_args.append(self.name);
824
825 switch (self.target) {
826 Target.Native => {},
827 Target.Cross => |cross_target| {
828 %%zig_args.append("--target-arch");
829 %%zig_args.append(@enumTagName(cross_target.arch));
830
831 %%zig_args.append("--target-os");
832 %%zig_args.append(@enumTagName(cross_target.os));
833
834 %%zig_args.append("--target-environ");
835 %%zig_args.append(@enumTagName(cross_target.environ));
836 },
837 }
838
839 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
840 }
841};
842
843pub const LinkStep = struct {
844 step: Step,
845 builder: &Builder,
846 name: []const u8,
847 target: Target,
848 linker_script: LinkerScript,
849 link_libs: BufSet,
850 verbose: bool,
851 release: bool,
852 output_path: ?[]const u8,
853 object_files: List([]const u8),
854 static: bool,
855 out_filename: []const u8,
856 out_type: OutType,
857 version: Version,
858 major_only_filename: []const u8,
859 name_only_filename: []const u8,
860
861 const OutType = enum {
862 Exe,
863 Lib,
864 };
865
866 pub fn initExecutable(builder: &Builder, name: []const u8) -> LinkStep {
867 return init(builder, name, OutType.Exe, builder.version(0, 0, 0), false)
868 }
869
870 pub fn initSharedLibrary(builder: &Builder, name: []const u8, version: &const Version) -> LinkStep {
871 return init(builder, name, OutType.Lib, version, false)
872 }
873
874 pub fn initStaticLibrary(builder: &Builder, name: []const u8) -> LinkStep {
875 return init(builder, name, OutType.Lib, builder.version(0, 0, 0), true)
876 }
877
878 fn init(builder: &Builder, name: []const u8, out_type: OutType, version: &const Version, static: bool) -> LinkStep {
879 var self = LinkStep {
880 .builder = builder,
881 .verbose = false,
882 .release = false,
883 .name = name,
884 .target = Target.Native,
885 .linker_script = LinkerScript.None,
886 .link_libs = BufSet.init(builder.allocator),
887 .step = Step.init(name, builder.allocator, make),
888 .output_path = null,
889 .object_files = List([]const u8).init(builder.allocator),
890 .out_type = out_type,
891 .version = *version,
892 .static = static,
893 .out_filename = undefined,
894 .major_only_filename = undefined,
895 .name_only_filename = undefined,
896 };
897 self.computeOutFileName();
898 return self;
899 }
900
901 fn computeOutFileName(self: &LinkStep) {
902 switch (self.out_type) {
903 OutType.Exe => {
904 self.out_filename = self.builder.fmt("{}{}", self.name, self.target.exeFileExt());
905 },
906 OutType.Lib => {
907 if (self.static) {
908 self.out_filename = self.builder.fmt("lib{}.a", self.name);
909 } else {
910 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
911 self.name, self.version.major, self.version.minor, self.version.patch);
912 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
913 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
914 }
915 },
916 }
917 }
918
919 pub fn addObjectFile(self: &LinkStep, file: []const u8) {
920 %%self.object_files.append(file);
921 }
922
923 pub fn setTarget(self: &LinkStep, target_arch: Arch, target_os: Os, target_environ: Environ) {
924 self.target = Target.Cross {
925 CrossTarget {
926 .arch = target_arch,
927 .os = target_os,
928 .environ = target_environ,
929 }
930 };
931 self.computeOutFileName();
932 }
933
934 /// LinkStep keeps a reference to script for its lifetime or until this function
935 /// is called again.
936 pub fn setLinkerScriptContents(self: &LinkStep, script: []const u8) {
937 self.linker_script = LinkerScript.Embed { script };
938 }
939
940 pub fn setLinkerScriptPath(self: &LinkStep, path: []const u8) {
941 self.linker_script = LinkerScript.Path { path };
942 }
943
944 pub fn linkLibrary(self: &LinkStep, name: []const u8) {
945 %%self.link_libs.put(name);
946 }
947
948 pub fn setVerbose(self: &LinkStep, value: bool) {
949 self.verbose = value;
950 }
951
952 pub fn setRelease(self: &LinkStep, value: bool) {
953 self.release = value;
954 }
955
956 pub fn setOutputPath(self: &LinkStep, value: []const u8) {
957 self.output_path = value;
958 }
959
960 fn make(step: &Step) -> %void {
961 const self = @fieldParentPtr(LinkStep, "step", step);
962 const builder = self.builder;
963
964 if (self.object_files.len == 0) {
965 %%io.stderr.printf("{}: linker needs 1 or more objects to link\n", step.name);
966 return error.NeedAnObject;
967 }
968
969 var zig_args = List([]const u8).init(builder.allocator);
970 defer zig_args.deinit();
971
972 const cmd = switch (self.out_type) {
973 OutType.Exe => "link_exe",
974 OutType.Lib => "link_lib",
975 };
976 %%zig_args.append(cmd);
977
978 for (self.object_files.toSliceConst()) |object_file| {
979 %%zig_args.append(builder.pathFromRoot(object_file));
980 }
981
982 if (self.verbose) {
983 %%zig_args.append("--verbose");
984 }
985
986 if (self.release) {
987 %%zig_args.append("--release");
988 }
989
990 if (self.static) {
991 %%zig_args.append("--static");
992 }
993
994 if (const output_path ?= self.output_path) {
995 %%zig_args.append("--output");
996 %%zig_args.append(builder.pathFromRoot(output_path));
997 }
998
999 %%zig_args.append("--name");
1000 %%zig_args.append(self.name);
1001
1002 switch (self.target) {
1003 Target.Native => {},
1004 Target.Cross => |cross_target| {
1005 %%zig_args.append("--target-arch");
1006 %%zig_args.append(@enumTagName(cross_target.arch));
1007
1008 %%zig_args.append("--target-os");
1009 %%zig_args.append(@enumTagName(cross_target.os));
1010
1011 %%zig_args.append("--target-environ");
1012 %%zig_args.append(@enumTagName(cross_target.environ));
1013 },
1014 }
1015
1016 switch (self.linker_script) {
1017 LinkerScript.None => {},
1018 LinkerScript.Embed => |script| {
1019 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
1020 io.writeFile(tmp_file_name, script, builder.allocator)
1021 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
1022 %%zig_args.append("--linker-script");
1023 %%zig_args.append(tmp_file_name);
1024 },
1025 LinkerScript.Path => |path| {
1026 %%zig_args.append("--linker-script");
1027 %%zig_args.append(path);
1028 },
1029 }
1030
1031 {
1032 var it = self.link_libs.iterator();
1033 while (true) {
1034 const entry = it.next() ?? break;
1035 %%zig_args.append("--library");
1036 %%zig_args.append(entry.key);
1037 }
1038 }
1039
1040 for (builder.rpaths.toSliceConst()) |rpath| {
1041 %%zig_args.append("-rpath");
1042 %%zig_args.append(rpath);
1043 }
1044
1045 for (builder.lib_paths.toSliceConst()) |lib_path| {
1046 %%zig_args.append("--library-path");
1047 %%zig_args.append(lib_path);
1048 }
1049
1050 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
1051 }
1052};
1053
1054pub const TestStep = struct {
1055 step: Step,
1056 builder: &Builder,
1057 root_src: []const u8,
1058 release: bool,
1059 verbose: bool,
1060 link_libs: BufSet,
1061 name_prefix: []const u8,
1062 filter: ?[]const u8,
1063
1064 pub fn init(builder: &Builder, root_src: []const u8) -> TestStep {
1065 const step_name = builder.fmt("test {}", root_src);
1066 TestStep {
1067 .step = Step.init(step_name, builder.allocator, make),
1068 .builder = builder,
1069 .root_src = root_src,
1070 .release = false,
1071 .verbose = false,
1072 .name_prefix = "",
1073 .filter = null,
1074 .link_libs = BufSet.init(builder.allocator),
1075 }
1076 }
1077
1078 pub fn setVerbose(self: &TestStep, value: bool) {
1079 self.verbose = value;
1080 }
1081
1082 pub fn setRelease(self: &TestStep, value: bool) {
1083 self.release = value;
1084 }
1085
1086 pub fn linkLibrary(self: &TestStep, name: []const u8) {
1087 %%self.link_libs.put(name);
1088 }
1089
1090 pub fn setNamePrefix(self: &TestStep, text: []const u8) {
1091 self.name_prefix = text;
1092 }
1093
1094 pub fn setFilter(self: &TestStep, text: ?[]const u8) {
1095 self.filter = text;
1096 }
1097
1098 fn make(step: &Step) -> %void {
1099 const self = @fieldParentPtr(TestStep, "step", step);
1100 const builder = self.builder;
1101
1102 var zig_args = List([]const u8).init(builder.allocator);
1103 defer zig_args.deinit();
1104
1105 %%zig_args.append("test");
1106 %%zig_args.append(builder.pathFromRoot(self.root_src));
1107
1108 if (self.verbose) {
1109 %%zig_args.append("--verbose");
1110 }
1111
1112 if (self.release) {
1113 %%zig_args.append("--release");
1114 }
1115
1116 if (const filter ?= self.filter) {
1117 %%zig_args.append("--test-filter");
1118 %%zig_args.append(filter);
1119 }
1120
1121 if (self.name_prefix.len != 0) {
1122 %%zig_args.append("--test-name-prefix");
1123 %%zig_args.append(self.name_prefix);
1124 }
1125
1126 {
1127 var it = self.link_libs.iterator();
1128 while (true) {
1129 const entry = it.next() ?? break;
1130 %%zig_args.append("--library");
1131 %%zig_args.append(entry.key);
1132 }
1133 }
1134
1135 for (builder.include_paths.toSliceConst()) |include_path| {
1136 %%zig_args.append("-isystem");
1137 %%zig_args.append(include_path);
1138 }
1139
1140 for (builder.rpaths.toSliceConst()) |rpath| {
1141 %%zig_args.append("-rpath");
1142 %%zig_args.append(rpath);
1143 }
1144
1145 for (builder.lib_paths.toSliceConst()) |lib_path| {
1146 %%zig_args.append("--library-path");
1147 %%zig_args.append(lib_path);
1148 }
1149
1150 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
1151 }
1152};
1153
1154pub const CLibrary = struct {
661 step: Step,1155 step: Step,
662 name: []const u8,1156 name: []const u8,
663 out_filename: []const u8,1157 out_filename: []const u8,
...@@ -678,7 +1172,7 @@ const CLibrary = struct {...@@ -678,7 +1172,7 @@ const CLibrary = struct {
678 }1172 }
6791173
680 pub fn initStatic(builder: &Builder, name: []const u8) -> CLibrary {1174 pub fn initStatic(builder: &Builder, name: []const u8) -> CLibrary {
681 return init(builder, name, undefined, true);1175 return init(builder, name, builder.version(0, 0, 0), true);
682 }1176 }
6831177
684 fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {1178 fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {
...@@ -704,14 +1198,12 @@ const CLibrary = struct {...@@ -704,14 +1198,12 @@ const CLibrary = struct {
7041198
705 fn computeOutFileName(self: &CLibrary) {1199 fn computeOutFileName(self: &CLibrary) {
706 if (self.static) {1200 if (self.static) {
707 self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.a", self.name);1201 self.out_filename = self.builder.fmt("lib{}.a", self.name);
708 } else {1202 } else {
709 self.out_filename = %%fmt.allocPrint(self.builder.allocator, "lib{}.so.{d}.{d}.{d}",1203 self.out_filename = self.builder.fmt("lib{}.so.{d}.{d}.{d}",
710 self.name, self.version.major, self.version.minor, self.version.patch);1204 self.name, self.version.major, self.version.minor, self.version.patch);
711 self.major_only_filename = %%fmt.allocPrint(self.builder.allocator,1205 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
712 "lib{}.so.{d}", self.name, self.version.major);1206 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
713 self.name_only_filename = %%fmt.allocPrint(self.builder.allocator,
714 "lib{}.so", self.name);
715 }1207 }
716 }1208 }
7171209
...@@ -770,7 +1262,7 @@ const CLibrary = struct {...@@ -770,7 +1262,7 @@ const CLibrary = struct {
770 %%cc_args.append(source_file);1262 %%cc_args.append(source_file);
7711263
772 // TODO don't dump the .o file in the same place as the source file1264 // TODO don't dump the .o file in the same place as the source file
773 const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt());1265 const o_file = builder.fmt("{}{}", source_file, self.target.oFileExt());
774 defer builder.allocator.free(o_file);1266 defer builder.allocator.free(o_file);
775 %%cc_args.append("-o");1267 %%cc_args.append("-o");
776 %%cc_args.append(o_file);1268 %%cc_args.append(o_file);
...@@ -797,8 +1289,7 @@ const CLibrary = struct {...@@ -797,8 +1289,7 @@ const CLibrary = struct {
797 %%cc_args.append("-fPIC");1289 %%cc_args.append("-fPIC");
798 %%cc_args.append("-shared");1290 %%cc_args.append("-shared");
7991291
800 const soname_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-soname,lib{}.so.{d}",1292 const soname_arg = builder.fmt("-Wl,-soname,lib{}.so.{d}", self.name, self.version.major);
801 self.name, self.version.major);
802 defer builder.allocator.free(soname_arg);1293 defer builder.allocator.free(soname_arg);
803 %%cc_args.append(soname_arg);1294 %%cc_args.append(soname_arg);
8041295
...@@ -806,7 +1297,7 @@ const CLibrary = struct {...@@ -806,7 +1297,7 @@ const CLibrary = struct {
806 %%cc_args.append(self.out_filename);1297 %%cc_args.append(self.out_filename);
8071298
808 for (self.object_files.toSliceConst()) |object_file| {1299 for (self.object_files.toSliceConst()) |object_file| {
809 %%cc_args.append(object_file);1300 %%cc_args.append(builder.pathFromRoot(object_file));
810 }1301 }
8111302
812 builder.spawnChild(cc, cc_args.toSliceConst());1303 builder.spawnChild(cc, cc_args.toSliceConst());
...@@ -829,7 +1320,7 @@ const CLibrary = struct {...@@ -829,7 +1320,7 @@ const CLibrary = struct {
829 }1320 }
830};1321};
8311322
832const CExecutable = struct {1323pub const CExecutable = struct {
833 step: Step,1324 step: Step,
834 builder: &Builder,1325 builder: &Builder,
835 name: []const u8,1326 name: []const u8,
...@@ -907,7 +1398,7 @@ const CExecutable = struct {...@@ -907,7 +1398,7 @@ const CExecutable = struct {
907 %%cc_args.append(source_file);1398 %%cc_args.append(source_file);
9081399
909 // TODO don't dump the .o file in the same place as the source file1400 // TODO don't dump the .o file in the same place as the source file
910 const o_file = %%fmt.allocPrint(builder.allocator, "{}{}", source_file, self.target.oFileExt());1401 const o_file = builder.fmt("{}{}", source_file, self.target.oFileExt());
911 defer builder.allocator.free(o_file);1402 defer builder.allocator.free(o_file);
912 %%cc_args.append("-o");1403 %%cc_args.append("-o");
913 %%cc_args.append(o_file);1404 %%cc_args.append(o_file);
...@@ -935,7 +1426,7 @@ const CExecutable = struct {...@@ -935,7 +1426,7 @@ const CExecutable = struct {
935 %%cc_args.append("-o");1426 %%cc_args.append("-o");
936 %%cc_args.append(self.name);1427 %%cc_args.append(self.name);
9371428
938 const rpath_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-rpath,{}", builder.out_dir);1429 const rpath_arg = builder.fmt("-Wl,-rpath,{}", builder.out_dir);
939 defer builder.allocator.free(rpath_arg);1430 defer builder.allocator.free(rpath_arg);
940 %%cc_args.append(rpath_arg);1431 %%cc_args.append(rpath_arg);
9411432
...@@ -959,7 +1450,7 @@ const CExecutable = struct {...@@ -959,7 +1450,7 @@ const CExecutable = struct {
959 }1450 }
960};1451};
9611452
962const CommandStep = struct {1453pub const CommandStep = struct {
963 step: Step,1454 step: Step,
964 builder: &Builder,1455 builder: &Builder,
965 exe_path: []const u8,1456 exe_path: []const u8,
...@@ -988,7 +1479,7 @@ const CommandStep = struct {...@@ -988,7 +1479,7 @@ const CommandStep = struct {
988 }1479 }
989};1480};
9901481
991const InstallCLibraryStep = struct {1482pub const InstallCLibraryStep = struct {
992 step: Step,1483 step: Step,
993 builder: &Builder,1484 builder: &Builder,
994 lib: &CLibrary,1485 lib: &CLibrary,
...@@ -997,9 +1488,7 @@ const InstallCLibraryStep = struct {...@@ -997,9 +1488,7 @@ const InstallCLibraryStep = struct {
997 pub fn init(builder: &Builder, lib: &CLibrary) -> InstallCLibraryStep {1488 pub fn init(builder: &Builder, lib: &CLibrary) -> InstallCLibraryStep {
998 var self = InstallCLibraryStep {1489 var self = InstallCLibraryStep {
999 .builder = builder,1490 .builder = builder,
1000 .step = Step.init(1491 .step = Step.init(builder.fmt("install {}", lib.step.name), builder.allocator, make),
1001 %%fmt.allocPrint(builder.allocator, "install {}", lib.step.name),
1002 builder.allocator, make),
1003 .lib = lib,1492 .lib = lib,
1004 .dest_file = undefined,1493 .dest_file = undefined,
1005 };1494 };
...@@ -1023,7 +1512,7 @@ const InstallCLibraryStep = struct {...@@ -1023,7 +1512,7 @@ const InstallCLibraryStep = struct {
1023 }1512 }
1024};1513};
10251514
1026const InstallFileStep = struct {1515pub const InstallFileStep = struct {
1027 step: Step,1516 step: Step,
1028 builder: &Builder,1517 builder: &Builder,
1029 src_path: []const u8,1518 src_path: []const u8,
...@@ -1032,9 +1521,7 @@ const InstallFileStep = struct {...@@ -1032,9 +1521,7 @@ const InstallFileStep = struct {
1032 pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) -> InstallFileStep {1521 pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) -> InstallFileStep {
1033 return InstallFileStep {1522 return InstallFileStep {
1034 .builder = builder,1523 .builder = builder,
1035 .step = Step.init(1524 .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),
1036 %%fmt.allocPrint(builder.allocator, "install {}", src_path),
1037 builder.allocator, make),
1038 .src_path = src_path,1525 .src_path = src_path,
1039 .dest_path = dest_path,1526 .dest_path = dest_path,
1040 };1527 };
...@@ -1047,7 +1534,81 @@ const InstallFileStep = struct {...@@ -1047,7 +1534,81 @@ const InstallFileStep = struct {
1047 }1534 }
1048};1535};
10491536
1050const Step = struct {1537pub const WriteFileStep = struct {
1538 step: Step,
1539 builder: &Builder,
1540 file_path: []const u8,
1541 data: []const u8,
1542
1543 pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) -> WriteFileStep {
1544 return WriteFileStep {
1545 .builder = builder,
1546 .step = Step.init(builder.fmt("writefile {}", file_path), builder.allocator, make),
1547 .file_path = file_path,
1548 .data = data,
1549 };
1550 }
1551
1552 fn make(step: &Step) -> %void {
1553 const self = @fieldParentPtr(WriteFileStep, "step", step);
1554 const full_path = self.builder.pathFromRoot(self.file_path);
1555 const full_path_dir = %%os.path.dirname(self.builder.allocator, full_path);
1556 os.makePath(self.builder.allocator, full_path_dir) %% |err| {
1557 %%io.stderr.printf("unable to make path {}: {}\n", full_path_dir, @errorName(err));
1558 return err;
1559 };
1560 io.writeFile(full_path, self.data, self.builder.allocator) %% |err| {
1561 %%io.stderr.printf("unable to write {}: {}\n", full_path, @errorName(err));
1562 return err;
1563 };
1564 }
1565};
1566
1567pub const LogStep = struct {
1568 step: Step,
1569 builder: &Builder,
1570 data: []const u8,
1571
1572 pub fn init(builder: &Builder, data: []const u8) -> LogStep {
1573 return LogStep {
1574 .builder = builder,
1575 .step = Step.init(builder.fmt("log {}", data), builder.allocator, make),
1576 .data = data,
1577 };
1578 }
1579
1580 fn make(step: &Step) -> %void {
1581 const self = @fieldParentPtr(LogStep, "step", step);
1582 %%io.stderr.write(self.data);
1583 %%io.stderr.flush();
1584 }
1585};
1586
1587pub const RemoveDirStep = struct {
1588 step: Step,
1589 builder: &Builder,
1590 dir_path: []const u8,
1591
1592 pub fn init(builder: &Builder, dir_path: []const u8) -> RemoveDirStep {
1593 return RemoveDirStep {
1594 .builder = builder,
1595 .step = Step.init(builder.fmt("RemoveDir {}", dir_path), builder.allocator, make),
1596 .dir_path = dir_path,
1597 };
1598 }
1599
1600 fn make(step: &Step) -> %void {
1601 const self = @fieldParentPtr(RemoveDirStep, "step", step);
1602
1603 const full_path = self.builder.pathFromRoot(self.dir_path);
1604 os.deleteTree(self.builder.allocator, full_path) %% |err| {
1605 %%io.stderr.printf("Unable to remove {}: {}\n", full_path, @errorName(err));
1606 return err;
1607 };
1608 }
1609};
1610
1611pub const Step = struct {
1051 name: []const u8,1612 name: []const u8,
1052 makeFn: fn(self: &Step) -> %void,1613 makeFn: fn(self: &Step) -> %void,
1053 dependencies: List(&Step),1614 dependencies: List(&Step),
std/io.zig+4-6
...@@ -57,8 +57,6 @@ error NoMem;...@@ -57,8 +57,6 @@ error NoMem;
57error Unseekable;57error Unseekable;
58error Eof;58error Eof;
5959
60const buffer_size = 4 * 1024;
61
62pub const OpenRead = 0b0001;60pub const OpenRead = 0b0001;
63pub const OpenWrite = 0b0010;61pub const OpenWrite = 0b0010;
64pub const OpenCreate = 0b0100;62pub const OpenCreate = 0b0100;
...@@ -66,7 +64,7 @@ pub const OpenTruncate = 0b1000;...@@ -66,7 +64,7 @@ pub const OpenTruncate = 0b1000;
6664
67pub const OutStream = struct {65pub const OutStream = struct {
68 fd: i32,66 fd: i32,
69 buffer: [buffer_size]u8,67 buffer: [os.page_size]u8,
70 index: usize,68 index: usize,
7169
72 /// `path` may need to be copied in memory to add a null terminating byte. In this case70 /// `path` may need to be copied in memory to add a null terminating byte. In this case
...@@ -97,7 +95,7 @@ pub const OutStream = struct {...@@ -97,7 +95,7 @@ pub const OutStream = struct {
97 }95 }
9896
99 pub fn write(self: &OutStream, bytes: []const u8) -> %void {97 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
100 if (bytes.len >= buffer_size) {98 if (bytes.len >= self.buffer.len) {
101 %return self.flush();99 %return self.flush();
102 return os.posixWrite(self.fd, bytes);100 return os.posixWrite(self.fd, bytes);
103 }101 }
...@@ -329,7 +327,7 @@ pub const InStream = struct {...@@ -329,7 +327,7 @@ pub const InStream = struct {
329 }327 }
330328
331 pub fn readAll(is: &InStream, buf: &Buffer0) -> %void {329 pub fn readAll(is: &InStream, buf: &Buffer0) -> %void {
332 %return buf.resize(buffer_size);330 %return buf.resize(os.page_size);
333331
334 var actual_buf_len: usize = 0;332 var actual_buf_len: usize = 0;
335 while (true) {333 while (true) {
...@@ -341,7 +339,7 @@ pub const InStream = struct {...@@ -341,7 +339,7 @@ pub const InStream = struct {
341 return buf.resize(actual_buf_len);339 return buf.resize(actual_buf_len);
342 }340 }
343341
344 %return buf.resize(actual_buf_len + buffer_size);342 %return buf.resize(actual_buf_len + os.page_size);
345 }343 }
346 }344 }
347};345};
std/list.zig+9-1
...@@ -61,10 +61,15 @@ pub fn List(comptime T: type) -> type{...@@ -61,10 +61,15 @@ pub fn List(comptime T: type) -> type{
61 l.len = new_length;61 l.len = new_length;
62 return result;62 return result;
63 }63 }
64
65 pub fn pop(self: &Self) -> T {
66 self.len -= 1;
67 return self.items[self.len];
68 }
64 }69 }
65}70}
6671
67test "basicListTest" {72test "basic list test" {
68 var list = List(i32).init(&debug.global_allocator);73 var list = List(i32).init(&debug.global_allocator);
69 defer list.deinit();74 defer list.deinit();
7075
...@@ -75,4 +80,7 @@ test "basicListTest" {...@@ -75,4 +80,7 @@ test "basicListTest" {
75 {var i: usize = 0; while (i < 10; i += 1) {80 {var i: usize = 0; while (i < 10; i += 1) {
76 assert(list.items[i] == i32(i + 1));81 assert(list.items[i] == i32(i + 1));
77 }}82 }}
83
84 assert(list.pop() == 10);
85 assert(list.len == 9);
78}86}
std/mem.zig+30
...@@ -9,6 +9,8 @@ error NoMem;...@@ -9,6 +9,8 @@ error NoMem;
99
10pub const Allocator = struct {10pub const Allocator = struct {
11 allocFn: fn (self: &Allocator, n: usize) -> %[]u8,11 allocFn: fn (self: &Allocator, n: usize) -> %[]u8,
12 /// Note that old_mem may be a slice of length 0, in which case reallocFn
13 /// should simply call allocFn
12 reallocFn: fn (self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8,14 reallocFn: fn (self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8,
13 freeFn: fn (self: &Allocator, mem: []u8),15 freeFn: fn (self: &Allocator, mem: []u8),
1416
...@@ -134,6 +136,13 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool {...@@ -134,6 +136,13 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool {
134 return true;136 return true;
135}137}
136138
139/// Copies ::m to newly allocated memory. Caller is responsible to free it.
140pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) -> %[]T {
141 const new_buf = %return allocator.alloc(T, m.len);
142 copy(T, new_buf, m);
143 return new_buf;
144}
145
137/// Linear search for the index of a scalar value inside a slice.146/// Linear search for the index of a scalar value inside a slice.
138pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {147pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {
139 for (slice) |item, i| {148 for (slice) |item, i| {
...@@ -144,6 +153,27 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {...@@ -144,6 +153,27 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {
144 return null;153 return null;
145}154}
146155
156// TODO boyer-moore algorithm
157pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) -> ?usize {
158 if (needle.len > haystack.len)
159 return null;
160
161 var i: usize = 0;
162 const end = haystack.len - needle.len;
163 while (i <= end; i += 1) {
164 if (eql(T, haystack[i...i + needle.len], needle))
165 return i;
166 }
167 return null;
168}
169
170test "mem.indexOf" {
171 assert(??indexOf(u8, "one two three four", "four") == 14);
172 assert(indexOf(u8, "one two three four", "gour") == null);
173 assert(??indexOf(u8, "foo", "foo") == 0);
174 assert(indexOf(u8, "foo", "fool") == null);
175}
176
147/// Reads an integer from memory with size equal to bytes.len.177/// Reads an integer from memory with size equal to bytes.len.
148/// T specifies the return type, which must be large enough to store178/// T specifies the return type, which must be large enough to store
149/// the result.179/// the result.
std/os/index.zig+239-4
...@@ -12,6 +12,13 @@ pub const max_noalloc_path_len = 1024;...@@ -12,6 +12,13 @@ pub const max_noalloc_path_len = 1024;
12pub const ChildProcess = @import("child_process.zig").ChildProcess;12pub const ChildProcess = @import("child_process.zig").ChildProcess;
13pub const path = @import("path.zig");13pub const path = @import("path.zig");
1414
15pub const line_sep = switch (@compileVar("os")) {
16 Os.windows => "\r\n",
17 else => "\n",
18};
19
20pub const page_size = 4 * 1024;
21
15const debug = @import("../debug.zig");22const debug = @import("../debug.zig");
16const assert = debug.assert;23const assert = debug.assert;
1724
...@@ -27,6 +34,7 @@ const cstr = @import("../cstr.zig");...@@ -27,6 +34,7 @@ const cstr = @import("../cstr.zig");
2734
28const io = @import("../io.zig");35const io = @import("../io.zig");
29const base64 = @import("../base64.zig");36const base64 = @import("../base64.zig");
37const List = @import("../list.zig").List;
3038
31error Unexpected;39error Unexpected;
32error SystemResources;40error SystemResources;
...@@ -41,6 +49,7 @@ error SymLinkLoop;...@@ -41,6 +49,7 @@ error SymLinkLoop;
41error ReadOnlyFileSystem;49error ReadOnlyFileSystem;
42error LinkQuotaExceeded;50error LinkQuotaExceeded;
43error RenameAcrossMountPoints;51error RenameAcrossMountPoints;
52error DirNotEmpty;
4453
45/// Fills `buf` with random bytes. If linking against libc, this calls the54/// Fills `buf` with random bytes. If linking against libc, this calls the
46/// appropriate OS-specific library call. Otherwise it uses the zig standard55/// appropriate OS-specific library call. Otherwise it uses the zig standard
...@@ -319,7 +328,8 @@ fn posixExecveErrnoToErr(err: usize) -> error {...@@ -319,7 +328,8 @@ fn posixExecveErrnoToErr(err: usize) -> error {
319 errno.EINVAL, errno.ENOEXEC => error.InvalidExe,328 errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
320 errno.EIO, errno.ELOOP => error.FileSystem,329 errno.EIO, errno.ELOOP => error.FileSystem,
321 errno.EISDIR => error.IsDir,330 errno.EISDIR => error.IsDir,
322 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,331 errno.ENOENT => error.FileNotFound,
332 errno.ENOTDIR => error.NotDir,
323 errno.ETXTBSY => error.FileBusy,333 errno.ETXTBSY => error.FileBusy,
324 else => error.Unexpected,334 else => error.Unexpected,
325 };335 };
...@@ -413,7 +423,8 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con...@@ -413,7 +423,8 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
413 errno.EIO => error.FileSystem,423 errno.EIO => error.FileSystem,
414 errno.ELOOP => error.SymLinkLoop,424 errno.ELOOP => error.SymLinkLoop,
415 errno.ENAMETOOLONG => error.NameTooLong,425 errno.ENAMETOOLONG => error.NameTooLong,
416 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,426 errno.ENOENT => error.FileNotFound,
427 errno.ENOTDIR => error.NotDir,
417 errno.ENOMEM => error.SystemResources,428 errno.ENOMEM => error.SystemResources,
418 errno.ENOSPC => error.NoSpaceLeft,429 errno.ENOSPC => error.NoSpaceLeft,
419 errno.EROFS => error.ReadOnlyFileSystem,430 errno.EROFS => error.ReadOnlyFileSystem,
...@@ -471,7 +482,8 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {...@@ -471,7 +482,8 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {
471 errno.EISDIR => error.IsDir,482 errno.EISDIR => error.IsDir,
472 errno.ELOOP => error.SymLinkLoop,483 errno.ELOOP => error.SymLinkLoop,
473 errno.ENAMETOOLONG => error.NameTooLong,484 errno.ENAMETOOLONG => error.NameTooLong,
474 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,485 errno.ENOENT => error.FileNotFound,
486 errno.ENOTDIR => error.NotDir,
475 errno.ENOMEM => error.SystemResources,487 errno.ENOMEM => error.SystemResources,
476 errno.EROFS => error.ReadOnlyFileSystem,488 errno.EROFS => error.ReadOnlyFileSystem,
477 else => error.Unexpected,489 else => error.Unexpected,
...@@ -518,7 +530,8 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)...@@ -518,7 +530,8 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
518 errno.ELOOP => error.SymLinkLoop,530 errno.ELOOP => error.SymLinkLoop,
519 errno.EMLINK => error.LinkQuotaExceeded,531 errno.EMLINK => error.LinkQuotaExceeded,
520 errno.ENAMETOOLONG => error.NameTooLong,532 errno.ENAMETOOLONG => error.NameTooLong,
521 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,533 errno.ENOENT => error.FileNotFound,
534 errno.ENOTDIR => error.NotDir,
522 errno.ENOMEM => error.SystemResources,535 errno.ENOMEM => error.SystemResources,
523 errno.ENOSPC => error.NoSpaceLeft,536 errno.ENOSPC => error.NoSpaceLeft,
524 errno.EEXIST, errno.ENOTEMPTY => error.PathAlreadyExists,537 errno.EEXIST, errno.ENOTEMPTY => error.PathAlreadyExists,
...@@ -528,3 +541,225 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)...@@ -528,3 +541,225 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
528 };541 };
529 }542 }
530}543}
544
545pub fn makeDir(allocator: &Allocator, dir_path: []const u8) -> %void {
546 const path_buf = %return allocator.alloc(u8, dir_path.len + 1);
547 defer allocator.free(path_buf);
548
549 mem.copy(u8, path_buf, dir_path);
550 path_buf[dir_path.len] = 0;
551
552 const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755));
553 if (err > 0) {
554 return switch (err) {
555 errno.EACCES, errno.EPERM => error.AccessDenied,
556 errno.EDQUOT => error.DiskQuota,
557 errno.EEXIST => error.PathAlreadyExists,
558 errno.EFAULT => unreachable,
559 errno.ELOOP => error.SymLinkLoop,
560 errno.EMLINK => error.LinkQuotaExceeded,
561 errno.ENAMETOOLONG => error.NameTooLong,
562 errno.ENOENT => error.FileNotFound,
563 errno.ENOMEM => error.SystemResources,
564 errno.ENOSPC => error.NoSpaceLeft,
565 errno.ENOTDIR => error.NotDir,
566 errno.EROFS => error.ReadOnlyFileSystem,
567 else => error.Unexpected,
568 };
569 }
570}
571
572/// Calls makeDir recursively to make an entire path. Returns success if the path
573/// already exists and is a directory.
574pub fn makePath(allocator: &Allocator, full_path: []const u8) -> %void {
575 const child_dir = %return path.dirname(allocator, full_path);
576 defer allocator.free(child_dir);
577
578 if (mem.eql(u8, child_dir, full_path))
579 return;
580
581 makePath(allocator, child_dir) %% |err| {
582 if (err != error.PathAlreadyExists)
583 return err;
584 };
585
586 makeDir(allocator, full_path) %% |err| {
587 if (err != error.PathAlreadyExists)
588 return err;
589 // TODO stat the file and return an error if it's not a directory
590 };
591}
592
593/// Returns ::error.DirNotEmpty if the directory is not empty.
594/// To delete a directory recursively, see ::deleteTree
595pub fn deleteDir(allocator: &Allocator, dir_path: []const u8) -> %void {
596 const path_buf = %return allocator.alloc(u8, dir_path.len + 1);
597 defer allocator.free(path_buf);
598
599 mem.copy(u8, path_buf, dir_path);
600 path_buf[dir_path.len] = 0;
601
602 const err = posix.getErrno(posix.rmdir(path_buf.ptr));
603 if (err > 0) {
604 return switch (err) {
605 errno.EACCES, errno.EPERM => error.AccessDenied,
606 errno.EBUSY => error.FileBusy,
607 errno.EFAULT, errno.EINVAL => unreachable,
608 errno.ELOOP => error.SymLinkLoop,
609 errno.ENAMETOOLONG => error.NameTooLong,
610 errno.ENOENT => error.FileNotFound,
611 errno.ENOMEM => error.SystemResources,
612 errno.ENOTDIR => error.NotDir,
613 errno.EEXIST, errno.ENOTEMPTY => error.DirNotEmpty,
614 errno.EROFS => error.ReadOnlyFileSystem,
615 else => error.Unexpected,
616 };
617 }
618}
619
620/// Whether ::full_path describes a symlink, file, or directory, this function
621/// removes it. If it cannot be removed because it is a non-empty directory,
622/// this function recursively removes its entries and then tries again.
623// TODO non-recursive implementation
624pub fn deleteTree(allocator: &Allocator, full_path: []const u8) -> %void {
625start_over:
626 // First, try deleting the item as a file. This way we don't follow sym links.
627 try (deleteFile(allocator, full_path)) {
628 return;
629 } else |err| {
630 if (err == error.FileNotFound)
631 return;
632 if (err != error.IsDir)
633 return err;
634 }
635 {
636 var dir = Dir.open(allocator, full_path) %% |err| {
637 if (err == error.FileNotFound)
638 return;
639 if (err == error.NotDir)
640 goto start_over;
641 return err;
642 };
643 defer dir.close();
644
645 var full_entry_buf = List(u8).init(allocator);
646 defer full_entry_buf.deinit();
647
648 while (true) {
649 const entry = (%return dir.next()) ?? break;
650
651 %return full_entry_buf.resize(full_path.len + entry.name.len + 1);
652 const full_entry_path = full_entry_buf.toSlice();
653 mem.copy(u8, full_entry_path, full_path);
654 full_entry_path[full_path.len] = '/';
655 mem.copy(u8, full_entry_path[full_path.len + 1...], entry.name);
656
657 %return deleteTree(allocator, full_entry_path);
658 }
659 }
660 return deleteDir(allocator, full_path);
661}
662
663pub const Dir = struct {
664 fd: i32,
665 allocator: &Allocator,
666 buf: []u8,
667 index: usize,
668 end_index: usize,
669
670 const LinuxEntry = extern struct {
671 d_ino: usize,
672 d_off: usize,
673 d_reclen: u16,
674 d_name: u8, // field address is the address of first byte of name
675 };
676
677 pub const Entry = struct {
678 name: []const u8,
679 kind: Kind,
680
681 pub const Kind = enum {
682 BlockDevice,
683 CharacterDevice,
684 Directory,
685 NamedPipe,
686 SymLink,
687 File,
688 UnixDomainSocket,
689 Unknown,
690 };
691 };
692
693 pub fn open(allocator: &Allocator, dir_path: []const u8) -> %Dir {
694 const fd = %return posixOpen(dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0, allocator);
695 return Dir {
696 .allocator = allocator,
697 .fd = fd,
698 .index = 0,
699 .end_index = 0,
700 .buf = []u8{},
701 };
702 }
703
704 pub fn close(self: &Dir) {
705 self.allocator.free(self.buf);
706 posixClose(self.fd);
707 }
708
709 /// Memory such as file names referenced in this returned entry becomes invalid
710 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
711 pub fn next(self: &Dir) -> %?Entry {
712 start_over:
713 if (self.index >= self.end_index) {
714 if (self.buf.len == 0) {
715 self.buf = %return self.allocator.alloc(u8, 2); //page_size);
716 }
717
718 while (true) {
719 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
720 const err = linux.getErrno(result);
721 if (err > 0) {
722 switch (err) {
723 errno.EBADF, errno.EFAULT, errno.ENOTDIR => unreachable,
724 errno.EINVAL => {
725 self.buf = %return self.allocator.realloc(u8, self.buf, self.buf.len * 2);
726 continue;
727 },
728 else => return error.Unexpected,
729 };
730 }
731 if (result == 0)
732 return null;
733 self.index = 0;
734 self.end_index = result;
735 break;
736 }
737 }
738 const linux_entry = @ptrcast(&LinuxEntry, &self.buf[self.index]);
739 const next_index = self.index + linux_entry.d_reclen;
740 self.index = next_index;
741
742 const name = (&linux_entry.d_name)[0...cstr.len(&linux_entry.d_name)];
743
744 // skip . and .. entries
745 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
746 goto start_over;
747 }
748
749 const type_char = self.buf[next_index - 1];
750 const entry_kind = switch (type_char) {
751 posix.DT_BLK => Entry.Kind.BlockDevice,
752 posix.DT_CHR => Entry.Kind.CharacterDevice,
753 posix.DT_DIR => Entry.Kind.Directory,
754 posix.DT_FIFO => Entry.Kind.NamedPipe,
755 posix.DT_LNK => Entry.Kind.SymLink,
756 posix.DT_REG => Entry.Kind.File,
757 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
758 else => Entry.Kind.Unknown,
759 };
760 return Entry {
761 .name = name,
762 .kind = entry_kind,
763 };
764 }
765};
std/os/linux.zig+21
...@@ -241,6 +241,15 @@ pub const AF_NFC = PF_NFC;...@@ -241,6 +241,15 @@ pub const AF_NFC = PF_NFC;
241pub const AF_VSOCK = PF_VSOCK;241pub const AF_VSOCK = PF_VSOCK;
242pub const AF_MAX = PF_MAX;242pub const AF_MAX = PF_MAX;
243243
244pub const DT_UNKNOWN = 0;
245pub const DT_FIFO = 1;
246pub const DT_CHR = 2;
247pub const DT_DIR = 4;
248pub const DT_BLK = 6;
249pub const DT_REG = 8;
250pub const DT_LNK = 10;
251pub const DT_SOCK = 12;
252pub const DT_WHT = 14;
244253
245fn unsigned(s: i32) -> u32 { *@ptrcast(&u32, &s) }254fn unsigned(s: i32) -> u32 { *@ptrcast(&u32, &s) }
246fn signed(s: u32) -> i32 { *@ptrcast(&i32, &s) }255fn signed(s: u32) -> i32 { *@ptrcast(&i32, &s) }
...@@ -273,6 +282,14 @@ pub fn getcwd(buf: &u8, size: usize) -> usize {...@@ -273,6 +282,14 @@ pub fn getcwd(buf: &u8, size: usize) -> usize {
273 arch.syscall2(arch.SYS_getcwd, usize(buf), size)282 arch.syscall2(arch.SYS_getcwd, usize(buf), size)
274}283}
275284
285pub fn getdents(fd: i32, dirp: &u8, count: usize) -> usize {
286 arch.syscall3(arch.SYS_getdents, usize(fd), usize(dirp), usize(count))
287}
288
289pub fn mkdir(path: &const u8, mode: usize) -> usize {
290 arch.syscall2(arch.SYS_mkdir, usize(path), mode)
291}
292
276pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)293pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
277 -> usize294 -> usize
278{295{
...@@ -287,6 +304,10 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {...@@ -287,6 +304,10 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
287 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)304 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
288}305}
289306
307pub fn rmdir(path: &const u8) -> usize {
308 arch.syscall1(arch.SYS_rmdir, usize(path))
309}
310
290pub fn symlink(existing: &const u8, new: &const u8) -> usize {311pub fn symlink(existing: &const u8, new: &const u8) -> usize {
291 arch.syscall2(arch.SYS_symlink, usize(existing), usize(new))312 arch.syscall2(arch.SYS_symlink, usize(existing), usize(new))
292}313}
std/os/path.zig+49-10
...@@ -4,22 +4,61 @@ const mem = @import("../mem.zig");...@@ -4,22 +4,61 @@ const mem = @import("../mem.zig");
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
55
6/// Allocates memory for the result, which must be freed by the caller.6/// Allocates memory for the result, which must be freed by the caller.
7pub fn join(allocator: &Allocator, dirname: []const u8, basename: []const u8) -> %[]const u8 {7pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 {
8 const buf = %return allocator.alloc(u8, dirname.len + basename.len + 1);8 assert(paths.len >= 2);
9 var total_paths_len: usize = paths.len; // 1 slash per path
10 {
11 comptime var path_i = 0;
12 inline while (path_i < paths.len; path_i += 1) {
13 const arg = ([]const u8)(paths[path_i]);
14 total_paths_len += arg.len;
15 }
16 }
17
18 const buf = %return allocator.alloc(u8, total_paths_len);
9 %defer allocator.free(buf);19 %defer allocator.free(buf);
1020
11 mem.copy(u8, buf, dirname);21 var buf_index: usize = 0;
12 if (dirname[dirname.len - 1] == '/') {22 comptime var path_i = 0;
13 mem.copy(u8, buf[dirname.len...], basename);23 inline while (true) {
14 return buf[0...buf.len - 1];24 const arg = ([]const u8)(paths[path_i]);
15 } else {25 path_i += 1;
16 buf[dirname.len] = '/';26 mem.copy(u8, buf[buf_index...], arg);
17 mem.copy(u8, buf[dirname.len + 1 ...], basename);27 buf_index += arg.len;
18 return buf;28 if (path_i >= paths.len) break;
29 if (arg[arg.len - 1] != '/') {
30 buf[buf_index] = '/';
31 buf_index += 1;
32 }
19 }33 }
34
35 return buf[0...buf_index];
20}36}
2137
22test "os.path.join" {38test "os.path.join" {
23 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c"));39 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c"));
24 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c"));40 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c"));
41
42 assert(mem.eql(u8, %%join(&debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c"));
43 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/", "b/", "c"), "/a/b/c"));
44}
45
46pub fn dirname(allocator: &Allocator, path: []const u8) -> %[]u8 {
47 if (path.len != 0) {
48 var last_index: usize = path.len - 1;
49 if (path[last_index] == '/')
50 last_index -= 1;
51
52 var i: usize = last_index;
53 while (true) {
54 const c = path[i];
55 if (c == '/')
56 return mem.dupe(allocator, u8, path[0...i]);
57 if (i == 0)
58 break;
59 i -= 1;
60 }
61 }
62
63 return mem.dupe(allocator, u8, ".");
25}64}
std/special/build_file_template.zig+3-1
...@@ -3,6 +3,8 @@ const Builder = @import("std").build.Builder;...@@ -3,6 +3,8 @@ const Builder = @import("std").build.Builder;
3pub fn build(b: &Builder) {3pub fn build(b: &Builder) {
4 const release = b.option(bool, "release", "optimizations on and safety off") ?? false;4 const release = b.option(bool, "release", "optimizations on and safety off") ?? false;
55
6 var exe = b.addExe("src/main.zig", "YOUR_NAME_HERE");6 const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig");
7 exe.setRelease(release);7 exe.setRelease(release);
8
9 b.default_step.dependOn(&exe.step);
8}10}
std/special/build_runner.zig+32-21
...@@ -10,74 +10,85 @@ const List = std.list.List;...@@ -10,74 +10,85 @@ const List = std.list.List;
10error InvalidArgs;10error InvalidArgs;
1111
12pub fn main() -> %void {12pub fn main() -> %void {
13 var arg_i: usize = 1;
14
15 const zig_exe = {
16 if (arg_i >= os.args.count()) {
17 %%io.stderr.printf("Expected first argument to be path to zig compiler\n");
18 return error.InvalidArgs;
19 }
20 const result = os.args.at(arg_i);
21 arg_i += 1;
22 result
23 };
24
25 const build_root = {
26 if (arg_i >= os.args.count()) {
27 %%io.stderr.printf("Expected second argument to be build root directory path\n");
28 return error.InvalidArgs;
29 }
30 const result = os.args.at(arg_i);
31 arg_i += 1;
32 result
33 };
34
13 // TODO use a more general purpose allocator here35 // TODO use a more general purpose allocator here
14 var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024);36 var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024);
15 defer inc_allocator.deinit();37 defer inc_allocator.deinit();
1638
17 const allocator = &inc_allocator.allocator;39 const allocator = &inc_allocator.allocator;
1840
19 var builder = Builder.init(allocator);41 var builder = Builder.init(allocator, zig_exe, build_root);
20 defer builder.deinit();42 defer builder.deinit();
2143
22 var maybe_zig_exe: ?[]const u8 = null;
23 var targets = List([]const u8).init(allocator);44 var targets = List([]const u8).init(allocator);
2445
25 var prefix: ?[]const u8 = null;46 var prefix: ?[]const u8 = null;
2647
27 var arg_i: usize = 1;
28 while (arg_i < os.args.count(); arg_i += 1) {48 while (arg_i < os.args.count(); arg_i += 1) {
29 const arg = os.args.at(arg_i);49 const arg = os.args.at(arg_i);
30 if (mem.startsWith(u8, arg, "-D")) {50 if (mem.startsWith(u8, arg, "-D")) {
31 const option_contents = arg[2...];51 const option_contents = arg[2...];
32 if (option_contents.len == 0) {52 if (option_contents.len == 0) {
33 %%io.stderr.printf("Expected option name after '-D'\n\n");53 %%io.stderr.printf("Expected option name after '-D'\n\n");
34 return usage(&builder, maybe_zig_exe, false, &io.stderr);54 return usage(&builder, false, &io.stderr);
35 }55 }
36 if (const name_end ?= mem.indexOfScalar(u8, option_contents, '=')) {56 if (const name_end ?= mem.indexOfScalar(u8, option_contents, '=')) {
37 const option_name = option_contents[0...name_end];57 const option_name = option_contents[0...name_end];
38 const option_value = option_contents[name_end...];58 const option_value = option_contents[name_end + 1...];
39 if (builder.addUserInputOption(option_name, option_value))59 if (builder.addUserInputOption(option_name, option_value))
40 return usage(&builder, maybe_zig_exe, false, &io.stderr);60 return usage(&builder, false, &io.stderr);
41 } else {61 } else {
42 if (builder.addUserInputFlag(option_contents))62 if (builder.addUserInputFlag(option_contents))
43 return usage(&builder, maybe_zig_exe, false, &io.stderr);63 return usage(&builder, false, &io.stderr);
44 }64 }
45 } else if (mem.startsWith(u8, arg, "-")) {65 } else if (mem.startsWith(u8, arg, "-")) {
46 if (mem.eql(u8, arg, "--verbose")) {66 if (mem.eql(u8, arg, "--verbose")) {
47 builder.verbose = true;67 builder.verbose = true;
48 } else if (mem.eql(u8, arg, "--help")) {68 } else if (mem.eql(u8, arg, "--help")) {
49 return usage(&builder, maybe_zig_exe, false, &io.stdout);69 return usage(&builder, false, &io.stdout);
50 } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) {70 } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) {
51 arg_i += 1;71 arg_i += 1;
52 prefix = os.args.at(arg_i);72 prefix = os.args.at(arg_i);
53 } else {73 } else {
54 %%io.stderr.printf("Unrecognized argument: {}\n\n", arg);74 %%io.stderr.printf("Unrecognized argument: {}\n\n", arg);
55 return usage(&builder, maybe_zig_exe, false, &io.stderr);75 return usage(&builder, false, &io.stderr);
56 }76 }
57 } else if (maybe_zig_exe == null) {
58 maybe_zig_exe = arg;
59 } else {77 } else {
60 %%targets.append(arg);78 %%targets.append(arg);
61 }79 }
62 }80 }
6381
64 builder.zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr);
65 builder.setInstallPrefix(prefix);82 builder.setInstallPrefix(prefix);
66
67 root.build(&builder);83 root.build(&builder);
6884
69 if (builder.validateUserInputDidItFail())85 if (builder.validateUserInputDidItFail())
70 return usage(&builder, maybe_zig_exe, true, &io.stderr);86 return usage(&builder, true, &io.stderr);
7187
72 %return builder.make(targets.toSliceConst());88 %return builder.make(targets.toSliceConst());
73}89}
7490
75fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, out_stream: &io.OutStream) -> %void {91fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) -> %void {
76 const zig_exe = maybe_zig_exe ?? {
77 %%out_stream.printf("Expected first argument to be path to zig compiler\n");
78 return error.InvalidArgs;
79 };
80
81 // run the build script to collect the options92 // run the build script to collect the options
82 if (!already_ran_build) {93 if (!already_ran_build) {
83 builder.setInstallPrefix(null);94 builder.setInstallPrefix(null);
...@@ -90,7 +101,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,...@@ -90,7 +101,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
90 \\101 \\
91 \\Steps:102 \\Steps:
92 \\103 \\
93 , zig_exe);104 , builder.zig_exe);
94105
95 const allocator = builder.allocator;106 const allocator = builder.allocator;
96 for (builder.top_level_steps.toSliceConst()) |top_level_step| {107 for (builder.top_level_steps.toSliceConst()) |top_level_step| {
test/assemble_and_link.zig created+26
...@@ -0,0 +1,26 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.CompareOutputContext) {
4 if (@compileVar("os") == Os.linux and @compileVar("arch") == Arch.x86_64) {
5 cases.addAsm("hello world linux x86_64",
6 \\.text
7 \\.globl _start
8 \\
9 \\_start:
10 \\ mov rax, 1
11 \\ mov rdi, 1
12 \\ lea rsi, msg
13 \\ mov rdx, 14
14 \\ syscall
15 \\
16 \\ mov rax, 60
17 \\ mov rdi, 0
18 \\ syscall
19 \\
20 \\.data
21 \\
22 \\msg:
23 \\ .ascii "Hello, world!\n"
24 , "Hello, world!\n");
25 }
26}
test/behavior.zig created+39
...@@ -0,0 +1,39 @@
1comptime {
2 _ = @import("cases/array.zig");
3 _ = @import("cases/asm.zig");
4 _ = @import("cases/atomics.zig");
5 _ = @import("cases/bool.zig");
6 _ = @import("cases/cast.zig");
7 _ = @import("cases/const_slice_child.zig");
8 _ = @import("cases/defer.zig");
9 _ = @import("cases/enum.zig");
10 _ = @import("cases/enum_with_members.zig");
11 _ = @import("cases/error.zig");
12 _ = @import("cases/eval.zig");
13 _ = @import("cases/field_parent_ptr.zig");
14 _ = @import("cases/fn.zig");
15 _ = @import("cases/for.zig");
16 _ = @import("cases/generics.zig");
17 _ = @import("cases/goto.zig");
18 _ = @import("cases/if.zig");
19 _ = @import("cases/import.zig");
20 _ = @import("cases/incomplete_struct_param_tld.zig");
21 _ = @import("cases/ir_block_deps.zig");
22 _ = @import("cases/math.zig");
23 _ = @import("cases/misc.zig");
24 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
25 _ = @import("cases/null.zig");
26 _ = @import("cases/pub_enum/index.zig");
27 _ = @import("cases/sizeof_and_typeof.zig");
28 _ = @import("cases/struct.zig");
29 _ = @import("cases/struct_contains_slice_of_itself.zig");
30 _ = @import("cases/switch.zig");
31 _ = @import("cases/switch_prong_err_enum.zig");
32 _ = @import("cases/switch_prong_implicit_cast.zig");
33 _ = @import("cases/this.zig");
34 _ = @import("cases/try.zig");
35 _ = @import("cases/undefined.zig");
36 _ = @import("cases/var_args.zig");
37 _ = @import("cases/void.zig");
38 _ = @import("cases/while.zig");
39}
test/build_examples.zig created+8
...@@ -0,0 +1,8 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.BuildExamplesContext) {
4 cases.add("example/hello_world/hello.zig");
5 cases.addC("example/hello_world/hello_libc.zig");
6 cases.add("example/cat/main.zig");
7 cases.add("example/guess_number/main.zig");
8}
test/compare_output.zig created+404
...@@ -0,0 +1,404 @@
1const os = @import("std").os;
2const tests = @import("tests.zig");
3
4pub fn addCases(cases: &tests.CompareOutputContext) {
5 cases.addC("hello world with libc",
6 \\const c = @cImport(@cInclude("stdio.h"));
7 \\export fn main(argc: c_int, argv: &&u8) -> c_int {
8 \\ _ = c.puts(c"Hello, world!");
9 \\ return 0;
10 \\}
11 , "Hello, world!" ++ os.line_sep);
12
13 cases.addCase({
14 var tc = cases.create("multiple files with private function",
15 \\use @import("std").io;
16 \\use @import("foo.zig");
17 \\
18 \\pub fn main() -> %void {
19 \\ privateFunction();
20 \\ %%stdout.printf("OK 2\n");
21 \\}
22 \\
23 \\fn privateFunction() {
24 \\ printText();
25 \\}
26 , "OK 1\nOK 2\n");
27
28 tc.addSourceFile("foo.zig",
29 \\use @import("std").io;
30 \\
31 \\// purposefully conflicting function with main.zig
32 \\// but it's private so it should be OK
33 \\fn privateFunction() {
34 \\ %%stdout.printf("OK 1\n");
35 \\}
36 \\
37 \\pub fn printText() {
38 \\ privateFunction();
39 \\}
40 );
41
42 tc
43 });
44
45 cases.addCase({
46 var tc = cases.create("import segregation",
47 \\use @import("foo.zig");
48 \\use @import("bar.zig");
49 \\
50 \\pub fn main() -> %void {
51 \\ foo_function();
52 \\ bar_function();
53 \\}
54 , "OK\nOK\n");
55
56 tc.addSourceFile("foo.zig",
57 \\use @import("std").io;
58 \\pub fn foo_function() {
59 \\ %%stdout.printf("OK\n");
60 \\}
61 );
62
63 tc.addSourceFile("bar.zig",
64 \\use @import("other.zig");
65 \\use @import("std").io;
66 \\
67 \\pub fn bar_function() {
68 \\ if (foo_function()) {
69 \\ %%stdout.printf("OK\n");
70 \\ }
71 \\}
72 );
73
74 tc.addSourceFile("other.zig",
75 \\pub fn foo_function() -> bool {
76 \\ // this one conflicts with the one from foo
77 \\ return true;
78 \\}
79 );
80
81 tc
82 });
83
84 cases.addCase({
85 var tc = cases.create("two files use import each other",
86 \\use @import("a.zig");
87 \\
88 \\pub fn main() -> %void {
89 \\ ok();
90 \\}
91 , "OK\n");
92
93 tc.addSourceFile("a.zig",
94 \\use @import("b.zig");
95 \\const io = @import("std").io;
96 \\
97 \\pub const a_text = "OK\n";
98 \\
99 \\pub fn ok() {
100 \\ %%io.stdout.printf(b_text);
101 \\}
102 );
103
104 tc.addSourceFile("b.zig",
105 \\use @import("a.zig");
106 \\
107 \\pub const b_text = a_text;
108 );
109
110 tc
111 });
112
113 cases.add("hello world without libc",
114 \\const io = @import("std").io;
115 \\
116 \\pub fn main() -> %void {
117 \\ %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));
118 \\}
119 , "Hello, world!\n0012 012 a\n");
120
121 cases.addC("number literals",
122 \\const c = @cImport(@cInclude("stdio.h"));
123 \\
124 \\export fn main(argc: c_int, argv: &&u8) -> c_int {
125 \\ _ = c.printf(c"0: %llu\n",
126 \\ u64(0));
127 \\ _ = c.printf(c"320402575052271: %llu\n",
128 \\ u64(320402575052271));
129 \\ _ = c.printf(c"0x01236789abcdef: %llu\n",
130 \\ u64(0x01236789abcdef));
131 \\ _ = c.printf(c"0xffffffffffffffff: %llu\n",
132 \\ u64(0xffffffffffffffff));
133 \\ _ = c.printf(c"0x000000ffffffffffffffff: %llu\n",
134 \\ u64(0x000000ffffffffffffffff));
135 \\ _ = c.printf(c"0o1777777777777777777777: %llu\n",
136 \\ u64(0o1777777777777777777777));
137 \\ _ = c.printf(c"0o0000001777777777777777777777: %llu\n",
138 \\ u64(0o0000001777777777777777777777));
139 \\ _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
140 \\ u64(0b1111111111111111111111111111111111111111111111111111111111111111));
141 \\ _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
142 \\ u64(0b0000001111111111111111111111111111111111111111111111111111111111111111));
143 \\
144 \\ _ = c.printf(c"\n");
145 \\
146 \\ _ = c.printf(c"0.0: %a\n",
147 \\ f64(0.0));
148 \\ _ = c.printf(c"0e0: %a\n",
149 \\ f64(0e0));
150 \\ _ = c.printf(c"0.0e0: %a\n",
151 \\ f64(0.0e0));
152 \\ _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n",
153 \\ f64(000000000000000000000000000000000000000000000000000000000.0e0));
154 \\ _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n",
155 \\ f64(0.000000000000000000000000000000000000000000000000000000000e0));
156 \\ _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n",
157 \\ f64(0.0e000000000000000000000000000000000000000000000000000000000));
158 \\ _ = c.printf(c"1.0: %a\n",
159 \\ f64(1.0));
160 \\ _ = c.printf(c"10.0: %a\n",
161 \\ f64(10.0));
162 \\ _ = c.printf(c"10.5: %a\n",
163 \\ f64(10.5));
164 \\ _ = c.printf(c"10.5e5: %a\n",
165 \\ f64(10.5e5));
166 \\ _ = c.printf(c"10.5e+5: %a\n",
167 \\ f64(10.5e+5));
168 \\ _ = c.printf(c"50.0e-2: %a\n",
169 \\ f64(50.0e-2));
170 \\ _ = c.printf(c"50e-2: %a\n",
171 \\ f64(50e-2));
172 \\
173 \\ _ = c.printf(c"\n");
174 \\
175 \\ _ = c.printf(c"0x1.0: %a\n",
176 \\ f64(0x1.0));
177 \\ _ = c.printf(c"0x10.0: %a\n",
178 \\ f64(0x10.0));
179 \\ _ = c.printf(c"0x100.0: %a\n",
180 \\ f64(0x100.0));
181 \\ _ = c.printf(c"0x103.0: %a\n",
182 \\ f64(0x103.0));
183 \\ _ = c.printf(c"0x103.7: %a\n",
184 \\ f64(0x103.7));
185 \\ _ = c.printf(c"0x103.70: %a\n",
186 \\ f64(0x103.70));
187 \\ _ = c.printf(c"0x103.70p4: %a\n",
188 \\ f64(0x103.70p4));
189 \\ _ = c.printf(c"0x103.70p5: %a\n",
190 \\ f64(0x103.70p5));
191 \\ _ = c.printf(c"0x103.70p+5: %a\n",
192 \\ f64(0x103.70p+5));
193 \\ _ = c.printf(c"0x103.70p-5: %a\n",
194 \\ f64(0x103.70p-5));
195 \\
196 \\ _ = c.printf(c"\n");
197 \\
198 \\ _ = c.printf(c"0b10100.00010e0: %a\n",
199 \\ f64(0b10100.00010e0));
200 \\ _ = c.printf(c"0o10700.00010e0: %a\n",
201 \\ f64(0o10700.00010e0));
202 \\
203 \\ return 0;
204 \\}
205 ,
206 \\0: 0
207 \\320402575052271: 320402575052271
208 \\0x01236789abcdef: 320402575052271
209 \\0xffffffffffffffff: 18446744073709551615
210 \\0x000000ffffffffffffffff: 18446744073709551615
211 \\0o1777777777777777777777: 18446744073709551615
212 \\0o0000001777777777777777777777: 18446744073709551615
213 \\0b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615
214 \\0b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615
215 \\
216 \\0.0: 0x0p+0
217 \\0e0: 0x0p+0
218 \\0.0e0: 0x0p+0
219 \\000000000000000000000000000000000000000000000000000000000.0e0: 0x0p+0
220 \\0.000000000000000000000000000000000000000000000000000000000e0: 0x0p+0
221 \\0.0e000000000000000000000000000000000000000000000000000000000: 0x0p+0
222 \\1.0: 0x1p+0
223 \\10.0: 0x1.4p+3
224 \\10.5: 0x1.5p+3
225 \\10.5e5: 0x1.0059p+20
226 \\10.5e+5: 0x1.0059p+20
227 \\50.0e-2: 0x1p-1
228 \\50e-2: 0x1p-1
229 \\
230 \\0x1.0: 0x1p+0
231 \\0x10.0: 0x1p+4
232 \\0x100.0: 0x1p+8
233 \\0x103.0: 0x1.03p+8
234 \\0x103.7: 0x1.037p+8
235 \\0x103.70: 0x1.037p+8
236 \\0x103.70p4: 0x1.037p+12
237 \\0x103.70p5: 0x1.037p+13
238 \\0x103.70p+5: 0x1.037p+13
239 \\0x103.70p-5: 0x1.037p+3
240 \\
241 \\0b10100.00010e0: 0x1.41p+4
242 \\0o10700.00010e0: 0x1.1c0001p+12
243 \\
244 );
245
246 cases.add("order-independent declarations",
247 \\const io = @import("std").io;
248 \\const z = io.stdin_fileno;
249 \\const x : @typeOf(y) = 1234;
250 \\const y : u16 = 5678;
251 \\pub fn main() -> %void {
252 \\ var x_local : i32 = print_ok(x);
253 \\}
254 \\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
255 \\ %%io.stdout.printf("OK\n");
256 \\ return 0;
257 \\}
258 \\const foo : i32 = 0;
259 , "OK\n");
260
261 cases.addC("expose function pointer to C land",
262 \\const c = @cImport(@cInclude("stdlib.h"));
263 \\
264 \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
265 \\ const a_int = @ptrcast(&i32, a ?? unreachable);
266 \\ const b_int = @ptrcast(&i32, b ?? unreachable);
267 \\ if (*a_int < *b_int) {
268 \\ -1
269 \\ } else if (*a_int > *b_int) {
270 \\ 1
271 \\ } else {
272 \\ c_int(0)
273 \\ }
274 \\}
275 \\
276 \\export fn main() -> c_int {
277 \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
278 \\
279 \\ c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
280 \\
281 \\ for (array) |item, i| {
282 \\ if (item != i) {
283 \\ c.abort();
284 \\ }
285 \\ }
286 \\
287 \\ return 0;
288 \\}
289 , "");
290
291 cases.addC("casting between float and integer types",
292 \\const c = @cImport(@cInclude("stdio.h"));
293 \\export fn main(argc: c_int, argv: &&u8) -> c_int {
294 \\ const small: f32 = 3.25;
295 \\ const x: f64 = small;
296 \\ const y = i32(x);
297 \\ const z = f64(y);
298 \\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4));
299 \\ return 0;
300 \\}
301 , "3.25\n3\n3.00\n-0.40\n");
302
303 cases.add("same named methods in incomplete struct",
304 \\const io = @import("std").io;
305 \\
306 \\const Foo = struct {
307 \\ field1: Bar,
308 \\
309 \\ fn method(a: &const Foo) -> bool { true }
310 \\};
311 \\
312 \\const Bar = struct {
313 \\ field2: i32,
314 \\
315 \\ fn method(b: &const Bar) -> bool { true }
316 \\};
317 \\
318 \\pub fn main() -> %void {
319 \\ const bar = Bar {.field2 = 13,};
320 \\ const foo = Foo {.field1 = bar,};
321 \\ if (!foo.method()) {
322 \\ %%io.stdout.printf("BAD\n");
323 \\ }
324 \\ if (!bar.method()) {
325 \\ %%io.stdout.printf("BAD\n");
326 \\ }
327 \\ %%io.stdout.printf("OK\n");
328 \\}
329 , "OK\n");
330
331 cases.add("defer with only fallthrough",
332 \\const io = @import("std").io;
333 \\pub fn main() -> %void {
334 \\ %%io.stdout.printf("before\n");
335 \\ defer %%io.stdout.printf("defer1\n");
336 \\ defer %%io.stdout.printf("defer2\n");
337 \\ defer %%io.stdout.printf("defer3\n");
338 \\ %%io.stdout.printf("after\n");
339 \\}
340 , "before\nafter\ndefer3\ndefer2\ndefer1\n");
341
342 cases.add("defer with return",
343 \\const io = @import("std").io;
344 \\const os = @import("std").os;
345 \\pub fn main() -> %void {
346 \\ %%io.stdout.printf("before\n");
347 \\ defer %%io.stdout.printf("defer1\n");
348 \\ defer %%io.stdout.printf("defer2\n");
349 \\ if (os.args.count() == 1) return;
350 \\ defer %%io.stdout.printf("defer3\n");
351 \\ %%io.stdout.printf("after\n");
352 \\}
353 , "before\ndefer2\ndefer1\n");
354
355 cases.add("%defer and it fails",
356 \\const io = @import("std").io;
357 \\pub fn main() -> %void {
358 \\ do_test() %% return;
359 \\}
360 \\fn do_test() -> %void {
361 \\ %%io.stdout.printf("before\n");
362 \\ defer %%io.stdout.printf("defer1\n");
363 \\ %defer %%io.stdout.printf("deferErr\n");
364 \\ %return its_gonna_fail();
365 \\ defer %%io.stdout.printf("defer3\n");
366 \\ %%io.stdout.printf("after\n");
367 \\}
368 \\error IToldYouItWouldFail;
369 \\fn its_gonna_fail() -> %void {
370 \\ return error.IToldYouItWouldFail;
371 \\}
372 , "before\ndeferErr\ndefer1\n");
373
374 cases.add("%defer and it passes",
375 \\const io = @import("std").io;
376 \\pub fn main() -> %void {
377 \\ do_test() %% return;
378 \\}
379 \\fn do_test() -> %void {
380 \\ %%io.stdout.printf("before\n");
381 \\ defer %%io.stdout.printf("defer1\n");
382 \\ %defer %%io.stdout.printf("deferErr\n");
383 \\ %return its_gonna_pass();
384 \\ defer %%io.stdout.printf("defer3\n");
385 \\ %%io.stdout.printf("after\n");
386 \\}
387 \\fn its_gonna_pass() -> %void { }
388 , "before\nafter\ndefer3\ndefer1\n");
389
390 cases.addCase({
391 var tc = cases.create("@embedFile",
392 \\const foo_txt = @embedFile("foo.txt");
393 \\const io = @import("std").io;
394 \\
395 \\pub fn main() -> %void {
396 \\ %%io.stdout.printf(foo_txt);
397 \\}
398 , "1234\nabcd\n");
399
400 tc.addSourceFile("foo.txt", "1234\nabcd\n");
401
402 tc
403 });
404}
test/compile_errors.zig created+1577
...@@ -0,0 +1,1577 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.CompileErrorContext) {
4 cases.add("implicit semicolon - block statement",
5 \\export fn entry() {
6 \\ {}
7 \\ var good = {};
8 \\ ({})
9 \\ var bad = {};
10 \\}
11 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
12
13 cases.add("implicit semicolon - block expr",
14 \\export fn entry() {
15 \\ _ = {};
16 \\ var good = {};
17 \\ _ = {}
18 \\ var bad = {};
19 \\}
20 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
21
22 cases.add("implicit semicolon - comptime statement",
23 \\export fn entry() {
24 \\ comptime {}
25 \\ var good = {};
26 \\ comptime ({})
27 \\ var bad = {};
28 \\}
29 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
30
31 cases.add("implicit semicolon - comptime expression",
32 \\export fn entry() {
33 \\ _ = comptime {};
34 \\ var good = {};
35 \\ _ = comptime {}
36 \\ var bad = {};
37 \\}
38 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
39
40 cases.add("implicit semicolon - defer",
41 \\export fn entry() {
42 \\ defer {}
43 \\ var good = {};
44 \\ defer ({})
45 \\ var bad = {};
46 \\}
47 , ".tmp_source.zig:5:5: error: expected token ';', found 'var'");
48
49 cases.add("implicit semicolon - if statement",
50 \\export fn entry() {
51 \\ if(true) {}
52 \\ var good = {};
53 \\ if(true) ({})
54 \\ var bad = {};
55 \\}
56 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
57
58 cases.add("implicit semicolon - if expression",
59 \\export fn entry() {
60 \\ _ = if(true) {};
61 \\ var good = {};
62 \\ _ = if(true) {}
63 \\ var bad = {};
64 \\}
65 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
66
67 cases.add("implicit semicolon - if-else statement",
68 \\export fn entry() {
69 \\ if(true) {} else {}
70 \\ var good = {};
71 \\ if(true) ({}) else ({})
72 \\ var bad = {};
73 \\}
74 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
75
76 cases.add("implicit semicolon - if-else expression",
77 \\export fn entry() {
78 \\ _ = if(true) {} else {};
79 \\ var good = {};
80 \\ _ = if(true) {} else {}
81 \\ var bad = {};
82 \\}
83 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
84
85 cases.add("implicit semicolon - if-else-if statement",
86 \\export fn entry() {
87 \\ if(true) {} else if(true) {}
88 \\ var good = {};
89 \\ if(true) ({}) else if(true) ({})
90 \\ var bad = {};
91 \\}
92 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
93
94 cases.add("implicit semicolon - if-else-if expression",
95 \\export fn entry() {
96 \\ _ = if(true) {} else if(true) {};
97 \\ var good = {};
98 \\ _ = if(true) {} else if(true) {}
99 \\ var bad = {};
100 \\}
101 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
102
103 cases.add("implicit semicolon - if-else-if-else statement",
104 \\export fn entry() {
105 \\ if(true) {} else if(true) {} else {}
106 \\ var good = {};
107 \\ if(true) ({}) else if(true) ({}) else ({})
108 \\ var bad = {};
109 \\}
110 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
111
112 cases.add("implicit semicolon - if-else-if-else expression",
113 \\export fn entry() {
114 \\ _ = if(true) {} else if(true) {} else {};
115 \\ var good = {};
116 \\ _ = if(true) {} else if(true) {} else {}
117 \\ var bad = {};
118 \\}
119 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
120
121 cases.add("implicit semicolon - if(var) statement",
122 \\export fn entry() {
123 \\ if(_=foo()) {}
124 \\ var good = {};
125 \\ if(_=foo()) ({})
126 \\ var bad = {};
127 \\}
128 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
129
130 cases.add("implicit semicolon - if(var) expression",
131 \\export fn entry() {
132 \\ _ = if(_=foo()) {};
133 \\ var good = {};
134 \\ _ = if(_=foo()) {}
135 \\ var bad = {};
136 \\}
137 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
138
139 cases.add("implicit semicolon - if(var)-else statement",
140 \\export fn entry() {
141 \\ if(_=foo()) {} else {}
142 \\ var good = {};
143 \\ if(_=foo()) ({}) else ({})
144 \\ var bad = {};
145 \\}
146 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
147
148 cases.add("implicit semicolon - if(var)-else expression",
149 \\export fn entry() {
150 \\ _ = if(_=foo()) {} else {};
151 \\ var good = {};
152 \\ _ = if(_=foo()) {} else {}
153 \\ var bad = {};
154 \\}
155 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
156
157 cases.add("implicit semicolon - if(var)-else-if(var) statement",
158 \\export fn entry() {
159 \\ if(_=foo()) {} else if(_=foo()) {}
160 \\ var good = {};
161 \\ if(_=foo()) ({}) else if(_=foo()) ({})
162 \\ var bad = {};
163 \\}
164 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
165
166 cases.add("implicit semicolon - if(var)-else-if(var) expression",
167 \\export fn entry() {
168 \\ _ = if(_=foo()) {} else if(_=foo()) {};
169 \\ var good = {};
170 \\ _ = if(_=foo()) {} else if(_=foo()) {}
171 \\ var bad = {};
172 \\}
173 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
174
175 cases.add("implicit semicolon - if(var)-else-if(var)-else statement",
176 \\export fn entry() {
177 \\ if(_=foo()) {} else if(_=foo()) {} else {}
178 \\ var good = {};
179 \\ if(_=foo()) ({}) else if(_=foo()) ({}) else ({})
180 \\ var bad = {};
181 \\}
182 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
183
184 cases.add("implicit semicolon - if(var)-else-if(var)-else expression",
185 \\export fn entry() {
186 \\ _ = if(_=foo()) {} else if(_=foo()) {} else {};
187 \\ var good = {};
188 \\ _ = if(_=foo()) {} else if(_=foo()) {} else {}
189 \\ var bad = {};
190 \\}
191 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
192
193 cases.add("implicit semicolon - try statement",
194 \\export fn entry() {
195 \\ try (_ = foo()) {}
196 \\ var good = {};
197 \\ try (_ = foo()) ({})
198 \\ var bad = {};
199 \\}
200 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
201
202 cases.add("implicit semicolon - try expression",
203 \\export fn entry() {
204 \\ _ = try (_ = foo()) {};
205 \\ var good = {};
206 \\ _ = try (_ = foo()) {}
207 \\ var bad = {};
208 \\}
209 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
210
211 cases.add("implicit semicolon - while statement",
212 \\export fn entry() {
213 \\ while(true) {}
214 \\ var good = {};
215 \\ while(true) ({})
216 \\ var bad = {};
217 \\}
218 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
219
220 cases.add("implicit semicolon - while expression",
221 \\export fn entry() {
222 \\ _ = while(true) {};
223 \\ var good = {};
224 \\ _ = while(true) {}
225 \\ var bad = {};
226 \\}
227 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
228
229 cases.add("implicit semicolon - while-continue statement",
230 \\export fn entry() {
231 \\ while(true;{}) {}
232 \\ var good = {};
233 \\ while(true;{}) ({})
234 \\ var bad = {};
235 \\}
236 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
237
238 cases.add("implicit semicolon - while-continue expression",
239 \\export fn entry() {
240 \\ _ = while(true;{}) {};
241 \\ var good = {};
242 \\ _ = while(true;{}) {}
243 \\ var bad = {};
244 \\}
245 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
246
247 cases.add("implicit semicolon - for statement",
248 \\export fn entry() {
249 \\ for(foo()) {}
250 \\ var good = {};
251 \\ for(foo()) ({})
252 \\ var bad = {};
253 \\}
254 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
255
256 cases.add("implicit semicolon - for expression",
257 \\export fn entry() {
258 \\ _ = for(foo()) {};
259 \\ var good = {};
260 \\ _ = for(foo()) {}
261 \\ var bad = {};
262 \\}
263 , ".tmp_source.zig:5:5: error: invalid token: 'var'");
264
265 cases.add("multiple function definitions",
266 \\fn a() {}
267 \\fn a() {}
268 \\export fn entry() { a(); }
269 , ".tmp_source.zig:2:1: error: redefinition of 'a'");
270
271 cases.add("unreachable with return",
272 \\fn a() -> noreturn {return;}
273 \\export fn entry() { a(); }
274 , ".tmp_source.zig:1:21: error: expected type 'noreturn', found 'void'");
275
276 cases.add("control reaches end of non-void function",
277 \\fn a() -> i32 {}
278 \\export fn entry() { _ = a(); }
279 , ".tmp_source.zig:1:15: error: expected type 'i32', found 'void'");
280
281 cases.add("undefined function call",
282 \\export fn a() {
283 \\ b();
284 \\}
285 , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'");
286
287 cases.add("wrong number of arguments",
288 \\export fn a() {
289 \\ b(1);
290 \\}
291 \\fn b(a: i32, b: i32, c: i32) { }
292 , ".tmp_source.zig:2:6: error: expected 3 arguments, found 1");
293
294 cases.add("invalid type",
295 \\fn a() -> bogus {}
296 \\export fn entry() { _ = a(); }
297 , ".tmp_source.zig:1:11: error: use of undeclared identifier 'bogus'");
298
299 cases.add("pointer to unreachable",
300 \\fn a() -> &noreturn {}
301 \\export fn entry() { _ = a(); }
302 , ".tmp_source.zig:1:12: error: pointer to unreachable not allowed");
303
304 cases.add("unreachable code",
305 \\export fn a() {
306 \\ return;
307 \\ b();
308 \\}
309 \\
310 \\fn b() {}
311 , ".tmp_source.zig:3:6: error: unreachable code");
312
313 cases.add("bad import",
314 \\const bogus = @import("bogus-does-not-exist.zig");
315 \\export fn entry() { bogus.bogo(); }
316 , ".tmp_source.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'");
317
318 cases.add("undeclared identifier",
319 \\export fn a() {
320 \\ b +
321 \\ c
322 \\}
323 ,
324 ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'",
325 ".tmp_source.zig:3:5: error: use of undeclared identifier 'c'");
326
327 cases.add("parameter redeclaration",
328 \\fn f(a : i32, a : i32) {
329 \\}
330 \\export fn entry() { f(1, 2); }
331 , ".tmp_source.zig:1:15: error: redeclaration of variable 'a'");
332
333 cases.add("local variable redeclaration",
334 \\export fn f() {
335 \\ const a : i32 = 0;
336 \\ const a = 0;
337 \\}
338 , ".tmp_source.zig:3:5: error: redeclaration of variable 'a'");
339
340 cases.add("local variable redeclares parameter",
341 \\fn f(a : i32) {
342 \\ const a = 0;
343 \\}
344 \\export fn entry() { f(1); }
345 , ".tmp_source.zig:2:5: error: redeclaration of variable 'a'");
346
347 cases.add("variable has wrong type",
348 \\export fn f() -> i32 {
349 \\ const a = c"a";
350 \\ a
351 \\}
352 , ".tmp_source.zig:3:5: error: expected type 'i32', found '&const u8'");
353
354 cases.add("if condition is bool, not int",
355 \\export fn f() {
356 \\ if (0) {}
357 \\}
358 , ".tmp_source.zig:2:9: error: integer value 0 cannot be implicitly casted to type 'bool'");
359
360 cases.add("assign unreachable",
361 \\export fn f() {
362 \\ const a = return;
363 \\}
364 , ".tmp_source.zig:2:5: error: unreachable code");
365
366 cases.add("unreachable variable",
367 \\export fn f() {
368 \\ const a: noreturn = {};
369 \\}
370 , ".tmp_source.zig:2:14: error: variable of type 'noreturn' not allowed");
371
372 cases.add("unreachable parameter",
373 \\fn f(a: noreturn) {}
374 \\export fn entry() { f(); }
375 , ".tmp_source.zig:1:9: error: parameter of type 'noreturn' not allowed");
376
377 cases.add("bad assignment target",
378 \\export fn f() {
379 \\ 3 = 3;
380 \\}
381 , ".tmp_source.zig:2:7: error: cannot assign to constant");
382
383 cases.add("assign to constant variable",
384 \\export fn f() {
385 \\ const a = 3;
386 \\ a = 4;
387 \\}
388 , ".tmp_source.zig:3:7: error: cannot assign to constant");
389
390 cases.add("use of undeclared identifier",
391 \\export fn f() {
392 \\ b = 3;
393 \\}
394 , ".tmp_source.zig:2:5: error: use of undeclared identifier 'b'");
395
396 cases.add("const is a statement, not an expression",
397 \\export fn f() {
398 \\ (const a = 0);
399 \\}
400 , ".tmp_source.zig:2:6: error: invalid token: 'const'");
401
402 cases.add("array access of undeclared identifier",
403 \\export fn f() {
404 \\ i[i] = i[i];
405 \\}
406 , ".tmp_source.zig:2:5: error: use of undeclared identifier 'i'",
407 ".tmp_source.zig:2:12: error: use of undeclared identifier 'i'");
408
409 cases.add("array access of non array",
410 \\export fn f() {
411 \\ var bad : bool = undefined;
412 \\ bad[bad] = bad[bad];
413 \\}
414 , ".tmp_source.zig:3:8: error: array access of non-array type 'bool'",
415 ".tmp_source.zig:3:19: error: array access of non-array type 'bool'");
416
417 cases.add("array access with non integer index",
418 \\export fn f() {
419 \\ var array = "aoeu";
420 \\ var bad = false;
421 \\ array[bad] = array[bad];
422 \\}
423 , ".tmp_source.zig:4:11: error: expected type 'usize', found 'bool'",
424 ".tmp_source.zig:4:24: error: expected type 'usize', found 'bool'");
425
426 cases.add("write to const global variable",
427 \\const x : i32 = 99;
428 \\fn f() {
429 \\ x = 1;
430 \\}
431 \\export fn entry() { f(); }
432 , ".tmp_source.zig:3:7: error: cannot assign to constant");
433
434
435 cases.add("missing else clause",
436 \\fn f(b: bool) {
437 \\ const x : i32 = if (b) { 1 };
438 \\ const y = if (b) { i32(1) };
439 \\}
440 \\export fn entry() { f(true); }
441 , ".tmp_source.zig:2:30: error: integer value 1 cannot be implicitly casted to type 'void'",
442 ".tmp_source.zig:3:15: error: incompatible types: 'i32' and 'void'");
443
444 cases.add("direct struct loop",
445 \\const A = struct { a : A, };
446 \\export fn entry() -> usize { @sizeOf(A) }
447 , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
448
449 cases.add("indirect struct loop",
450 \\const A = struct { b : B, };
451 \\const B = struct { c : C, };
452 \\const C = struct { a : A, };
453 \\export fn entry() -> usize { @sizeOf(A) }
454 , ".tmp_source.zig:1:11: error: struct 'A' contains itself");
455
456 cases.add("invalid struct field",
457 \\const A = struct { x : i32, };
458 \\export fn f() {
459 \\ var a : A = undefined;
460 \\ a.foo = 1;
461 \\ const y = a.bar;
462 \\}
463 ,
464 ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'",
465 ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'");
466
467 cases.add("redefinition of struct",
468 \\const A = struct { x : i32, };
469 \\const A = struct { y : i32, };
470 , ".tmp_source.zig:2:1: error: redefinition of 'A'");
471
472 cases.add("redefinition of enums",
473 \\const A = enum {};
474 \\const A = enum {};
475 , ".tmp_source.zig:2:1: error: redefinition of 'A'");
476
477 cases.add("redefinition of global variables",
478 \\var a : i32 = 1;
479 \\var a : i32 = 2;
480 ,
481 ".tmp_source.zig:2:1: error: redefinition of 'a'",
482 ".tmp_source.zig:1:1: note: previous definition is here");
483
484 cases.add("byvalue struct parameter in exported function",
485 \\const A = struct { x : i32, };
486 \\export fn f(a : A) {}
487 , ".tmp_source.zig:2:13: error: byvalue types not yet supported on extern function parameters");
488
489 cases.add("byvalue struct return value in exported function",
490 \\const A = struct { x: i32, };
491 \\export fn f() -> A {
492 \\ A {.x = 1234 }
493 \\}
494 , ".tmp_source.zig:2:18: error: byvalue types not yet supported on extern function return values");
495
496 cases.add("duplicate field in struct value expression",
497 \\const A = struct {
498 \\ x : i32,
499 \\ y : i32,
500 \\ z : i32,
501 \\};
502 \\export fn f() {
503 \\ const a = A {
504 \\ .z = 1,
505 \\ .y = 2,
506 \\ .x = 3,
507 \\ .z = 4,
508 \\ };
509 \\}
510 , ".tmp_source.zig:11:9: error: duplicate field");
511
512 cases.add("missing field in struct value expression",
513 \\const A = struct {
514 \\ x : i32,
515 \\ y : i32,
516 \\ z : i32,
517 \\};
518 \\export fn f() {
519 \\ // we want the error on the '{' not the 'A' because
520 \\ // the A could be a complicated expression
521 \\ const a = A {
522 \\ .z = 4,
523 \\ .y = 2,
524 \\ };
525 \\}
526 , ".tmp_source.zig:9:17: error: missing field: 'x'");
527
528 cases.add("invalid field in struct value expression",
529 \\const A = struct {
530 \\ x : i32,
531 \\ y : i32,
532 \\ z : i32,
533 \\};
534 \\export fn f() {
535 \\ const a = A {
536 \\ .z = 4,
537 \\ .y = 2,
538 \\ .foo = 42,
539 \\ };
540 \\}
541 , ".tmp_source.zig:10:9: error: no member named 'foo' in 'A'");
542
543 cases.add("invalid break expression",
544 \\export fn f() {
545 \\ break;
546 \\}
547 , ".tmp_source.zig:2:5: error: 'break' expression outside loop");
548
549 cases.add("invalid continue expression",
550 \\export fn f() {
551 \\ continue;
552 \\}
553 , ".tmp_source.zig:2:5: error: 'continue' expression outside loop");
554
555 cases.add("invalid maybe type",
556 \\export fn f() {
557 \\ if (const x ?= true) { }
558 \\}
559 , ".tmp_source.zig:2:20: error: expected nullable type, found 'bool'");
560
561 cases.add("cast unreachable",
562 \\fn f() -> i32 {
563 \\ i32(return 1)
564 \\}
565 \\export fn entry() { _ = f(); }
566 , ".tmp_source.zig:2:8: error: unreachable code");
567
568 cases.add("invalid builtin fn",
569 \\fn f() -> @bogus(foo) {
570 \\}
571 \\export fn entry() { _ = f(); }
572 , ".tmp_source.zig:1:11: error: invalid builtin function: 'bogus'");
573
574 cases.add("top level decl dependency loop",
575 \\const a : @typeOf(b) = 0;
576 \\const b : @typeOf(a) = 0;
577 \\export fn entry() {
578 \\ const c = a + b;
579 \\}
580 , ".tmp_source.zig:1:1: error: 'a' depends on itself");
581
582 cases.add("noalias on non pointer param",
583 \\fn f(noalias x: i32) {}
584 \\export fn entry() { f(1234); }
585 , ".tmp_source.zig:1:6: error: noalias on non-pointer parameter");
586
587 cases.add("struct init syntax for array",
588 \\const foo = []u16{.x = 1024,};
589 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
590 , ".tmp_source.zig:1:18: error: type '[]u16' does not support struct initialization syntax");
591
592 cases.add("type variables must be constant",
593 \\var foo = u8;
594 \\export fn entry() -> foo {
595 \\ return 1;
596 \\}
597 , ".tmp_source.zig:1:1: error: variable of type 'type' must be constant");
598
599
600 cases.add("variables shadowing types",
601 \\const Foo = struct {};
602 \\const Bar = struct {};
603 \\
604 \\fn f(Foo: i32) {
605 \\ var Bar : i32 = undefined;
606 \\}
607 \\
608 \\export fn entry() {
609 \\ f(1234);
610 \\}
611 ,
612 ".tmp_source.zig:4:6: error: redefinition of 'Foo'",
613 ".tmp_source.zig:1:1: note: previous definition is here",
614 ".tmp_source.zig:5:5: error: redefinition of 'Bar'",
615 ".tmp_source.zig:2:1: note: previous definition is here");
616
617 cases.add("multiple else prongs in a switch",
618 \\fn f(x: u32) {
619 \\ const value: bool = switch (x) {
620 \\ 1234 => false,
621 \\ else => true,
622 \\ else => true,
623 \\ };
624 \\}
625 \\export fn entry() {
626 \\ f(1234);
627 \\}
628 , ".tmp_source.zig:5:9: error: multiple else prongs in switch expression");
629
630 cases.add("global variable initializer must be constant expression",
631 \\extern fn foo() -> i32;
632 \\const x = foo();
633 \\export fn entry() -> i32 { x }
634 , ".tmp_source.zig:2:11: error: unable to evaluate constant expression");
635
636 cases.add("array concatenation with wrong type",
637 \\const src = "aoeu";
638 \\const derp = usize(1234);
639 \\const a = derp ++ "foo";
640 \\
641 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
642 , ".tmp_source.zig:3:11: error: expected array or C string literal, found 'usize'");
643
644 cases.add("non compile time array concatenation",
645 \\fn f() -> []u8 {
646 \\ s ++ "foo"
647 \\}
648 \\var s: [10]u8 = undefined;
649 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
650 , ".tmp_source.zig:2:5: error: unable to evaluate constant expression");
651
652 cases.add("@cImport with bogus include",
653 \\const c = @cImport(@cInclude("bogus.h"));
654 \\export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) }
655 , ".tmp_source.zig:1:11: error: C import failed",
656 ".h:1:10: note: 'bogus.h' file not found");
657
658 cases.add("address of number literal",
659 \\const x = 3;
660 \\const y = &x;
661 \\fn foo() -> &const i32 { y }
662 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
663 , ".tmp_source.zig:3:26: error: expected type '&const i32', found '&const (integer literal)'");
664
665 cases.add("integer overflow error",
666 \\const x : u8 = 300;
667 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
668 , ".tmp_source.zig:1:16: error: integer value 300 cannot be implicitly casted to type 'u8'");
669
670 cases.add("incompatible number literals",
671 \\const x = 2 == 2.0;
672 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
673 , ".tmp_source.zig:1:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'");
674
675 cases.add("missing function call param",
676 \\const Foo = struct {
677 \\ a: i32,
678 \\ b: i32,
679 \\
680 \\ fn member_a(foo: &const Foo) -> i32 {
681 \\ return foo.a;
682 \\ }
683 \\ fn member_b(foo: &const Foo) -> i32 {
684 \\ return foo.b;
685 \\ }
686 \\};
687 \\
688 \\const member_fn_type = @typeOf(Foo.member_a);
689 \\const members = []member_fn_type {
690 \\ Foo.member_a,
691 \\ Foo.member_b,
692 \\};
693 \\
694 \\fn f(foo: &const Foo, index: usize) {
695 \\ const result = members[index]();
696 \\}
697 \\
698 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
699 , ".tmp_source.zig:20:34: error: expected 1 arguments, found 0");
700
701 cases.add("missing function name and param name",
702 \\fn () {}
703 \\fn f(i32) {}
704 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
705 ,
706 ".tmp_source.zig:1:1: error: missing function name",
707 ".tmp_source.zig:2:6: error: missing parameter name");
708
709 cases.add("wrong function type",
710 \\const fns = []fn(){ a, b, c };
711 \\fn a() -> i32 {0}
712 \\fn b() -> i32 {1}
713 \\fn c() -> i32 {2}
714 \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
715 , ".tmp_source.zig:1:21: error: expected type 'fn()', found 'fn() -> i32'");
716
717 cases.add("extern function pointer mismatch",
718 \\const fns = [](fn(i32)->i32){ a, b, c };
719 \\pub fn a(x: i32) -> i32 {x + 0}
720 \\pub fn b(x: i32) -> i32 {x + 1}
721 \\export fn c(x: i32) -> i32 {x + 2}
722 \\
723 \\export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
724 , ".tmp_source.zig:1:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'");
725
726
727 cases.add("implicit cast from f64 to f32",
728 \\const x : f64 = 1.0;
729 \\const y : f32 = x;
730 \\
731 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
732 , ".tmp_source.zig:2:17: error: expected type 'f32', found 'f64'");
733
734
735 cases.add("colliding invalid top level functions",
736 \\fn func() -> bogus {}
737 \\fn func() -> bogus {}
738 \\export fn entry() -> usize { @sizeOf(@typeOf(func)) }
739 ,
740 ".tmp_source.zig:2:1: error: redefinition of 'func'",
741 ".tmp_source.zig:1:14: error: use of undeclared identifier 'bogus'");
742
743
744 cases.add("bogus compile var",
745 \\const x = @compileVar("bogus");
746 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
747 , ".tmp_source.zig:1:23: error: unrecognized compile variable: 'bogus'");
748
749
750 cases.add("non constant expression in array size outside function",
751 \\const Foo = struct {
752 \\ y: [get()]u8,
753 \\};
754 \\var global_var: usize = 1;
755 \\fn get() -> usize { global_var }
756 \\
757 \\export fn entry() -> usize { @sizeOf(@typeOf(Foo)) }
758 ,
759 ".tmp_source.zig:5:21: error: unable to evaluate constant expression",
760 ".tmp_source.zig:2:12: note: called from here",
761 ".tmp_source.zig:2:8: note: called from here");
762
763
764 cases.add("addition with non numbers",
765 \\const Foo = struct {
766 \\ field: i32,
767 \\};
768 \\const x = Foo {.field = 1} + Foo {.field = 2};
769 \\
770 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
771 , ".tmp_source.zig:4:28: error: invalid operands to binary expression: 'Foo' and 'Foo'");
772
773
774 cases.add("division by zero",
775 \\const lit_int_x = 1 / 0;
776 \\const lit_float_x = 1.0 / 0.0;
777 \\const int_x = i32(1) / i32(0);
778 \\const float_x = f32(1.0) / f32(0.0);
779 \\
780 \\export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) }
781 \\export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) }
782 \\export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) }
783 \\export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) }
784 ,
785 ".tmp_source.zig:1:21: error: division by zero is undefined",
786 ".tmp_source.zig:2:25: error: division by zero is undefined",
787 ".tmp_source.zig:3:22: error: division by zero is undefined",
788 ".tmp_source.zig:4:26: error: division by zero is undefined");
789
790
791 cases.add("missing switch prong",
792 \\const Number = enum {
793 \\ One,
794 \\ Two,
795 \\ Three,
796 \\ Four,
797 \\};
798 \\fn f(n: Number) -> i32 {
799 \\ switch (n) {
800 \\ Number.One => 1,
801 \\ Number.Two => 2,
802 \\ Number.Three => i32(3),
803 \\ }
804 \\}
805 \\
806 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
807 , ".tmp_source.zig:8:5: error: enumeration value 'Number.Four' not handled in switch");
808
809 cases.add("normal string with newline",
810 \\const foo = "a
811 \\b";
812 \\
813 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
814 , ".tmp_source.zig:1:13: error: newline not allowed in string literal");
815
816 cases.add("invalid comparison for function pointers",
817 \\fn foo() {}
818 \\const invalid = foo > foo;
819 \\
820 \\export fn entry() -> usize { @sizeOf(@typeOf(invalid)) }
821 , ".tmp_source.zig:2:21: error: operator not allowed for type 'fn()'");
822
823 cases.add("generic function instance with non-constant expression",
824 \\fn foo(comptime x: i32, y: i32) -> i32 { return x + y; }
825 \\fn test1(a: i32, b: i32) -> i32 {
826 \\ return foo(a, b);
827 \\}
828 \\
829 \\export fn entry() -> usize { @sizeOf(@typeOf(test1)) }
830 , ".tmp_source.zig:3:16: error: unable to evaluate constant expression");
831
832 cases.add("goto jumping into block",
833 \\export fn f() {
834 \\ {
835 \\a_label:
836 \\ }
837 \\ goto a_label;
838 \\}
839 , ".tmp_source.zig:5:5: error: no label in scope named 'a_label'");
840
841 cases.add("goto jumping past a defer",
842 \\fn f(b: bool) {
843 \\ if (b) goto label;
844 \\ defer derp();
845 \\label:
846 \\}
847 \\fn derp(){}
848 \\
849 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
850 , ".tmp_source.zig:2:12: error: no label in scope named 'label'");
851
852 cases.add("assign null to non-nullable pointer",
853 \\const a: &u8 = null;
854 \\
855 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
856 , ".tmp_source.zig:1:16: error: expected type '&u8', found '(null)'");
857
858 cases.add("indexing an array of size zero",
859 \\const array = []u8{};
860 \\export fn foo() {
861 \\ const pointer = &array[0];
862 \\}
863 , ".tmp_source.zig:3:27: error: index 0 outside array of size 0");
864
865 cases.add("compile time division by zero",
866 \\const y = foo(0);
867 \\fn foo(x: i32) -> i32 {
868 \\ 1 / x
869 \\}
870 \\
871 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
872 ,
873 ".tmp_source.zig:3:7: error: division by zero is undefined",
874 ".tmp_source.zig:1:14: note: called from here");
875
876 cases.add("branch on undefined value",
877 \\const x = if (undefined) true else false;
878 \\
879 \\export fn entry() -> usize { @sizeOf(@typeOf(x)) }
880 , ".tmp_source.zig:1:15: error: use of undefined value");
881
882
883 cases.add("endless loop in function evaluation",
884 \\const seventh_fib_number = fibbonaci(7);
885 \\fn fibbonaci(x: i32) -> i32 {
886 \\ return fibbonaci(x - 1) + fibbonaci(x - 2);
887 \\}
888 \\
889 \\export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) }
890 ,
891 ".tmp_source.zig:3:21: error: evaluation exceeded 1000 backwards branches",
892 ".tmp_source.zig:3:21: note: called from here");
893
894 cases.add("@embedFile with bogus file",
895 \\const resource = @embedFile("bogus.txt");
896 \\
897 \\export fn entry() -> usize { @sizeOf(@typeOf(resource)) }
898 , ".tmp_source.zig:1:29: error: unable to find '", "/bogus.txt'");
899
900 cases.add("non-const expression in struct literal outside function",
901 \\const Foo = struct {
902 \\ x: i32,
903 \\};
904 \\const a = Foo {.x = get_it()};
905 \\extern fn get_it() -> i32;
906 \\
907 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
908 , ".tmp_source.zig:4:21: error: unable to evaluate constant expression");
909
910 cases.add("non-const expression function call with struct return value outside function",
911 \\const Foo = struct {
912 \\ x: i32,
913 \\};
914 \\const a = get_it();
915 \\fn get_it() -> Foo {
916 \\ global_side_effect = true;
917 \\ Foo {.x = 13}
918 \\}
919 \\var global_side_effect = false;
920 \\
921 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
922 ,
923 ".tmp_source.zig:6:24: error: unable to evaluate constant expression",
924 ".tmp_source.zig:4:17: note: called from here");
925
926 cases.add("undeclared identifier error should mark fn as impure",
927 \\export fn foo() {
928 \\ test_a_thing();
929 \\}
930 \\fn test_a_thing() {
931 \\ bad_fn_call();
932 \\}
933 , ".tmp_source.zig:5:5: error: use of undeclared identifier 'bad_fn_call'");
934
935 cases.add("illegal comparison of types",
936 \\fn bad_eql_1(a: []u8, b: []u8) -> bool {
937 \\ a == b
938 \\}
939 \\const EnumWithData = enum {
940 \\ One,
941 \\ Two: i32,
942 \\};
943 \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
944 \\ *a == *b
945 \\}
946 \\
947 \\export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) }
948 \\export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) }
949 ,
950 ".tmp_source.zig:2:7: error: operator not allowed for type '[]u8'",
951 ".tmp_source.zig:9:8: error: operator not allowed for type 'EnumWithData'");
952
953 cases.add("non-const switch number literal",
954 \\export fn foo() {
955 \\ const x = switch (bar()) {
956 \\ 1, 2 => 1,
957 \\ 3, 4 => 2,
958 \\ else => 3,
959 \\ };
960 \\}
961 \\fn bar() -> i32 {
962 \\ 2
963 \\}
964 , ".tmp_source.zig:2:15: error: unable to infer expression type");
965
966 cases.add("atomic orderings of cmpxchg - failure stricter than success",
967 \\export fn f() {
968 \\ var x: i32 = 1234;
969 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
970 \\}
971 , ".tmp_source.zig:3:72: error: failure atomic ordering must be no stricter than success");
972
973 cases.add("atomic orderings of cmpxchg - success Monotonic or stricter",
974 \\export fn f() {
975 \\ var x: i32 = 1234;
976 \\ while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
977 \\}
978 , ".tmp_source.zig:3:49: error: success atomic ordering must be Monotonic or stricter");
979
980 cases.add("negation overflow in function evaluation",
981 \\const y = neg(-128);
982 \\fn neg(x: i8) -> i8 {
983 \\ -x
984 \\}
985 \\
986 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
987 ,
988 ".tmp_source.zig:3:5: error: negation caused overflow",
989 ".tmp_source.zig:1:14: note: called from here");
990
991 cases.add("add overflow in function evaluation",
992 \\const y = add(65530, 10);
993 \\fn add(a: u16, b: u16) -> u16 {
994 \\ a + b
995 \\}
996 \\
997 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
998 ,
999 ".tmp_source.zig:3:7: error: operation caused overflow",
1000 ".tmp_source.zig:1:14: note: called from here");
1001
1002
1003 cases.add("sub overflow in function evaluation",
1004 \\const y = sub(10, 20);
1005 \\fn sub(a: u16, b: u16) -> u16 {
1006 \\ a - b
1007 \\}
1008 \\
1009 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1010 ,
1011 ".tmp_source.zig:3:7: error: operation caused overflow",
1012 ".tmp_source.zig:1:14: note: called from here");
1013
1014 cases.add("mul overflow in function evaluation",
1015 \\const y = mul(300, 6000);
1016 \\fn mul(a: u16, b: u16) -> u16 {
1017 \\ a * b
1018 \\}
1019 \\
1020 \\export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1021 ,
1022 ".tmp_source.zig:3:7: error: operation caused overflow",
1023 ".tmp_source.zig:1:14: note: called from here");
1024
1025 cases.add("truncate sign mismatch",
1026 \\fn f() -> i8 {
1027 \\ const x: u32 = 10;
1028 \\ @truncate(i8, x)
1029 \\}
1030 \\
1031 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1032 , ".tmp_source.zig:3:19: error: expected signed integer type, found 'u32'");
1033
1034 cases.add("%return in function with non error return type",
1035 \\export fn f() {
1036 \\ %return something();
1037 \\}
1038 \\fn something() -> %void { }
1039 ,
1040 ".tmp_source.zig:2:5: error: expected type 'void', found 'error'");
1041
1042 cases.add("wrong return type for main",
1043 \\pub fn main() { }
1044 , ".tmp_source.zig:1:15: error: expected return type of main to be '%void', instead is 'void'");
1045
1046 cases.add("double ?? on main return value",
1047 \\pub fn main() -> ??void {
1048 \\}
1049 , ".tmp_source.zig:1:18: error: expected return type of main to be '%void', instead is '??void'");
1050
1051 cases.add("invalid pointer for var type",
1052 \\extern fn ext() -> usize;
1053 \\var bytes: [ext()]u8 = undefined;
1054 \\export fn f() {
1055 \\ for (bytes) |*b, i| {
1056 \\ *b = u8(i);
1057 \\ }
1058 \\}
1059 , ".tmp_source.zig:2:13: error: unable to evaluate constant expression");
1060
1061 cases.add("export function with comptime parameter",
1062 \\export fn foo(comptime x: i32, y: i32) -> i32{
1063 \\ x + y
1064 \\}
1065 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function");
1066
1067 cases.add("extern function with comptime parameter",
1068 \\extern fn foo(comptime x: i32, y: i32) -> i32;
1069 \\fn f() -> i32 {
1070 \\ foo(1, 2)
1071 \\}
1072 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1073 , ".tmp_source.zig:1:15: error: comptime parameter not allowed in extern function");
1074
1075 cases.add("convert fixed size array to slice with invalid size",
1076 \\export fn f() {
1077 \\ var array: [5]u8 = undefined;
1078 \\ var foo = ([]const u32)(array)[0];
1079 \\}
1080 , ".tmp_source.zig:3:28: error: unable to convert [5]u8 to []const u32: size mismatch");
1081
1082 cases.add("non-pure function returns type",
1083 \\var a: u32 = 0;
1084 \\pub fn List(comptime T: type) -> type {
1085 \\ a += 1;
1086 \\ SmallList(T, 8)
1087 \\}
1088 \\
1089 \\pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
1090 \\ struct {
1091 \\ items: []T,
1092 \\ length: usize,
1093 \\ prealloc_items: [STATIC_SIZE]T,
1094 \\ }
1095 \\}
1096 \\
1097 \\export fn function_with_return_type_type() {
1098 \\ var list: List(i32) = undefined;
1099 \\ list.length = 10;
1100 \\}
1101 , ".tmp_source.zig:3:7: error: unable to evaluate constant expression",
1102 ".tmp_source.zig:16:19: note: called from here");
1103
1104 cases.add("bogus method call on slice",
1105 \\var self = "aoeu";
1106 \\fn f(m: []const u8) {
1107 \\ m.copy(u8, self[0...], m);
1108 \\}
1109 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1110 , ".tmp_source.zig:3:6: error: no member named 'copy' in '[]const u8'");
1111
1112 cases.add("wrong number of arguments for method fn call",
1113 \\const Foo = struct {
1114 \\ fn method(self: &const Foo, a: i32) {}
1115 \\};
1116 \\fn f(foo: &const Foo) {
1117 \\
1118 \\ foo.method(1, 2);
1119 \\}
1120 \\export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1121 , ".tmp_source.zig:6:15: error: expected 2 arguments, found 3");
1122
1123 cases.add("assign through constant pointer",
1124 \\export fn f() {
1125 \\ var cstr = c"Hat";
1126 \\ cstr[0] = 'W';
1127 \\}
1128 , ".tmp_source.zig:3:11: error: cannot assign to constant");
1129
1130 cases.add("assign through constant slice",
1131 \\export fn f() {
1132 \\ var cstr: []const u8 = "Hat";
1133 \\ cstr[0] = 'W';
1134 \\}
1135 , ".tmp_source.zig:3:11: error: cannot assign to constant");
1136
1137 cases.add("main function with bogus args type",
1138 \\pub fn main(args: [][]bogus) -> %void {}
1139 , ".tmp_source.zig:1:23: error: use of undeclared identifier 'bogus'");
1140
1141 cases.add("for loop missing element param",
1142 \\fn foo(blah: []u8) {
1143 \\ for (blah) { }
1144 \\}
1145 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1146 , ".tmp_source.zig:2:5: error: for loop expression missing element parameter");
1147
1148 cases.add("misspelled type with pointer only reference",
1149 \\const JasonHM = u8;
1150 \\const JasonList = &JsonNode;
1151 \\
1152 \\const JsonOA = enum {
1153 \\ JSONArray: JsonList,
1154 \\ JSONObject: JasonHM,
1155 \\};
1156 \\
1157 \\const JsonType = enum {
1158 \\ JSONNull: void,
1159 \\ JSONInteger: isize,
1160 \\ JSONDouble: f64,
1161 \\ JSONBool: bool,
1162 \\ JSONString: []u8,
1163 \\ JSONArray,
1164 \\ JSONObject,
1165 \\};
1166 \\
1167 \\pub const JsonNode = struct {
1168 \\ kind: JsonType,
1169 \\ jobject: ?JsonOA,
1170 \\};
1171 \\
1172 \\fn foo() {
1173 \\ var jll: JasonList = undefined;
1174 \\ jll.init(1234);
1175 \\ var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} };
1176 \\}
1177 \\
1178 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1179 , ".tmp_source.zig:5:16: error: use of undeclared identifier 'JsonList'");
1180
1181 cases.add("method call with first arg type primitive",
1182 \\const Foo = struct {
1183 \\ x: i32,
1184 \\
1185 \\ fn init(x: i32) -> Foo {
1186 \\ Foo {
1187 \\ .x = x,
1188 \\ }
1189 \\ }
1190 \\};
1191 \\
1192 \\export fn f() {
1193 \\ const derp = Foo.init(3);
1194 \\
1195 \\ derp.init();
1196 \\}
1197 , ".tmp_source.zig:14:5: error: expected type 'i32', found '&const Foo'");
1198
1199 cases.add("method call with first arg type wrong container",
1200 \\pub const List = struct {
1201 \\ len: usize,
1202 \\ allocator: &Allocator,
1203 \\
1204 \\ pub fn init(allocator: &Allocator) -> List {
1205 \\ List {
1206 \\ .len = 0,
1207 \\ .allocator = allocator,
1208 \\ }
1209 \\ }
1210 \\};
1211 \\
1212 \\pub var global_allocator = Allocator {
1213 \\ .field = 1234,
1214 \\};
1215 \\
1216 \\pub const Allocator = struct {
1217 \\ field: i32,
1218 \\};
1219 \\
1220 \\export fn foo() {
1221 \\ var x = List.init(&global_allocator);
1222 \\ x.init();
1223 \\}
1224 , ".tmp_source.zig:23:5: error: expected type '&Allocator', found '&List'");
1225
1226 cases.add("binary not on number literal",
1227 \\const TINY_QUANTUM_SHIFT = 4;
1228 \\const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
1229 \\var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
1230 \\
1231 \\export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) }
1232 , ".tmp_source.zig:3:60: error: unable to perform binary not operation on type '(integer literal)'");
1233
1234 cases.addCase({
1235 const tc = cases.create("multiple files with private function error",
1236 \\const foo = @import("foo.zig");
1237 \\
1238 \\export fn callPrivFunction() {
1239 \\ foo.privateFunction();
1240 \\}
1241 ,
1242 ".tmp_source.zig:4:8: error: 'privateFunction' is private",
1243 "foo.zig:1:1: note: declared here");
1244
1245 tc.addSourceFile("foo.zig",
1246 \\fn privateFunction() { }
1247 );
1248
1249 tc
1250 });
1251
1252 cases.add("container init with non-type",
1253 \\const zero: i32 = 0;
1254 \\const a = zero{1};
1255 \\
1256 \\export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1257 , ".tmp_source.zig:2:11: error: expected type, found 'i32'");
1258
1259 cases.add("assign to constant field",
1260 \\const Foo = struct {
1261 \\ field: i32,
1262 \\};
1263 \\export fn derp() {
1264 \\ const f = Foo {.field = 1234,};
1265 \\ f.field = 0;
1266 \\}
1267 , ".tmp_source.zig:6:13: error: cannot assign to constant");
1268
1269 cases.add("return from defer expression",
1270 \\pub fn testTrickyDefer() -> %void {
1271 \\ defer canFail() %% {};
1272 \\
1273 \\ defer %return canFail();
1274 \\
1275 \\ const a = maybeInt() ?? return;
1276 \\}
1277 \\
1278 \\fn canFail() -> %void { }
1279 \\
1280 \\pub fn maybeInt() -> ?i32 {
1281 \\ return 0;
1282 \\}
1283 \\
1284 \\export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) }
1285 , ".tmp_source.zig:4:11: error: cannot return from defer expression");
1286
1287 cases.add("attempt to access var args out of bounds",
1288 \\fn add(args: ...) -> i32 {
1289 \\ args[0] + args[1]
1290 \\}
1291 \\
1292 \\fn foo() -> i32 {
1293 \\ add(i32(1234))
1294 \\}
1295 \\
1296 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1297 ,
1298 ".tmp_source.zig:2:19: error: index 1 outside argument list of size 1",
1299 ".tmp_source.zig:6:8: note: called from here");
1300
1301 cases.add("pass integer literal to var args",
1302 \\fn add(args: ...) -> i32 {
1303 \\ var sum = i32(0);
1304 \\ {comptime var i: usize = 0; inline while (i < args.len; i += 1) {
1305 \\ sum += args[i];
1306 \\ }}
1307 \\ return sum;
1308 \\}
1309 \\
1310 \\fn bar() -> i32 {
1311 \\ add(1, 2, 3, 4)
1312 \\}
1313 \\
1314 \\export fn entry() -> usize { @sizeOf(@typeOf(bar)) }
1315 , ".tmp_source.zig:10:9: error: parameter of type '(integer literal)' requires comptime");
1316
1317 cases.add("assign too big number to u16",
1318 \\export fn foo() {
1319 \\ var vga_mem: u16 = 0xB8000;
1320 \\}
1321 , ".tmp_source.zig:2:24: error: integer value 753664 cannot be implicitly casted to type 'u16'");
1322
1323 cases.add("set global variable alignment to non power of 2",
1324 \\const some_data: [100]u8 = {
1325 \\ @setGlobalAlign(some_data, 3);
1326 \\ undefined
1327 \\};
1328 \\export fn entry() -> usize { @sizeOf(@typeOf(some_data)) }
1329 , ".tmp_source.zig:2:32: error: alignment value must be power of 2");
1330
1331 cases.add("compile log",
1332 \\export fn foo() {
1333 \\ comptime bar(12, "hi");
1334 \\}
1335 \\fn bar(a: i32, b: []const u8) {
1336 \\ @compileLog("begin");
1337 \\ @compileLog("a", a, "b", b);
1338 \\ @compileLog("end");
1339 \\}
1340 ,
1341 ".tmp_source.zig:5:5: error: found compile log statement",
1342 ".tmp_source.zig:2:17: note: called from here",
1343 ".tmp_source.zig:6:5: error: found compile log statement",
1344 ".tmp_source.zig:2:17: note: called from here",
1345 ".tmp_source.zig:7:5: error: found compile log statement",
1346 ".tmp_source.zig:2:17: note: called from here");
1347
1348 cases.add("casting bit offset pointer to regular pointer",
1349 \\const u2 = @IntType(false, 2);
1350 \\const u3 = @IntType(false, 3);
1351 \\
1352 \\const BitField = packed struct {
1353 \\ a: u3,
1354 \\ b: u3,
1355 \\ c: u2,
1356 \\};
1357 \\
1358 \\fn foo(bit_field: &const BitField) -> u3 {
1359 \\ return bar(&bit_field.b);
1360 \\}
1361 \\
1362 \\fn bar(x: &const u3) -> u3 {
1363 \\ return *x;
1364 \\}
1365 \\
1366 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1367 , ".tmp_source.zig:11:26: error: expected type '&const u3', found '&:3:6 const u3'");
1368
1369 cases.add("referring to a struct that is invalid",
1370 \\const UsbDeviceRequest = struct {
1371 \\ Type: u8,
1372 \\};
1373 \\
1374 \\export fn foo() {
1375 \\ comptime assert(@sizeOf(UsbDeviceRequest) == 0x8);
1376 \\}
1377 \\
1378 \\fn assert(ok: bool) {
1379 \\ if (!ok) unreachable;
1380 \\}
1381 ,
1382 ".tmp_source.zig:10:14: error: unable to evaluate constant expression",
1383 ".tmp_source.zig:6:20: note: called from here");
1384
1385 cases.add("control flow uses comptime var at runtime",
1386 \\export fn foo() {
1387 \\ comptime var i = 0;
1388 \\ while (i < 5; i += 1) {
1389 \\ bar();
1390 \\ }
1391 \\}
1392 \\
1393 \\fn bar() { }
1394 ,
1395 ".tmp_source.zig:3:5: error: control flow attempts to use compile-time variable at runtime",
1396 ".tmp_source.zig:3:21: note: compile-time variable assigned here");
1397
1398 cases.add("ignored return value",
1399 \\export fn foo() {
1400 \\ bar();
1401 \\}
1402 \\fn bar() -> i32 { 0 }
1403 , ".tmp_source.zig:2:8: error: return value ignored");
1404
1405 cases.add("integer literal on a non-comptime var",
1406 \\export fn foo() {
1407 \\ var i = 0;
1408 \\ while (i < 10; i += 1) { }
1409 \\}
1410 , ".tmp_source.zig:2:5: error: unable to infer variable type");
1411
1412 cases.add("undefined literal on a non-comptime var",
1413 \\export fn foo() {
1414 \\ var i = undefined;
1415 \\ i = i32(1);
1416 \\}
1417 , ".tmp_source.zig:2:5: error: unable to infer variable type");
1418
1419 cases.add("dereference an array",
1420 \\var s_buffer: [10]u8 = undefined;
1421 \\pub fn pass(in: []u8) -> []u8 {
1422 \\ var out = &s_buffer;
1423 \\ *out[0] = in[0];
1424 \\ return (*out)[0...1];
1425 \\}
1426 \\
1427 \\export fn entry() -> usize { @sizeOf(@typeOf(pass)) }
1428 , ".tmp_source.zig:4:5: error: attempt to dereference non pointer type '[10]u8'");
1429
1430 cases.add("pass const ptr to mutable ptr fn",
1431 \\fn foo() -> bool {
1432 \\ const a = ([]const u8)("a");
1433 \\ const b = &a;
1434 \\ return ptrEql(b, b);
1435 \\}
1436 \\fn ptrEql(a: &[]const u8, b: &[]const u8) -> bool {
1437 \\ return true;
1438 \\}
1439 \\
1440 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1441 , ".tmp_source.zig:4:19: error: expected type '&[]const u8', found '&const []const u8'");
1442
1443 cases.addCase({
1444 const tc = cases.create("export collision",
1445 \\const foo = @import("foo.zig");
1446 \\
1447 \\export fn bar() -> usize {
1448 \\ return foo.baz;
1449 \\}
1450 ,
1451 "foo.zig:1:8: error: exported symbol collision: 'bar'",
1452 ".tmp_source.zig:3:8: note: other symbol is here");
1453
1454 tc.addSourceFile("foo.zig",
1455 \\export fn bar() {}
1456 \\pub const baz = 1234;
1457 );
1458
1459 tc
1460 });
1461
1462 cases.add("pass non-copyable type by value to function",
1463 \\const Point = struct { x: i32, y: i32, };
1464 \\fn foo(p: Point) { }
1465 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1466 , ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value");
1467
1468 cases.add("implicit cast from array to mutable slice",
1469 \\var global_array: [10]i32 = undefined;
1470 \\fn foo(param: []i32) {}
1471 \\export fn entry() {
1472 \\ foo(global_array);
1473 \\}
1474 , ".tmp_source.zig:4:9: error: expected type '[]i32', found '[10]i32'");
1475
1476 cases.add("ptrcast to non-pointer",
1477 \\export fn entry(a: &i32) -> usize {
1478 \\ return @ptrcast(usize, a);
1479 \\}
1480 , ".tmp_source.zig:2:21: error: expected pointer, found 'usize'");
1481
1482 cases.add("too many error values to cast to small integer",
1483 \\error A; error B; error C; error D; error E; error F; error G; error H;
1484 \\const u2 = @IntType(false, 2);
1485 \\fn foo(e: error) -> u2 {
1486 \\ return u2(e);
1487 \\}
1488 \\export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1489 , ".tmp_source.zig:4:14: error: too many error values to fit in 'u2'");
1490
1491 cases.add("asm at compile time",
1492 \\comptime {
1493 \\ doSomeAsm();
1494 \\}
1495 \\
1496 \\fn doSomeAsm() {
1497 \\ asm volatile (
1498 \\ \\.globl aoeu;
1499 \\ \\.type aoeu, @function;
1500 \\ \\.set aoeu, derp;
1501 \\ );
1502 \\}
1503 , ".tmp_source.zig:6:5: error: unable to evaluate constant expression");
1504
1505 cases.add("invalid member of builtin enum",
1506 \\export fn entry() {
1507 \\ const foo = Arch.x86;
1508 \\}
1509 , ".tmp_source.zig:2:21: error: container 'Arch' has no member called 'x86'");
1510
1511 cases.add("int to ptr of 0 bits",
1512 \\export fn foo() {
1513 \\ var x: usize = 0x1000;
1514 \\ var y: &void = @intToPtr(&void, x);
1515 \\}
1516 , ".tmp_source.zig:3:31: error: type '&void' has 0 bits and cannot store information");
1517
1518 cases.add("@fieldParentPtr - non struct",
1519 \\const Foo = i32;
1520 \\export fn foo(a: &i32) -> &Foo {
1521 \\ return @fieldParentPtr(Foo, "a", a);
1522 \\}
1523 , ".tmp_source.zig:3:28: error: expected struct type, found 'i32'");
1524
1525 cases.add("@fieldParentPtr - bad field name",
1526 \\const Foo = struct {
1527 \\ derp: i32,
1528 \\};
1529 \\export fn foo(a: &i32) -> &Foo {
1530 \\ return @fieldParentPtr(Foo, "a", a);
1531 \\}
1532 , ".tmp_source.zig:5:33: error: struct 'Foo' has no field 'a'");
1533
1534 cases.add("@fieldParentPtr - field pointer is not pointer",
1535 \\const Foo = struct {
1536 \\ a: i32,
1537 \\};
1538 \\export fn foo(a: i32) -> &Foo {
1539 \\ return @fieldParentPtr(Foo, "a", a);
1540 \\}
1541 , ".tmp_source.zig:5:38: error: expected pointer, found 'i32'");
1542
1543 cases.add("@fieldParentPtr - comptime field ptr not based on struct",
1544 \\const Foo = struct {
1545 \\ a: i32,
1546 \\ b: i32,
1547 \\};
1548 \\const foo = Foo { .a = 1, .b = 2, };
1549 \\
1550 \\comptime {
1551 \\ const field_ptr = @intToPtr(&i32, 0x1234);
1552 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
1553 \\}
1554 , ".tmp_source.zig:9:55: error: pointer value not based on parent struct");
1555
1556 cases.add("@fieldParentPtr - comptime wrong field index",
1557 \\const Foo = struct {
1558 \\ a: i32,
1559 \\ b: i32,
1560 \\};
1561 \\const foo = Foo { .a = 1, .b = 2, };
1562 \\
1563 \\comptime {
1564 \\ const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
1565 \\}
1566 , ".tmp_source.zig:8:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'");
1567
1568 cases.addExe("missing main fn in executable",
1569 \\
1570 , "error: no member named 'main' in '");
1571
1572 cases.addExe("private main fn",
1573 \\fn main() {}
1574 ,
1575 "error: 'main' is private",
1576 ".tmp_source.zig:1:1: note: declared here");
1577}
test/debug_safety.zig created+234
...@@ -0,0 +1,234 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.CompareOutputContext) {
4 cases.addDebugSafety("calling panic",
5 \\pub fn panic(message: []const u8) -> noreturn {
6 \\ @breakpoint();
7 \\ while (true) {}
8 \\}
9 \\pub fn main() -> %void {
10 \\ @panic("oh no");
11 \\}
12 );
13
14 cases.addDebugSafety("out of bounds slice access",
15 \\pub fn panic(message: []const u8) -> noreturn {
16 \\ @breakpoint();
17 \\ while (true) {}
18 \\}
19 \\pub fn main() -> %void {
20 \\ const a = []i32{1, 2, 3, 4};
21 \\ baz(bar(a));
22 \\}
23 \\fn bar(a: []const i32) -> i32 {
24 \\ a[4]
25 \\}
26 \\fn baz(a: i32) { }
27 );
28
29 cases.addDebugSafety("integer addition overflow",
30 \\pub fn panic(message: []const u8) -> noreturn {
31 \\ @breakpoint();
32 \\ while (true) {}
33 \\}
34 \\error Whatever;
35 \\pub fn main() -> %void {
36 \\ const x = add(65530, 10);
37 \\ if (x == 0) return error.Whatever;
38 \\}
39 \\fn add(a: u16, b: u16) -> u16 {
40 \\ a + b
41 \\}
42 );
43
44 cases.addDebugSafety("integer subtraction overflow",
45 \\pub fn panic(message: []const u8) -> noreturn {
46 \\ @breakpoint();
47 \\ while (true) {}
48 \\}
49 \\error Whatever;
50 \\pub fn main() -> %void {
51 \\ const x = sub(10, 20);
52 \\ if (x == 0) return error.Whatever;
53 \\}
54 \\fn sub(a: u16, b: u16) -> u16 {
55 \\ a - b
56 \\}
57 );
58
59 cases.addDebugSafety("integer multiplication overflow",
60 \\pub fn panic(message: []const u8) -> noreturn {
61 \\ @breakpoint();
62 \\ while (true) {}
63 \\}
64 \\error Whatever;
65 \\pub fn main() -> %void {
66 \\ const x = mul(300, 6000);
67 \\ if (x == 0) return error.Whatever;
68 \\}
69 \\fn mul(a: u16, b: u16) -> u16 {
70 \\ a * b
71 \\}
72 );
73
74 cases.addDebugSafety("integer negation overflow",
75 \\pub fn panic(message: []const u8) -> noreturn {
76 \\ @breakpoint();
77 \\ while (true) {}
78 \\}
79 \\error Whatever;
80 \\pub fn main() -> %void {
81 \\ const x = neg(-32768);
82 \\ if (x == 32767) return error.Whatever;
83 \\}
84 \\fn neg(a: i16) -> i16 {
85 \\ -a
86 \\}
87 );
88
89 cases.addDebugSafety("signed integer division overflow",
90 \\pub fn panic(message: []const u8) -> noreturn {
91 \\ @breakpoint();
92 \\ while (true) {}
93 \\}
94 \\error Whatever;
95 \\pub fn main() -> %void {
96 \\ const x = div(-32768, -1);
97 \\ if (x == 32767) return error.Whatever;
98 \\}
99 \\fn div(a: i16, b: i16) -> i16 {
100 \\ a / b
101 \\}
102 );
103
104 cases.addDebugSafety("signed shift left overflow",
105 \\pub fn panic(message: []const u8) -> noreturn {
106 \\ @breakpoint();
107 \\ while (true) {}
108 \\}
109 \\error Whatever;
110 \\pub fn main() -> %void {
111 \\ const x = shl(-16385, 1);
112 \\ if (x == 0) return error.Whatever;
113 \\}
114 \\fn shl(a: i16, b: i16) -> i16 {
115 \\ a << b
116 \\}
117 );
118
119 cases.addDebugSafety("unsigned shift left overflow",
120 \\pub fn panic(message: []const u8) -> noreturn {
121 \\ @breakpoint();
122 \\ while (true) {}
123 \\}
124 \\error Whatever;
125 \\pub fn main() -> %void {
126 \\ const x = shl(0b0010111111111111, 3);
127 \\ if (x == 0) return error.Whatever;
128 \\}
129 \\fn shl(a: u16, b: u16) -> u16 {
130 \\ a << b
131 \\}
132 );
133
134 cases.addDebugSafety("integer division by zero",
135 \\pub fn panic(message: []const u8) -> noreturn {
136 \\ @breakpoint();
137 \\ while (true) {}
138 \\}
139 \\error Whatever;
140 \\pub fn main() -> %void {
141 \\ const x = div0(999, 0);
142 \\}
143 \\fn div0(a: i32, b: i32) -> i32 {
144 \\ a / b
145 \\}
146 );
147
148 cases.addDebugSafety("exact division failure",
149 \\pub fn panic(message: []const u8) -> noreturn {
150 \\ @breakpoint();
151 \\ while (true) {}
152 \\}
153 \\error Whatever;
154 \\pub fn main() -> %void {
155 \\ const x = divExact(10, 3);
156 \\ if (x == 0) return error.Whatever;
157 \\}
158 \\fn divExact(a: i32, b: i32) -> i32 {
159 \\ @divExact(a, b)
160 \\}
161 );
162
163 cases.addDebugSafety("cast []u8 to bigger slice of wrong size",
164 \\pub fn panic(message: []const u8) -> noreturn {
165 \\ @breakpoint();
166 \\ while (true) {}
167 \\}
168 \\error Whatever;
169 \\pub fn main() -> %void {
170 \\ const x = widenSlice([]u8{1, 2, 3, 4, 5});
171 \\ if (x.len == 0) return error.Whatever;
172 \\}
173 \\fn widenSlice(slice: []const u8) -> []const i32 {
174 \\ ([]const i32)(slice)
175 \\}
176 );
177
178 cases.addDebugSafety("value does not fit in shortening cast",
179 \\pub fn panic(message: []const u8) -> noreturn {
180 \\ @breakpoint();
181 \\ while (true) {}
182 \\}
183 \\error Whatever;
184 \\pub fn main() -> %void {
185 \\ const x = shorten_cast(200);
186 \\ if (x == 0) return error.Whatever;
187 \\}
188 \\fn shorten_cast(x: i32) -> i8 {
189 \\ i8(x)
190 \\}
191 );
192
193 cases.addDebugSafety("signed integer not fitting in cast to unsigned integer",
194 \\pub fn panic(message: []const u8) -> noreturn {
195 \\ @breakpoint();
196 \\ while (true) {}
197 \\}
198 \\error Whatever;
199 \\pub fn main() -> %void {
200 \\ const x = unsigned_cast(-10);
201 \\ if (x == 0) return error.Whatever;
202 \\}
203 \\fn unsigned_cast(x: i32) -> u32 {
204 \\ u32(x)
205 \\}
206 );
207
208 cases.addDebugSafety("unwrap error",
209 \\pub fn panic(message: []const u8) -> noreturn {
210 \\ @breakpoint();
211 \\ while (true) {}
212 \\}
213 \\error Whatever;
214 \\pub fn main() -> %void {
215 \\ %%bar();
216 \\}
217 \\fn bar() -> %void {
218 \\ return error.Whatever;
219 \\}
220 );
221
222 cases.addDebugSafety("cast integer to error and no code matches",
223 \\pub fn panic(message: []const u8) -> noreturn {
224 \\ @breakpoint();
225 \\ while (true) {}
226 \\}
227 \\pub fn main() -> %void {
228 \\ _ = bar(9999);
229 \\}
230 \\fn bar(x: u32) -> error {
231 \\ return error(x);
232 \\}
233 );
234}
test/parseh.zig created+243
...@@ -0,0 +1,243 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.ParseHContext) {
4 cases.addAllowWarnings("simple data types",
5 \\#include <stdint.h>
6 \\int foo(char a, unsigned char b, signed char c);
7 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
8 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
9 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
10 ,
11 \\pub extern fn foo(a: u8, b: u8, c: i8) -> c_int;
12 ,
13 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64);
14 ,
15 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64);
16 );
17
18 cases.add("noreturn attribute",
19 \\void foo(void) __attribute__((noreturn));
20 ,
21 \\pub extern fn foo() -> noreturn;
22 );
23
24 cases.add("enums",
25 \\enum Foo {
26 \\ FooA,
27 \\ FooB,
28 \\ Foo1,
29 \\};
30 ,
31 \\pub const enum_Foo = extern enum {
32 \\ A,
33 \\ B,
34 \\ @"1",
35 \\};
36 ,
37 \\pub const FooA = 0;
38 ,
39 \\pub const FooB = 1;
40 ,
41 \\pub const Foo1 = 2;
42 ,
43 \\pub const Foo = enum_Foo
44 );
45
46 cases.add("restrict -> noalias",
47 \\void foo(void *restrict bar, void *restrict);
48 ,
49 \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);
50 );
51
52 cases.add("simple struct",
53 \\struct Foo {
54 \\ int x;
55 \\ char *y;
56 \\};
57 ,
58 \\const struct_Foo = extern struct {
59 \\ x: c_int,
60 \\ y: ?&u8,
61 \\};
62 ,
63 \\pub const Foo = struct_Foo;
64 );
65
66 cases.add("qualified struct and enum",
67 \\struct Foo {
68 \\ int x;
69 \\ int y;
70 \\};
71 \\enum Bar {
72 \\ BarA,
73 \\ BarB,
74 \\};
75 \\void func(struct Foo *a, enum Bar **b);
76 ,
77 \\pub const struct_Foo = extern struct {
78 \\ x: c_int,
79 \\ y: c_int,
80 \\};
81 ,
82 \\pub const enum_Bar = extern enum {
83 \\ A,
84 \\ B,
85 \\};
86 ,
87 \\pub const BarA = 0;
88 ,
89 \\pub const BarB = 1;
90 ,
91 \\pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar);
92 ,
93 \\pub const Foo = struct_Foo;
94 ,
95 \\pub const Bar = enum_Bar;
96 );
97
98 cases.add("constant size array",
99 \\void func(int array[20]);
100 ,
101 \\pub extern fn func(array: ?&c_int);
102 );
103
104 cases.add("self referential struct with function pointer",
105 \\struct Foo {
106 \\ void (*derp)(struct Foo *foo);
107 \\};
108 ,
109 \\pub const struct_Foo = extern struct {
110 \\ derp: ?extern fn(?&struct_Foo),
111 \\};
112 ,
113 \\pub const Foo = struct_Foo;
114 );
115
116 cases.add("struct prototype used in func",
117 \\struct Foo;
118 \\struct Foo *some_func(struct Foo *foo, int x);
119 ,
120 \\pub const struct_Foo = @OpaqueType();
121 ,
122 \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;
123 ,
124 \\pub const Foo = struct_Foo;
125 );
126
127 cases.add("#define a char literal",
128 \\#define A_CHAR 'a'
129 ,
130 \\pub const A_CHAR = 97;
131 );
132
133 cases.add("#define an unsigned integer literal",
134 \\#define CHANNEL_COUNT 24
135 ,
136 \\pub const CHANNEL_COUNT = 24;
137 );
138
139 cases.add("#define referencing another #define",
140 \\#define THING2 THING1
141 \\#define THING1 1234
142 ,
143 \\pub const THING1 = 1234;
144 ,
145 \\pub const THING2 = THING1;
146 );
147
148 cases.add("variables",
149 \\extern int extern_var;
150 \\static const int int_var = 13;
151 ,
152 \\pub extern var extern_var: c_int;
153 ,
154 \\pub const int_var: c_int = 13;
155 );
156
157 cases.add("circular struct definitions",
158 \\struct Bar;
159 \\
160 \\struct Foo {
161 \\ struct Bar *next;
162 \\};
163 \\
164 \\struct Bar {
165 \\ struct Foo *next;
166 \\};
167 ,
168 \\pub const struct_Bar = extern struct {
169 \\ next: ?&struct_Foo,
170 \\};
171 ,
172 \\pub const struct_Foo = extern struct {
173 \\ next: ?&struct_Bar,
174 \\};
175 );
176
177 cases.add("typedef void",
178 \\typedef void Foo;
179 \\Foo fun(Foo *a);
180 ,
181 \\pub const Foo = c_void;
182 ,
183 \\pub extern fn fun(a: ?&c_void);
184 );
185
186 cases.add("generate inline func for #define global extern fn",
187 \\extern void (*fn_ptr)(void);
188 \\#define foo fn_ptr
189 \\
190 \\extern char (*fn_ptr2)(int, float);
191 \\#define bar fn_ptr2
192 ,
193 \\pub extern var fn_ptr: ?extern fn();
194 ,
195 \\pub fn foo();
196 ,
197 \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
198 ,
199 \\pub fn bar(arg0: c_int, arg1: f32) -> u8;
200 );
201
202 cases.add("#define string",
203 \\#define foo "a string"
204 ,
205 \\pub const foo: &const u8 = &(c str lit);
206 );
207
208 cases.add("__cdecl doesn't mess up function pointers",
209 \\void foo(void (__cdecl *fn_ptr)(void));
210 ,
211 \\pub extern fn foo(fn_ptr: ?extern fn());
212 );
213
214 cases.add("comment after integer literal",
215 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
216 ,
217 \\pub const SDL_INIT_VIDEO = 32;
218 );
219
220 cases.add("zig keywords in C code",
221 \\struct comptime {
222 \\ int defer;
223 \\};
224 ,
225 \\pub const struct_comptime = extern struct {
226 \\ @"defer": c_int,
227 \\};
228 ,
229 \\pub const @"comptime" = struct_comptime;
230 );
231
232 cases.add("macro defines string literal with octal",
233 \\#define FOO "aoeu\023 derp"
234 \\#define FOO2 "aoeu\0234 derp"
235 \\#define FOO_CHAR '\077'
236 ,
237 \\pub const FOO: &const u8 = &(c str lit);
238 ,
239 \\pub const FOO2: &const u8 = &(c str lit);
240 ,
241 \\pub const FOO_CHAR = 63;
242 );
243}
test/run_tests.cpp deleted-3035
...@@ -1,3035 +0,0 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "list.hpp"
9#include "buffer.hpp"
10#include "os.hpp"
11#include "error.hpp"
12#include "config.h"
13
14#include <stdio.h>
15#include <stdarg.h>
16
17enum TestSpecial {
18 TestSpecialNone,
19 TestSpecialSelfHosted,
20 TestSpecialStd,
21 TestSpecialLinkStep,
22};
23
24struct TestSourceFile {
25 const char *relative_path;
26 const char *source_code;
27};
28
29enum AllowWarnings {
30 AllowWarningsNo,
31 AllowWarningsYes,
32};
33
34struct TestCase {
35 const char *case_name;
36 const char *output;
37 ZigList<TestSourceFile> source_files;
38 ZigList<const char *> compile_errors;
39 ZigList<const char *> compiler_args;
40 ZigList<const char *> linker_args;
41 ZigList<const char *> program_args;
42 bool is_parseh;
43 TestSpecial special;
44 bool is_release_mode;
45 bool is_debug_safety;
46 AllowWarnings allow_warnings;
47};
48
49static ZigList<TestCase*> test_cases = {0};
50static const char *tmp_source_path = ".tmp_source.zig";
51static const char *tmp_h_path = ".tmp_header.h";
52
53#if defined(_WIN32)
54static const char *tmp_exe_path = "./.tmp_exe.exe";
55static const char *zig_exe = "./zig.exe";
56#define NL "\r\n"
57#else
58static const char *tmp_exe_path = "./.tmp_exe";
59static const char *zig_exe = "./zig";
60#define NL "\n"
61#endif
62
63static void add_source_file(TestCase *test_case, const char *path, const char *source) {
64 test_case->source_files.add_one();
65 test_case->source_files.last().relative_path = path;
66 test_case->source_files.last().source_code = source;
67}
68
69static TestCase *add_simple_case(const char *case_name, const char *source, const char *output) {
70 TestCase *test_case = allocate<TestCase>(1);
71 test_case->case_name = case_name;
72 test_case->output = output;
73
74 test_case->source_files.resize(1);
75 test_case->source_files.at(0).relative_path = tmp_source_path;
76 test_case->source_files.at(0).source_code = source;
77
78 test_case->compiler_args.append("build_exe");
79 test_case->compiler_args.append(tmp_source_path);
80 test_case->compiler_args.append("--name");
81 test_case->compiler_args.append("test");
82 test_case->compiler_args.append("--output");
83 test_case->compiler_args.append(tmp_exe_path);
84 test_case->compiler_args.append("--release");
85 test_case->compiler_args.append("--strip");
86 test_case->compiler_args.append("--color");
87 test_case->compiler_args.append("on");
88
89 test_cases.append(test_case);
90
91 return test_case;
92}
93
94static TestCase *add_asm_case(const char *case_name, const char *source, const char *output) {
95 TestCase *test_case = allocate<TestCase>(1);
96 test_case->case_name = case_name;
97 test_case->output = output;
98 test_case->special = TestSpecialLinkStep;
99
100 test_case->source_files.resize(1);
101 test_case->source_files.at(0).relative_path = ".tmp_source.s";
102 test_case->source_files.at(0).source_code = source;
103
104 test_case->compiler_args.append("asm");
105 test_case->compiler_args.append(".tmp_source.s");
106 test_case->compiler_args.append("--name");
107 test_case->compiler_args.append("test");
108 test_case->compiler_args.append("--color");
109 test_case->compiler_args.append("on");
110
111 test_case->linker_args.append("link_exe");
112 test_case->linker_args.append("test.o");
113 test_case->linker_args.append("--name");
114 test_case->linker_args.append("test");
115 test_case->linker_args.append("--output");
116 test_case->linker_args.append(tmp_exe_path);
117 test_case->linker_args.append("--color");
118 test_case->linker_args.append("on");
119
120 test_cases.append(test_case);
121
122 return test_case;
123}
124
125static TestCase *add_simple_case_libc(const char *case_name, const char *source, const char *output) {
126 TestCase *tc = add_simple_case(case_name, source, output);
127 tc->compiler_args.append("--library");
128 tc->compiler_args.append("c");
129 return tc;
130}
131
132static TestCase *add_compile_fail_case(const char *case_name, const char *source, size_t count, ...) {
133 va_list ap;
134 va_start(ap, count);
135
136 TestCase *test_case = allocate<TestCase>(1);
137 test_case->case_name = case_name;
138 test_case->source_files.resize(1);
139 test_case->source_files.at(0).relative_path = tmp_source_path;
140 test_case->source_files.at(0).source_code = source;
141
142 for (size_t i = 0; i < count; i += 1) {
143 const char *arg = va_arg(ap, const char *);
144 test_case->compile_errors.append(arg);
145 }
146
147 test_case->compiler_args.append("build_obj");
148 test_case->compiler_args.append(tmp_source_path);
149
150 test_case->compiler_args.append("--name");
151 test_case->compiler_args.append("test");
152
153 test_case->compiler_args.append("--output");
154 test_case->compiler_args.append(tmp_exe_path);
155
156 test_case->compiler_args.append("--release");
157 test_case->compiler_args.append("--strip");
158
159 test_cases.append(test_case);
160
161 return test_case;
162}
163
164static TestCase *add_compile_fail_case_exe(const char *case_name, const char *source, size_t count, ...) {
165 va_list ap;
166 va_start(ap, count);
167
168 TestCase *test_case = allocate<TestCase>(1);
169 test_case->case_name = case_name;
170 test_case->source_files.resize(1);
171 test_case->source_files.at(0).relative_path = tmp_source_path;
172 test_case->source_files.at(0).source_code = source;
173
174 for (size_t i = 0; i < count; i += 1) {
175 const char *arg = va_arg(ap, const char *);
176 test_case->compile_errors.append(arg);
177 }
178
179 test_case->compiler_args.append("build_exe");
180 test_case->compiler_args.append(tmp_source_path);
181
182 test_case->compiler_args.append("--name");
183 test_case->compiler_args.append("test");
184
185 test_case->compiler_args.append("--output");
186 test_case->compiler_args.append(tmp_exe_path);
187
188 test_case->compiler_args.append("--release");
189 test_case->compiler_args.append("--strip");
190
191 test_cases.append(test_case);
192
193 return test_case;
194}
195
196static void add_debug_safety_case(const char *case_name, const char *source) {
197 TestCase *test_case = allocate<TestCase>(1);
198 test_case->is_debug_safety = true;
199 test_case->case_name = buf_ptr(buf_sprintf("%s", case_name));
200 test_case->source_files.resize(1);
201 test_case->source_files.at(0).relative_path = tmp_source_path;
202 test_case->source_files.at(0).source_code = source;
203
204 test_case->compiler_args.append("build_exe");
205 test_case->compiler_args.append(tmp_source_path);
206
207 test_case->compiler_args.append("--name");
208 test_case->compiler_args.append("test");
209
210 test_case->compiler_args.append("--output");
211 test_case->compiler_args.append(tmp_exe_path);
212
213 test_cases.append(test_case);
214}
215
216static TestCase *add_parseh_case(const char *case_name, AllowWarnings allow_warnings,
217 const char *source, size_t count, ...)
218{
219 va_list ap;
220 va_start(ap, count);
221
222 TestCase *test_case = allocate<TestCase>(1);
223 test_case->case_name = case_name;
224 test_case->is_parseh = true;
225 test_case->allow_warnings = allow_warnings;
226
227 test_case->source_files.resize(1);
228 test_case->source_files.at(0).relative_path = tmp_h_path;
229 test_case->source_files.at(0).source_code = source;
230
231 for (size_t i = 0; i < count; i += 1) {
232 const char *arg = va_arg(ap, const char *);
233 test_case->compile_errors.append(arg);
234 }
235
236 test_case->compiler_args.append("parseh");
237 test_case->compiler_args.append(tmp_h_path);
238 //test_case->compiler_args.append("--verbose");
239
240 test_cases.append(test_case);
241
242 va_end(ap);
243 return test_case;
244}
245
246static TestCase *add_example_compile_extra(const char *root_source_file, bool libc) {
247 TestCase *test_case = allocate<TestCase>(1);
248 test_case->case_name = buf_ptr(buf_sprintf("build example %s", root_source_file));
249 test_case->output = nullptr;
250 test_case->special = TestSpecialNone;
251
252 test_case->compiler_args.append("build_exe");
253 test_case->compiler_args.append(buf_ptr(buf_sprintf("../%s", root_source_file)));
254
255 if (libc) {
256 test_case->compiler_args.append("--library");
257 test_case->compiler_args.append("c");
258 }
259
260 test_cases.append(test_case);
261
262 return test_case;
263}
264
265static TestCase *add_example_compile(const char *root_source_file) {
266 return add_example_compile_extra(root_source_file, false);
267}
268
269static TestCase *add_example_compile_libc(const char *root_source_file) {
270 return add_example_compile_extra(root_source_file, true);
271}
272
273static void add_compiling_test_cases(void) {
274 add_simple_case_libc("hello world with libc", R"SOURCE(
275const c = @cImport(@cInclude("stdio.h"));
276export fn main(argc: c_int, argv: &&u8) -> c_int {
277 _ = c.puts(c"Hello, world!");
278 return 0;
279}
280 )SOURCE", "Hello, world!" NL);
281
282 {
283 TestCase *tc = add_simple_case("multiple files with private function", R"SOURCE(
284use @import("std").io;
285use @import("foo.zig");
286
287pub fn main() -> %void {
288 privateFunction();
289 %%stdout.printf("OK 2\n");
290}
291
292fn privateFunction() {
293 printText();
294}
295 )SOURCE", "OK 1\nOK 2\n");
296
297 add_source_file(tc, "foo.zig", R"SOURCE(
298use @import("std").io;
299
300// purposefully conflicting function with main.zig
301// but it's private so it should be OK
302fn privateFunction() {
303 %%stdout.printf("OK 1\n");
304}
305
306pub fn printText() {
307 privateFunction();
308}
309 )SOURCE");
310 }
311
312 {
313 TestCase *tc = add_simple_case("import segregation", R"SOURCE(
314use @import("foo.zig");
315use @import("bar.zig");
316
317pub fn main() -> %void {
318 foo_function();
319 bar_function();
320}
321 )SOURCE", "OK\nOK\n");
322
323 add_source_file(tc, "foo.zig", R"SOURCE(
324use @import("std").io;
325pub fn foo_function() {
326 %%stdout.printf("OK\n");
327}
328 )SOURCE");
329
330 add_source_file(tc, "bar.zig", R"SOURCE(
331use @import("other.zig");
332use @import("std").io;
333
334pub fn bar_function() {
335 if (foo_function()) {
336 %%stdout.printf("OK\n");
337 }
338}
339 )SOURCE");
340
341 add_source_file(tc, "other.zig", R"SOURCE(
342pub fn foo_function() -> bool {
343 // this one conflicts with the one from foo
344 return true;
345}
346 )SOURCE");
347 }
348
349 {
350 TestCase *tc = add_simple_case("two files use import each other", R"SOURCE(
351use @import("a.zig");
352
353pub fn main() -> %void {
354 ok();
355}
356 )SOURCE", "OK\n");
357
358 add_source_file(tc, "a.zig", R"SOURCE(
359use @import("b.zig");
360const io = @import("std").io;
361
362pub const a_text = "OK\n";
363
364pub fn ok() {
365 %%io.stdout.printf(b_text);
366}
367 )SOURCE");
368
369 add_source_file(tc, "b.zig", R"SOURCE(
370use @import("a.zig");
371
372pub const b_text = a_text;
373 )SOURCE");
374 }
375
376
377
378 add_simple_case("hello world without libc", R"SOURCE(
379const io = @import("std").io;
380
381pub fn main() -> %void {
382 %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));
383}
384 )SOURCE", "Hello, world!\n0012 012 a\n");
385
386
387 add_simple_case_libc("number literals", R"SOURCE(
388const c = @cImport(@cInclude("stdio.h"));
389
390export fn main(argc: c_int, argv: &&u8) -> c_int {
391 _ = c.printf(c"\n");
392
393 _ = c.printf(c"0: %llu\n",
394 u64(0));
395 _ = c.printf(c"320402575052271: %llu\n",
396 u64(320402575052271));
397 _ = c.printf(c"0x01236789abcdef: %llu\n",
398 u64(0x01236789abcdef));
399 _ = c.printf(c"0xffffffffffffffff: %llu\n",
400 u64(0xffffffffffffffff));
401 _ = c.printf(c"0x000000ffffffffffffffff: %llu\n",
402 u64(0x000000ffffffffffffffff));
403 _ = c.printf(c"0o1777777777777777777777: %llu\n",
404 u64(0o1777777777777777777777));
405 _ = c.printf(c"0o0000001777777777777777777777: %llu\n",
406 u64(0o0000001777777777777777777777));
407 _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
408 u64(0b1111111111111111111111111111111111111111111111111111111111111111));
409 _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
410 u64(0b0000001111111111111111111111111111111111111111111111111111111111111111));
411
412 _ = c.printf(c"\n");
413
414 _ = c.printf(c"0.0: %a\n",
415 f64(0.0));
416 _ = c.printf(c"0e0: %a\n",
417 f64(0e0));
418 _ = c.printf(c"0.0e0: %a\n",
419 f64(0.0e0));
420 _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n",
421 f64(000000000000000000000000000000000000000000000000000000000.0e0));
422 _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n",
423 f64(0.000000000000000000000000000000000000000000000000000000000e0));
424 _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n",
425 f64(0.0e000000000000000000000000000000000000000000000000000000000));
426 _ = c.printf(c"1.0: %a\n",
427 f64(1.0));
428 _ = c.printf(c"10.0: %a\n",
429 f64(10.0));
430 _ = c.printf(c"10.5: %a\n",
431 f64(10.5));
432 _ = c.printf(c"10.5e5: %a\n",
433 f64(10.5e5));
434 _ = c.printf(c"10.5e+5: %a\n",
435 f64(10.5e+5));
436 _ = c.printf(c"50.0e-2: %a\n",
437 f64(50.0e-2));
438 _ = c.printf(c"50e-2: %a\n",
439 f64(50e-2));
440
441 _ = c.printf(c"\n");
442
443 _ = c.printf(c"0x1.0: %a\n",
444 f64(0x1.0));
445 _ = c.printf(c"0x10.0: %a\n",
446 f64(0x10.0));
447 _ = c.printf(c"0x100.0: %a\n",
448 f64(0x100.0));
449 _ = c.printf(c"0x103.0: %a\n",
450 f64(0x103.0));
451 _ = c.printf(c"0x103.7: %a\n",
452 f64(0x103.7));
453 _ = c.printf(c"0x103.70: %a\n",
454 f64(0x103.70));
455 _ = c.printf(c"0x103.70p4: %a\n",
456 f64(0x103.70p4));
457 _ = c.printf(c"0x103.70p5: %a\n",
458 f64(0x103.70p5));
459 _ = c.printf(c"0x103.70p+5: %a\n",
460 f64(0x103.70p+5));
461 _ = c.printf(c"0x103.70p-5: %a\n",
462 f64(0x103.70p-5));
463
464 _ = c.printf(c"\n");
465
466 _ = c.printf(c"0b10100.00010e0: %a\n",
467 f64(0b10100.00010e0));
468 _ = c.printf(c"0o10700.00010e0: %a\n",
469 f64(0o10700.00010e0));
470
471 return 0;
472}
473 )SOURCE", R"OUTPUT(
4740: 0
475320402575052271: 320402575052271
4760x01236789abcdef: 320402575052271
4770xffffffffffffffff: 18446744073709551615
4780x000000ffffffffffffffff: 18446744073709551615
4790o1777777777777777777777: 18446744073709551615
4800o0000001777777777777777777777: 18446744073709551615
4810b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615
4820b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615
483
4840.0: 0x0p+0
4850e0: 0x0p+0
4860.0e0: 0x0p+0
487000000000000000000000000000000000000000000000000000000000.0e0: 0x0p+0
4880.000000000000000000000000000000000000000000000000000000000e0: 0x0p+0
4890.0e000000000000000000000000000000000000000000000000000000000: 0x0p+0
4901.0: 0x1p+0
49110.0: 0x1.4p+3
49210.5: 0x1.5p+3
49310.5e5: 0x1.0059p+20
49410.5e+5: 0x1.0059p+20
49550.0e-2: 0x1p-1
49650e-2: 0x1p-1
497
4980x1.0: 0x1p+0
4990x10.0: 0x1p+4
5000x100.0: 0x1p+8
5010x103.0: 0x1.03p+8
5020x103.7: 0x1.037p+8
5030x103.70: 0x1.037p+8
5040x103.70p4: 0x1.037p+12
5050x103.70p5: 0x1.037p+13
5060x103.70p+5: 0x1.037p+13
5070x103.70p-5: 0x1.037p+3
508
5090b10100.00010e0: 0x1.41p+4
5100o10700.00010e0: 0x1.1c0001p+12
511)OUTPUT");
512
513 add_simple_case("order-independent declarations", R"SOURCE(
514const io = @import("std").io;
515const z = io.stdin_fileno;
516const x : @typeOf(y) = 1234;
517const y : u16 = 5678;
518pub fn main() -> %void {
519 var x_local : i32 = print_ok(x);
520}
521fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
522 %%io.stdout.printf("OK\n");
523 return 0;
524}
525const foo : i32 = 0;
526 )SOURCE", "OK\n");
527
528 add_simple_case_libc("expose function pointer to C land", R"SOURCE(
529const c = @cImport(@cInclude("stdlib.h"));
530
531export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
532 const a_int = @ptrcast(&i32, a ?? unreachable);
533 const b_int = @ptrcast(&i32, b ?? unreachable);
534 if (*a_int < *b_int) {
535 -1
536 } else if (*a_int > *b_int) {
537 1
538 } else {
539 c_int(0)
540 }
541}
542
543export fn main() -> c_int {
544 var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
545
546 c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
547
548 for (array) |item, i| {
549 if (item != i) {
550 c.abort();
551 }
552 }
553
554 return 0;
555}
556 )SOURCE", "");
557
558
559
560 add_simple_case_libc("casting between float and integer types", R"SOURCE(
561const c = @cImport(@cInclude("stdio.h"));
562export fn main(argc: c_int, argv: &&u8) -> c_int {
563 const small: f32 = 3.25;
564 const x: f64 = small;
565 const y = i32(x);
566 const z = f64(y);
567 _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4));
568 return 0;
569}
570 )SOURCE", "3.25\n3\n3.00\n-0.40\n");
571
572
573 add_simple_case("same named methods in incomplete struct", R"SOURCE(
574const io = @import("std").io;
575
576const Foo = struct {
577 field1: Bar,
578
579 fn method(a: &const Foo) -> bool { true }
580};
581
582const Bar = struct {
583 field2: i32,
584
585 fn method(b: &const Bar) -> bool { true }
586};
587
588pub fn main() -> %void {
589 const bar = Bar {.field2 = 13,};
590 const foo = Foo {.field1 = bar,};
591 if (!foo.method()) {
592 %%io.stdout.printf("BAD\n");
593 }
594 if (!bar.method()) {
595 %%io.stdout.printf("BAD\n");
596 }
597 %%io.stdout.printf("OK\n");
598}
599 )SOURCE", "OK\n");
600
601
602 add_simple_case("defer with only fallthrough", R"SOURCE(
603const io = @import("std").io;
604pub fn main() -> %void {
605 %%io.stdout.printf("before\n");
606 defer %%io.stdout.printf("defer1\n");
607 defer %%io.stdout.printf("defer2\n");
608 defer %%io.stdout.printf("defer3\n");
609 %%io.stdout.printf("after\n");
610}
611 )SOURCE", "before\nafter\ndefer3\ndefer2\ndefer1\n");
612
613
614 add_simple_case("defer with return", R"SOURCE(
615const io = @import("std").io;
616const os = @import("std").os;
617pub fn main() -> %void {
618 %%io.stdout.printf("before\n");
619 defer %%io.stdout.printf("defer1\n");
620 defer %%io.stdout.printf("defer2\n");
621 if (os.args.count() == 1) return;
622 defer %%io.stdout.printf("defer3\n");
623 %%io.stdout.printf("after\n");
624}
625 )SOURCE", "before\ndefer2\ndefer1\n");
626
627
628 add_simple_case("%defer and it fails", R"SOURCE(
629const io = @import("std").io;
630pub fn main() -> %void {
631 do_test() %% return;
632}
633fn do_test() -> %void {
634 %%io.stdout.printf("before\n");
635 defer %%io.stdout.printf("defer1\n");
636 %defer %%io.stdout.printf("deferErr\n");
637 %return its_gonna_fail();
638 defer %%io.stdout.printf("defer3\n");
639 %%io.stdout.printf("after\n");
640}
641error IToldYouItWouldFail;
642fn its_gonna_fail() -> %void {
643 return error.IToldYouItWouldFail;
644}
645 )SOURCE", "before\ndeferErr\ndefer1\n");
646
647
648 add_simple_case("%defer and it passes", R"SOURCE(
649const io = @import("std").io;
650pub fn main() -> %void {
651 do_test() %% return;
652}
653fn do_test() -> %void {
654 %%io.stdout.printf("before\n");
655 defer %%io.stdout.printf("defer1\n");
656 %defer %%io.stdout.printf("deferErr\n");
657 %return its_gonna_pass();
658 defer %%io.stdout.printf("defer3\n");
659 %%io.stdout.printf("after\n");
660}
661fn its_gonna_pass() -> %void { }
662 )SOURCE", "before\nafter\ndefer3\ndefer1\n");
663
664
665 {
666 TestCase *tc = add_simple_case("@embedFile", R"SOURCE(
667const foo_txt = @embedFile("foo.txt");
668const io = @import("std").io;
669
670pub fn main() -> %void {
671 %%io.stdout.printf(foo_txt);
672}
673 )SOURCE", "1234\nabcd\n");
674
675 add_source_file(tc, "foo.txt", "1234\nabcd\n");
676 }
677}
678
679////////////////////////////////////////////////////////////////////////////////////
680
681static void add_build_examples(void) {
682 add_example_compile("example/hello_world/hello.zig");
683 add_example_compile_libc("example/hello_world/hello_libc.zig");
684 add_example_compile("example/cat/main.zig");
685 add_example_compile("example/guess_number/main.zig");
686}
687
688
689////////////////////////////////////////////////////////////////////////////////////
690
691static void add_compile_failure_test_cases(void) {
692 add_compile_fail_case("multiple function definitions", R"SOURCE(
693fn a() {}
694fn a() {}
695export fn entry() { a(); }
696 )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'");
697
698 add_compile_fail_case("unreachable with return", R"SOURCE(
699fn a() -> noreturn {return;}
700export fn entry() { a(); }
701 )SOURCE", 1, ".tmp_source.zig:2:21: error: expected type 'noreturn', found 'void'");
702
703 add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
704fn a() -> i32 {}
705export fn entry() { _ = a(); }
706 )SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', found 'void'");
707
708 add_compile_fail_case("undefined function call", R"SOURCE(
709export fn a() {
710 b();
711}
712 )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'");
713
714 add_compile_fail_case("wrong number of arguments", R"SOURCE(
715export fn a() {
716 b(1);
717}
718fn b(a: i32, b: i32, c: i32) { }
719 )SOURCE", 1, ".tmp_source.zig:3:6: error: expected 3 arguments, found 1");
720
721 add_compile_fail_case("invalid type", R"SOURCE(
722fn a() -> bogus {}
723export fn entry() { _ = a(); }
724 )SOURCE", 1, ".tmp_source.zig:2:11: error: use of undeclared identifier 'bogus'");
725
726 add_compile_fail_case("pointer to unreachable", R"SOURCE(
727fn a() -> &noreturn {}
728export fn entry() { _ = a(); }
729 )SOURCE", 1, ".tmp_source.zig:2:12: error: pointer to unreachable not allowed");
730
731 add_compile_fail_case("unreachable code", R"SOURCE(
732export fn a() {
733 return;
734 b();
735}
736
737fn b() {}
738 )SOURCE", 1, ".tmp_source.zig:4:6: error: unreachable code");
739
740 add_compile_fail_case("bad import", R"SOURCE(
741const bogus = @import("bogus-does-not-exist.zig");
742export fn entry() { bogus.bogo(); }
743 )SOURCE", 1, ".tmp_source.zig:2:15: error: unable to find 'bogus-does-not-exist.zig'");
744
745 add_compile_fail_case("undeclared identifier", R"SOURCE(
746export fn a() {
747 b +
748 c
749}
750 )SOURCE", 2,
751 ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'",
752 ".tmp_source.zig:4:5: error: use of undeclared identifier 'c'");
753
754 add_compile_fail_case("parameter redeclaration", R"SOURCE(
755fn f(a : i32, a : i32) {
756}
757export fn entry() { f(1, 2); }
758 )SOURCE", 1, ".tmp_source.zig:2:15: error: redeclaration of variable 'a'");
759
760 add_compile_fail_case("local variable redeclaration", R"SOURCE(
761export fn f() {
762 const a : i32 = 0;
763 const a = 0;
764}
765 )SOURCE", 1, ".tmp_source.zig:4:5: error: redeclaration of variable 'a'");
766
767 add_compile_fail_case("local variable redeclares parameter", R"SOURCE(
768fn f(a : i32) {
769 const a = 0;
770}
771export fn entry() { f(1); }
772 )SOURCE", 1, ".tmp_source.zig:3:5: error: redeclaration of variable 'a'");
773
774 add_compile_fail_case("variable has wrong type", R"SOURCE(
775export fn f() -> i32 {
776 const a = c"a";
777 a
778}
779 )SOURCE", 1, ".tmp_source.zig:4:5: error: expected type 'i32', found '&const u8'");
780
781 add_compile_fail_case("if condition is bool, not int", R"SOURCE(
782export fn f() {
783 if (0) {}
784}
785 )SOURCE", 1, ".tmp_source.zig:3:9: error: integer value 0 cannot be implicitly casted to type 'bool'");
786
787 add_compile_fail_case("assign unreachable", R"SOURCE(
788export fn f() {
789 const a = return;
790}
791 )SOURCE", 1, ".tmp_source.zig:3:5: error: unreachable code");
792
793 add_compile_fail_case("unreachable variable", R"SOURCE(
794export fn f() {
795 const a: noreturn = {};
796}
797 )SOURCE", 1, ".tmp_source.zig:3:14: error: variable of type 'noreturn' not allowed");
798
799 add_compile_fail_case("unreachable parameter", R"SOURCE(
800fn f(a: noreturn) {}
801export fn entry() { f(); }
802 )SOURCE", 1, ".tmp_source.zig:2:9: error: parameter of type 'noreturn' not allowed");
803
804 add_compile_fail_case("bad assignment target", R"SOURCE(
805export fn f() {
806 3 = 3;
807}
808 )SOURCE", 1, ".tmp_source.zig:3:7: error: cannot assign to constant");
809
810 add_compile_fail_case("assign to constant variable", R"SOURCE(
811export fn f() {
812 const a = 3;
813 a = 4;
814}
815 )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant");
816
817 add_compile_fail_case("use of undeclared identifier", R"SOURCE(
818export fn f() {
819 b = 3;
820}
821 )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'");
822
823 add_compile_fail_case("const is a statement, not an expression", R"SOURCE(
824export fn f() {
825 (const a = 0);
826}
827 )SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'const'");
828
829 add_compile_fail_case("array access of undeclared identifier", R"SOURCE(
830export fn f() {
831 i[i] = i[i];
832}
833 )SOURCE", 2, ".tmp_source.zig:3:5: error: use of undeclared identifier 'i'",
834 ".tmp_source.zig:3:12: error: use of undeclared identifier 'i'");
835
836 add_compile_fail_case("array access of non array", R"SOURCE(
837export fn f() {
838 var bad : bool = undefined;
839 bad[bad] = bad[bad];
840}
841 )SOURCE", 2, ".tmp_source.zig:4:8: error: array access of non-array type 'bool'",
842 ".tmp_source.zig:4:19: error: array access of non-array type 'bool'");
843
844 add_compile_fail_case("array access with non integer index", R"SOURCE(
845export fn f() {
846 var array = "aoeu";
847 var bad = false;
848 array[bad] = array[bad];
849}
850 )SOURCE", 2, ".tmp_source.zig:5:11: error: expected type 'usize', found 'bool'",
851 ".tmp_source.zig:5:24: error: expected type 'usize', found 'bool'");
852
853 add_compile_fail_case("write to const global variable", R"SOURCE(
854const x : i32 = 99;
855fn f() {
856 x = 1;
857}
858export fn entry() { f(); }
859 )SOURCE", 1, ".tmp_source.zig:4:7: error: cannot assign to constant");
860
861
862 add_compile_fail_case("missing else clause", R"SOURCE(
863fn f(b: bool) {
864 const x : i32 = if (b) { 1 };
865 const y = if (b) { i32(1) };
866}
867export fn entry() { f(true); }
868 )SOURCE", 2, ".tmp_source.zig:3:30: error: integer value 1 cannot be implicitly casted to type 'void'",
869 ".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'");
870
871 add_compile_fail_case("direct struct loop", R"SOURCE(
872const A = struct { a : A, };
873export fn entry() -> usize { @sizeOf(A) }
874 )SOURCE", 1, ".tmp_source.zig:2:11: error: struct 'A' contains itself");
875
876 add_compile_fail_case("indirect struct loop", R"SOURCE(
877const A = struct { b : B, };
878const B = struct { c : C, };
879const C = struct { a : A, };
880export fn entry() -> usize { @sizeOf(A) }
881 )SOURCE", 1, ".tmp_source.zig:2:11: error: struct 'A' contains itself");
882
883 add_compile_fail_case("invalid struct field", R"SOURCE(
884const A = struct { x : i32, };
885export fn f() {
886 var a : A = undefined;
887 a.foo = 1;
888 const y = a.bar;
889}
890 )SOURCE", 2,
891 ".tmp_source.zig:5:6: error: no member named 'foo' in 'A'",
892 ".tmp_source.zig:6:16: error: no member named 'bar' in 'A'");
893
894 add_compile_fail_case("redefinition of struct", R"SOURCE(
895const A = struct { x : i32, };
896const A = struct { y : i32, };
897 )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'");
898
899 add_compile_fail_case("redefinition of enums", R"SOURCE(
900const A = enum {};
901const A = enum {};
902 )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'");
903
904 add_compile_fail_case("redefinition of global variables", R"SOURCE(
905var a : i32 = 1;
906var a : i32 = 2;
907 )SOURCE", 2,
908 ".tmp_source.zig:3:1: error: redefinition of 'a'",
909 ".tmp_source.zig:2:1: note: previous definition is here");
910
911 add_compile_fail_case("byvalue struct parameter in exported function", R"SOURCE(
912const A = struct { x : i32, };
913export fn f(a : A) {}
914 )SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue types not yet supported on extern function parameters");
915
916 add_compile_fail_case("byvalue struct return value in exported function", R"SOURCE(
917const A = struct { x: i32, };
918export fn f() -> A {
919 A {.x = 1234 }
920}
921 )SOURCE", 1, ".tmp_source.zig:3:18: error: byvalue types not yet supported on extern function return values");
922
923 add_compile_fail_case("duplicate field in struct value expression", R"SOURCE(
924const A = struct {
925 x : i32,
926 y : i32,
927 z : i32,
928};
929export fn f() {
930 const a = A {
931 .z = 1,
932 .y = 2,
933 .x = 3,
934 .z = 4,
935 };
936}
937 )SOURCE", 1, ".tmp_source.zig:12:9: error: duplicate field");
938
939 add_compile_fail_case("missing field in struct value expression", R"SOURCE(
940const A = struct {
941 x : i32,
942 y : i32,
943 z : i32,
944};
945export fn f() {
946 // we want the error on the '{' not the 'A' because
947 // the A could be a complicated expression
948 const a = A {
949 .z = 4,
950 .y = 2,
951 };
952}
953 )SOURCE", 1, ".tmp_source.zig:10:17: error: missing field: 'x'");
954
955 add_compile_fail_case("invalid field in struct value expression", R"SOURCE(
956const A = struct {
957 x : i32,
958 y : i32,
959 z : i32,
960};
961export fn f() {
962 const a = A {
963 .z = 4,
964 .y = 2,
965 .foo = 42,
966 };
967}
968 )SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'");
969
970 add_compile_fail_case("invalid break expression", R"SOURCE(
971export fn f() {
972 break;
973}
974 )SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression outside loop");
975
976 add_compile_fail_case("invalid continue expression", R"SOURCE(
977export fn f() {
978 continue;
979}
980 )SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression outside loop");
981
982 add_compile_fail_case("invalid maybe type", R"SOURCE(
983export fn f() {
984 if (const x ?= true) { }
985}
986 )SOURCE", 1, ".tmp_source.zig:3:20: error: expected nullable type, found 'bool'");
987
988 add_compile_fail_case("cast unreachable", R"SOURCE(
989fn f() -> i32 {
990 i32(return 1)
991}
992export fn entry() { _ = f(); }
993 )SOURCE", 1, ".tmp_source.zig:3:8: error: unreachable code");
994
995 add_compile_fail_case("invalid builtin fn", R"SOURCE(
996fn f() -> @bogus(foo) {
997}
998export fn entry() { _ = f(); }
999 )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid builtin function: 'bogus'");
1000
1001 add_compile_fail_case("top level decl dependency loop", R"SOURCE(
1002const a : @typeOf(b) = 0;
1003const b : @typeOf(a) = 0;
1004export fn entry() {
1005 const c = a + b;
1006}
1007 )SOURCE", 1, ".tmp_source.zig:2:1: error: 'a' depends on itself");
1008
1009 add_compile_fail_case("noalias on non pointer param", R"SOURCE(
1010fn f(noalias x: i32) {}
1011export fn entry() { f(1234); }
1012 )SOURCE", 1, ".tmp_source.zig:2:6: error: noalias on non-pointer parameter");
1013
1014 add_compile_fail_case("struct init syntax for array", R"SOURCE(
1015const foo = []u16{.x = 1024,};
1016export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1017 )SOURCE", 1, ".tmp_source.zig:2:18: error: type '[]u16' does not support struct initialization syntax");
1018
1019 add_compile_fail_case("type variables must be constant", R"SOURCE(
1020var foo = u8;
1021export fn entry() -> foo {
1022 return 1;
1023}
1024 )SOURCE", 1, ".tmp_source.zig:2:1: error: variable of type 'type' must be constant");
1025
1026
1027 add_compile_fail_case("variables shadowing types", R"SOURCE(
1028const Foo = struct {};
1029const Bar = struct {};
1030
1031fn f(Foo: i32) {
1032 var Bar : i32 = undefined;
1033}
1034
1035export fn entry() {
1036 f(1234);
1037}
1038 )SOURCE", 4,
1039 ".tmp_source.zig:5:6: error: redefinition of 'Foo'",
1040 ".tmp_source.zig:2:1: note: previous definition is here",
1041 ".tmp_source.zig:6:5: error: redefinition of 'Bar'",
1042 ".tmp_source.zig:3:1: note: previous definition is here");
1043
1044 add_compile_fail_case("multiple else prongs in a switch", R"SOURCE(
1045fn f(x: u32) {
1046 const value: bool = switch (x) {
1047 1234 => false,
1048 else => true,
1049 else => true,
1050 };
1051}
1052export fn entry() {
1053 f(1234);
1054}
1055 )SOURCE", 1, ".tmp_source.zig:6:9: error: multiple else prongs in switch expression");
1056
1057 add_compile_fail_case("global variable initializer must be constant expression", R"SOURCE(
1058extern fn foo() -> i32;
1059const x = foo();
1060export fn entry() -> i32 { x }
1061 )SOURCE", 1, ".tmp_source.zig:3:11: error: unable to evaluate constant expression");
1062
1063 add_compile_fail_case("array concatenation with wrong type", R"SOURCE(
1064const src = "aoeu";
1065const derp = usize(1234);
1066const a = derp ++ "foo";
1067
1068export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1069 )SOURCE", 1, ".tmp_source.zig:4:11: error: expected array or C string literal, found 'usize'");
1070
1071 add_compile_fail_case("non compile time array concatenation", R"SOURCE(
1072fn f() -> []u8 {
1073 s ++ "foo"
1074}
1075var s: [10]u8 = undefined;
1076export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1077 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to evaluate constant expression");
1078
1079 add_compile_fail_case("@cImport with bogus include", R"SOURCE(
1080const c = @cImport(@cInclude("bogus.h"));
1081export fn entry() -> usize { @sizeOf(@typeOf(c.bogo)) }
1082 )SOURCE", 2, ".tmp_source.zig:2:11: error: C import failed",
1083 ".h:1:10: note: 'bogus.h' file not found");
1084
1085 add_compile_fail_case("address of number literal", R"SOURCE(
1086const x = 3;
1087const y = &x;
1088fn foo() -> &const i32 { y }
1089export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1090 )SOURCE", 1, ".tmp_source.zig:4:26: error: expected type '&const i32', found '&const (integer literal)'");
1091
1092 add_compile_fail_case("integer overflow error", R"SOURCE(
1093const x : u8 = 300;
1094export fn entry() -> usize { @sizeOf(@typeOf(x)) }
1095 )SOURCE", 1, ".tmp_source.zig:2:16: error: integer value 300 cannot be implicitly casted to type 'u8'");
1096
1097 add_compile_fail_case("incompatible number literals", R"SOURCE(
1098const x = 2 == 2.0;
1099export fn entry() -> usize { @sizeOf(@typeOf(x)) }
1100 )SOURCE", 1, ".tmp_source.zig:2:11: error: integer value 2 cannot be implicitly casted to type '(float literal)'");
1101
1102 add_compile_fail_case("missing function call param", R"SOURCE(
1103const Foo = struct {
1104 a: i32,
1105 b: i32,
1106
1107 fn member_a(foo: &const Foo) -> i32 {
1108 return foo.a;
1109 }
1110 fn member_b(foo: &const Foo) -> i32 {
1111 return foo.b;
1112 }
1113};
1114
1115const member_fn_type = @typeOf(Foo.member_a);
1116const members = []member_fn_type {
1117 Foo.member_a,
1118 Foo.member_b,
1119};
1120
1121fn f(foo: &const Foo, index: usize) {
1122 const result = members[index]();
1123}
1124
1125export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1126 )SOURCE", 1, ".tmp_source.zig:21:34: error: expected 1 arguments, found 0");
1127
1128 add_compile_fail_case("missing function name and param name", R"SOURCE(
1129fn () {}
1130fn f(i32) {}
1131export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1132 )SOURCE", 2,
1133 ".tmp_source.zig:2:1: error: missing function name",
1134 ".tmp_source.zig:3:6: error: missing parameter name");
1135
1136 add_compile_fail_case("wrong function type", R"SOURCE(
1137const fns = []fn(){ a, b, c };
1138fn a() -> i32 {0}
1139fn b() -> i32 {1}
1140fn c() -> i32 {2}
1141export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
1142 )SOURCE", 1, ".tmp_source.zig:2:21: error: expected type 'fn()', found 'fn() -> i32'");
1143
1144 add_compile_fail_case("extern function pointer mismatch", R"SOURCE(
1145const fns = [](fn(i32)->i32){ a, b, c };
1146pub fn a(x: i32) -> i32 {x + 0}
1147pub fn b(x: i32) -> i32 {x + 1}
1148export fn c(x: i32) -> i32 {x + 2}
1149
1150export fn entry() -> usize { @sizeOf(@typeOf(fns)) }
1151 )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', found 'extern fn(i32) -> i32'");
1152
1153
1154 add_compile_fail_case("implicit cast from f64 to f32", R"SOURCE(
1155const x : f64 = 1.0;
1156const y : f32 = x;
1157
1158export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1159 )SOURCE", 1, ".tmp_source.zig:3:17: error: expected type 'f32', found 'f64'");
1160
1161
1162 add_compile_fail_case("colliding invalid top level functions", R"SOURCE(
1163fn func() -> bogus {}
1164fn func() -> bogus {}
1165export fn entry() -> usize { @sizeOf(@typeOf(func)) }
1166 )SOURCE", 2,
1167 ".tmp_source.zig:3:1: error: redefinition of 'func'",
1168 ".tmp_source.zig:2:14: error: use of undeclared identifier 'bogus'");
1169
1170
1171 add_compile_fail_case("bogus compile var", R"SOURCE(
1172const x = @compileVar("bogus");
1173export fn entry() -> usize { @sizeOf(@typeOf(x)) }
1174 )SOURCE", 1, ".tmp_source.zig:2:23: error: unrecognized compile variable: 'bogus'");
1175
1176
1177 add_compile_fail_case("non constant expression in array size outside function", R"SOURCE(
1178const Foo = struct {
1179 y: [get()]u8,
1180};
1181var global_var: usize = 1;
1182fn get() -> usize { global_var }
1183
1184export fn entry() -> usize { @sizeOf(@typeOf(Foo)) }
1185 )SOURCE", 3,
1186 ".tmp_source.zig:6:21: error: unable to evaluate constant expression",
1187 ".tmp_source.zig:3:12: note: called from here",
1188 ".tmp_source.zig:3:8: note: called from here");
1189
1190
1191 add_compile_fail_case("addition with non numbers", R"SOURCE(
1192const Foo = struct {
1193 field: i32,
1194};
1195const x = Foo {.field = 1} + Foo {.field = 2};
1196
1197export fn entry() -> usize { @sizeOf(@typeOf(x)) }
1198 )SOURCE", 1, ".tmp_source.zig:5:28: error: invalid operands to binary expression: 'Foo' and 'Foo'");
1199
1200
1201 add_compile_fail_case("division by zero", R"SOURCE(
1202const lit_int_x = 1 / 0;
1203const lit_float_x = 1.0 / 0.0;
1204const int_x = i32(1) / i32(0);
1205const float_x = f32(1.0) / f32(0.0);
1206
1207export fn entry1() -> usize { @sizeOf(@typeOf(lit_int_x)) }
1208export fn entry2() -> usize { @sizeOf(@typeOf(lit_float_x)) }
1209export fn entry3() -> usize { @sizeOf(@typeOf(int_x)) }
1210export fn entry4() -> usize { @sizeOf(@typeOf(float_x)) }
1211 )SOURCE", 4,
1212 ".tmp_source.zig:2:21: error: division by zero is undefined",
1213 ".tmp_source.zig:3:25: error: division by zero is undefined",
1214 ".tmp_source.zig:4:22: error: division by zero is undefined",
1215 ".tmp_source.zig:5:26: error: division by zero is undefined");
1216
1217
1218 add_compile_fail_case("missing switch prong", R"SOURCE(
1219const Number = enum {
1220 One,
1221 Two,
1222 Three,
1223 Four,
1224};
1225fn f(n: Number) -> i32 {
1226 switch (n) {
1227 Number.One => 1,
1228 Number.Two => 2,
1229 Number.Three => i32(3),
1230 }
1231}
1232
1233export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1234 )SOURCE", 1, ".tmp_source.zig:9:5: error: enumeration value 'Number.Four' not handled in switch");
1235
1236 add_compile_fail_case("normal string with newline", R"SOURCE(
1237const foo = "a
1238b";
1239
1240export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1241 )SOURCE", 1, ".tmp_source.zig:2:13: error: newline not allowed in string literal");
1242
1243 add_compile_fail_case("invalid comparison for function pointers", R"SOURCE(
1244fn foo() {}
1245const invalid = foo > foo;
1246
1247export fn entry() -> usize { @sizeOf(@typeOf(invalid)) }
1248 )SOURCE", 1, ".tmp_source.zig:3:21: error: operator not allowed for type 'fn()'");
1249
1250 add_compile_fail_case("generic function instance with non-constant expression", R"SOURCE(
1251fn foo(comptime x: i32, y: i32) -> i32 { return x + y; }
1252fn test1(a: i32, b: i32) -> i32 {
1253 return foo(a, b);
1254}
1255
1256export fn entry() -> usize { @sizeOf(@typeOf(test1)) }
1257 )SOURCE", 1, ".tmp_source.zig:4:16: error: unable to evaluate constant expression");
1258
1259 add_compile_fail_case("goto jumping into block", R"SOURCE(
1260export fn f() {
1261 {
1262a_label:
1263 }
1264 goto a_label;
1265}
1266 )SOURCE", 1, ".tmp_source.zig:6:5: error: no label in scope named 'a_label'");
1267
1268 add_compile_fail_case("goto jumping past a defer", R"SOURCE(
1269fn f(b: bool) {
1270 if (b) goto label;
1271 defer derp();
1272label:
1273}
1274fn derp(){}
1275
1276export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1277 )SOURCE", 1, ".tmp_source.zig:3:12: error: no label in scope named 'label'");
1278
1279 add_compile_fail_case("assign null to non-nullable pointer", R"SOURCE(
1280const a: &u8 = null;
1281
1282export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1283 )SOURCE", 1, ".tmp_source.zig:2:16: error: expected type '&u8', found '(null)'");
1284
1285 add_compile_fail_case("indexing an array of size zero", R"SOURCE(
1286const array = []u8{};
1287export fn foo() {
1288 const pointer = &array[0];
1289}
1290 )SOURCE", 1, ".tmp_source.zig:4:27: error: index 0 outside array of size 0");
1291
1292 add_compile_fail_case("compile time division by zero", R"SOURCE(
1293const y = foo(0);
1294fn foo(x: i32) -> i32 {
1295 1 / x
1296}
1297
1298export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1299 )SOURCE", 2,
1300 ".tmp_source.zig:4:7: error: division by zero is undefined",
1301 ".tmp_source.zig:2:14: note: called from here");
1302
1303 add_compile_fail_case("branch on undefined value", R"SOURCE(
1304const x = if (undefined) true else false;
1305
1306export fn entry() -> usize { @sizeOf(@typeOf(x)) }
1307 )SOURCE", 1, ".tmp_source.zig:2:15: error: use of undefined value");
1308
1309
1310 add_compile_fail_case("endless loop in function evaluation", R"SOURCE(
1311const seventh_fib_number = fibbonaci(7);
1312fn fibbonaci(x: i32) -> i32 {
1313 return fibbonaci(x - 1) + fibbonaci(x - 2);
1314}
1315
1316export fn entry() -> usize { @sizeOf(@typeOf(seventh_fib_number)) }
1317 )SOURCE", 2,
1318 ".tmp_source.zig:4:21: error: evaluation exceeded 1000 backwards branches",
1319 ".tmp_source.zig:4:21: note: called from here");
1320
1321 add_compile_fail_case("@embedFile with bogus file", R"SOURCE(
1322const resource = @embedFile("bogus.txt");
1323
1324export fn entry() -> usize { @sizeOf(@typeOf(resource)) }
1325 )SOURCE", 2, ".tmp_source.zig:2:29: error: unable to find '", "/bogus.txt'");
1326
1327 add_compile_fail_case("non-const expression in struct literal outside function", R"SOURCE(
1328const Foo = struct {
1329 x: i32,
1330};
1331const a = Foo {.x = get_it()};
1332extern fn get_it() -> i32;
1333
1334export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1335 )SOURCE", 1, ".tmp_source.zig:5:21: error: unable to evaluate constant expression");
1336
1337 add_compile_fail_case("non-const expression function call with struct return value outside function", R"SOURCE(
1338const Foo = struct {
1339 x: i32,
1340};
1341const a = get_it();
1342fn get_it() -> Foo {
1343 global_side_effect = true;
1344 Foo {.x = 13}
1345}
1346var global_side_effect = false;
1347
1348export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1349 )SOURCE", 2,
1350 ".tmp_source.zig:7:24: error: unable to evaluate constant expression",
1351 ".tmp_source.zig:5:17: note: called from here");
1352
1353 add_compile_fail_case("undeclared identifier error should mark fn as impure", R"SOURCE(
1354export fn foo() {
1355 test_a_thing();
1356}
1357fn test_a_thing() {
1358 bad_fn_call();
1359}
1360 )SOURCE", 1, ".tmp_source.zig:6:5: error: use of undeclared identifier 'bad_fn_call'");
1361
1362 add_compile_fail_case("illegal comparison of types", R"SOURCE(
1363fn bad_eql_1(a: []u8, b: []u8) -> bool {
1364 a == b
1365}
1366const EnumWithData = enum {
1367 One,
1368 Two: i32,
1369};
1370fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
1371 *a == *b
1372}
1373
1374export fn entry1() -> usize { @sizeOf(@typeOf(bad_eql_1)) }
1375export fn entry2() -> usize { @sizeOf(@typeOf(bad_eql_2)) }
1376 )SOURCE", 2,
1377 ".tmp_source.zig:3:7: error: operator not allowed for type '[]u8'",
1378 ".tmp_source.zig:10:8: error: operator not allowed for type 'EnumWithData'");
1379
1380 add_compile_fail_case("non-const switch number literal", R"SOURCE(
1381export fn foo() {
1382 const x = switch (bar()) {
1383 1, 2 => 1,
1384 3, 4 => 2,
1385 else => 3,
1386 };
1387}
1388fn bar() -> i32 {
1389 2
1390}
1391 )SOURCE", 1, ".tmp_source.zig:3:15: error: unable to infer expression type");
1392
1393 add_compile_fail_case("atomic orderings of cmpxchg - failure stricter than success", R"SOURCE(
1394export fn f() {
1395 var x: i32 = 1234;
1396 while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Monotonic, AtomicOrder.SeqCst)) {}
1397}
1398 )SOURCE", 1, ".tmp_source.zig:4:72: error: failure atomic ordering must be no stricter than success");
1399
1400 add_compile_fail_case("atomic orderings of cmpxchg - success Monotonic or stricter", R"SOURCE(
1401export fn f() {
1402 var x: i32 = 1234;
1403 while (!@cmpxchg(&x, 1234, 5678, AtomicOrder.Unordered, AtomicOrder.Unordered)) {}
1404}
1405 )SOURCE", 1, ".tmp_source.zig:4:49: error: success atomic ordering must be Monotonic or stricter");
1406
1407 add_compile_fail_case("negation overflow in function evaluation", R"SOURCE(
1408const y = neg(-128);
1409fn neg(x: i8) -> i8 {
1410 -x
1411}
1412
1413export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1414 )SOURCE", 2,
1415 ".tmp_source.zig:4:5: error: negation caused overflow",
1416 ".tmp_source.zig:2:14: note: called from here");
1417
1418 add_compile_fail_case("add overflow in function evaluation", R"SOURCE(
1419const y = add(65530, 10);
1420fn add(a: u16, b: u16) -> u16 {
1421 a + b
1422}
1423
1424export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1425 )SOURCE", 2,
1426 ".tmp_source.zig:4:7: error: operation caused overflow",
1427 ".tmp_source.zig:2:14: note: called from here");
1428
1429
1430 add_compile_fail_case("sub overflow in function evaluation", R"SOURCE(
1431const y = sub(10, 20);
1432fn sub(a: u16, b: u16) -> u16 {
1433 a - b
1434}
1435
1436export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1437 )SOURCE", 2,
1438 ".tmp_source.zig:4:7: error: operation caused overflow",
1439 ".tmp_source.zig:2:14: note: called from here");
1440
1441 add_compile_fail_case("mul overflow in function evaluation", R"SOURCE(
1442const y = mul(300, 6000);
1443fn mul(a: u16, b: u16) -> u16 {
1444 a * b
1445}
1446
1447export fn entry() -> usize { @sizeOf(@typeOf(y)) }
1448 )SOURCE", 2,
1449 ".tmp_source.zig:4:7: error: operation caused overflow",
1450 ".tmp_source.zig:2:14: note: called from here");
1451
1452 add_compile_fail_case("truncate sign mismatch", R"SOURCE(
1453fn f() -> i8 {
1454 const x: u32 = 10;
1455 @truncate(i8, x)
1456}
1457
1458export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1459 )SOURCE", 1, ".tmp_source.zig:4:19: error: expected signed integer type, found 'u32'");
1460
1461 add_compile_fail_case("%return in function with non error return type", R"SOURCE(
1462export fn f() {
1463 %return something();
1464}
1465fn something() -> %void { }
1466 )SOURCE", 1,
1467 ".tmp_source.zig:3:5: error: expected type 'void', found 'error'");
1468
1469 add_compile_fail_case("wrong return type for main", R"SOURCE(
1470pub fn main() { }
1471 )SOURCE", 1, ".tmp_source.zig:2:15: error: expected return type of main to be '%void', instead is 'void'");
1472
1473 add_compile_fail_case("double ?? on main return value", R"SOURCE(
1474pub fn main() -> ??void {
1475}
1476 )SOURCE", 1, ".tmp_source.zig:2:18: error: expected return type of main to be '%void', instead is '??void'");
1477
1478 add_compile_fail_case("invalid pointer for var type", R"SOURCE(
1479extern fn ext() -> usize;
1480var bytes: [ext()]u8 = undefined;
1481export fn f() {
1482 for (bytes) |*b, i| {
1483 *b = u8(i);
1484 }
1485}
1486 )SOURCE", 1, ".tmp_source.zig:3:13: error: unable to evaluate constant expression");
1487
1488 add_compile_fail_case("export function with comptime parameter", R"SOURCE(
1489export fn foo(comptime x: i32, y: i32) -> i32{
1490 x + y
1491}
1492 )SOURCE", 1, ".tmp_source.zig:2:15: error: comptime parameter not allowed in extern function");
1493
1494 add_compile_fail_case("extern function with comptime parameter", R"SOURCE(
1495extern fn foo(comptime x: i32, y: i32) -> i32;
1496fn f() -> i32 {
1497 foo(1, 2)
1498}
1499export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1500 )SOURCE", 1, ".tmp_source.zig:2:15: error: comptime parameter not allowed in extern function");
1501
1502 add_compile_fail_case("convert fixed size array to slice with invalid size", R"SOURCE(
1503export fn f() {
1504 var array: [5]u8 = undefined;
1505 var foo = ([]const u32)(array)[0];
1506}
1507 )SOURCE", 1, ".tmp_source.zig:4:28: error: unable to convert [5]u8 to []const u32: size mismatch");
1508
1509 add_compile_fail_case("non-pure function returns type", R"SOURCE(
1510var a: u32 = 0;
1511pub fn List(comptime T: type) -> type {
1512 a += 1;
1513 SmallList(T, 8)
1514}
1515
1516pub fn SmallList(comptime T: type, comptime STATIC_SIZE: usize) -> type {
1517 struct {
1518 items: []T,
1519 length: usize,
1520 prealloc_items: [STATIC_SIZE]T,
1521 }
1522}
1523
1524export fn function_with_return_type_type() {
1525 var list: List(i32) = undefined;
1526 list.length = 10;
1527}
1528
1529 )SOURCE", 2,
1530 ".tmp_source.zig:4:7: error: unable to evaluate constant expression",
1531 ".tmp_source.zig:17:19: note: called from here");
1532
1533 add_compile_fail_case("bogus method call on slice", R"SOURCE(
1534var self = "aoeu";
1535fn f(m: []const u8) {
1536 m.copy(u8, self[0...], m);
1537}
1538export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1539 )SOURCE", 1, ".tmp_source.zig:4:6: error: no member named 'copy' in '[]const u8'");
1540
1541 add_compile_fail_case("wrong number of arguments for method fn call", R"SOURCE(
1542const Foo = struct {
1543 fn method(self: &const Foo, a: i32) {}
1544};
1545fn f(foo: &const Foo) {
1546
1547 foo.method(1, 2);
1548}
1549export fn entry() -> usize { @sizeOf(@typeOf(f)) }
1550 )SOURCE", 1, ".tmp_source.zig:7:15: error: expected 2 arguments, found 3");
1551
1552 add_compile_fail_case("assign through constant pointer", R"SOURCE(
1553export fn f() {
1554 var cstr = c"Hat";
1555 cstr[0] = 'W';
1556}
1557 )SOURCE", 1, ".tmp_source.zig:4:11: error: cannot assign to constant");
1558
1559 add_compile_fail_case("assign through constant slice", R"SOURCE(
1560export fn f() {
1561 var cstr: []const u8 = "Hat";
1562 cstr[0] = 'W';
1563}
1564 )SOURCE", 1, ".tmp_source.zig:4:11: error: cannot assign to constant");
1565
1566 add_compile_fail_case("main function with bogus args type", R"SOURCE(
1567pub fn main(args: [][]bogus) -> %void {}
1568 )SOURCE", 1, ".tmp_source.zig:2:23: error: use of undeclared identifier 'bogus'");
1569
1570 add_compile_fail_case("for loop missing element param", R"SOURCE(
1571fn foo(blah: []u8) {
1572 for (blah) { }
1573}
1574export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1575 )SOURCE", 1, ".tmp_source.zig:3:5: error: for loop expression missing element parameter");
1576
1577 add_compile_fail_case("misspelled type with pointer only reference", R"SOURCE(
1578const JasonHM = u8;
1579const JasonList = &JsonNode;
1580
1581const JsonOA = enum {
1582 JSONArray: JsonList,
1583 JSONObject: JasonHM,
1584};
1585
1586const JsonType = enum {
1587 JSONNull: void,
1588 JSONInteger: isize,
1589 JSONDouble: f64,
1590 JSONBool: bool,
1591 JSONString: []u8,
1592 JSONArray,
1593 JSONObject,
1594};
1595
1596pub const JsonNode = struct {
1597 kind: JsonType,
1598 jobject: ?JsonOA,
1599};
1600
1601fn foo() {
1602 var jll: JasonList = undefined;
1603 jll.init(1234);
1604 var jd = JsonNode {.kind = JsonType.JSONArray , .jobject = JsonOA.JSONArray {jll} };
1605}
1606
1607export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1608 )SOURCE", 1, ".tmp_source.zig:6:16: error: use of undeclared identifier 'JsonList'");
1609
1610 add_compile_fail_case("method call with first arg type primitive", R"SOURCE(
1611const Foo = struct {
1612 x: i32,
1613
1614 fn init(x: i32) -> Foo {
1615 Foo {
1616 .x = x,
1617 }
1618 }
1619};
1620
1621export fn f() {
1622 const derp = Foo.init(3);
1623
1624 derp.init();
1625}
1626 )SOURCE", 1, ".tmp_source.zig:15:5: error: expected type 'i32', found '&const Foo'");
1627
1628 add_compile_fail_case("method call with first arg type wrong container", R"SOURCE(
1629pub const List = struct {
1630 len: usize,
1631 allocator: &Allocator,
1632
1633 pub fn init(allocator: &Allocator) -> List {
1634 List {
1635 .len = 0,
1636 .allocator = allocator,
1637 }
1638 }
1639};
1640
1641pub var global_allocator = Allocator {
1642 .field = 1234,
1643};
1644
1645pub const Allocator = struct {
1646 field: i32,
1647};
1648
1649export fn foo() {
1650 var x = List.init(&global_allocator);
1651 x.init();
1652}
1653 )SOURCE", 1, ".tmp_source.zig:24:5: error: expected type '&Allocator', found '&List'");
1654
1655 add_compile_fail_case("binary not on number literal", R"SOURCE(
1656const TINY_QUANTUM_SHIFT = 4;
1657const TINY_QUANTUM_SIZE = 1 << TINY_QUANTUM_SHIFT;
1658var block_aligned_stuff: usize = (4 + TINY_QUANTUM_SIZE) & ~(TINY_QUANTUM_SIZE - 1);
1659
1660export fn entry() -> usize { @sizeOf(@typeOf(block_aligned_stuff)) }
1661 )SOURCE", 1, ".tmp_source.zig:4:60: error: unable to perform binary not operation on type '(integer literal)'");
1662
1663 {
1664 TestCase *tc = add_compile_fail_case("multiple files with private function error", R"SOURCE(
1665const foo = @import("foo.zig");
1666
1667export fn callPrivFunction() {
1668 foo.privateFunction();
1669}
1670 )SOURCE", 2,
1671 ".tmp_source.zig:5:8: error: 'privateFunction' is private",
1672 "foo.zig:2:1: note: declared here");
1673
1674 add_source_file(tc, "foo.zig", R"SOURCE(
1675fn privateFunction() { }
1676 )SOURCE");
1677 }
1678
1679 add_compile_fail_case("container init with non-type", R"SOURCE(
1680const zero: i32 = 0;
1681const a = zero{1};
1682
1683export fn entry() -> usize { @sizeOf(@typeOf(a)) }
1684 )SOURCE", 1, ".tmp_source.zig:3:11: error: expected type, found 'i32'");
1685
1686 add_compile_fail_case("assign to constant field", R"SOURCE(
1687const Foo = struct {
1688 field: i32,
1689};
1690export fn derp() {
1691 const f = Foo {.field = 1234,};
1692 f.field = 0;
1693}
1694 )SOURCE", 1, ".tmp_source.zig:7:13: error: cannot assign to constant");
1695
1696 add_compile_fail_case("return from defer expression", R"SOURCE(
1697pub fn testTrickyDefer() -> %void {
1698 defer canFail() %% {};
1699
1700 defer %return canFail();
1701
1702 const a = maybeInt() ?? return;
1703}
1704
1705fn canFail() -> %void { }
1706
1707pub fn maybeInt() -> ?i32 {
1708 return 0;
1709}
1710
1711export fn entry() -> usize { @sizeOf(@typeOf(testTrickyDefer)) }
1712 )SOURCE", 1, ".tmp_source.zig:5:11: error: cannot return from defer expression");
1713
1714 add_compile_fail_case("attempt to access var args out of bounds", R"SOURCE(
1715fn add(args: ...) -> i32 {
1716 args[0] + args[1]
1717}
1718
1719fn foo() -> i32 {
1720 add(i32(1234))
1721}
1722
1723export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1724 )SOURCE", 2,
1725 ".tmp_source.zig:3:19: error: index 1 outside argument list of size 1",
1726 ".tmp_source.zig:7:8: note: called from here");
1727
1728 add_compile_fail_case("pass integer literal to var args", R"SOURCE(
1729fn add(args: ...) -> i32 {
1730 var sum = i32(0);
1731 {comptime var i: usize = 0; inline while (i < args.len; i += 1) {
1732 sum += args[i];
1733 }}
1734 return sum;
1735}
1736
1737fn bar() -> i32 {
1738 add(1, 2, 3, 4)
1739}
1740
1741export fn entry() -> usize { @sizeOf(@typeOf(bar)) }
1742 )SOURCE", 1, ".tmp_source.zig:11:9: error: parameter of type '(integer literal)' requires comptime");
1743
1744 add_compile_fail_case("assign too big number to u16", R"SOURCE(
1745export fn foo() {
1746 var vga_mem: u16 = 0xB8000;
1747}
1748 )SOURCE", 1, ".tmp_source.zig:3:24: error: integer value 753664 cannot be implicitly casted to type 'u16'");
1749
1750 add_compile_fail_case("set global variable alignment to non power of 2", R"SOURCE(
1751const some_data: [100]u8 = {
1752 @setGlobalAlign(some_data, 3);
1753 undefined
1754};
1755export fn entry() -> usize { @sizeOf(@typeOf(some_data)) }
1756 )SOURCE", 1, ".tmp_source.zig:3:32: error: alignment value must be power of 2");
1757
1758 add_compile_fail_case("compile log", R"SOURCE(
1759export fn foo() {
1760 comptime bar(12, "hi");
1761}
1762fn bar(a: i32, b: []const u8) {
1763 @compileLog("begin");
1764 @compileLog("a", a, "b", b);
1765 @compileLog("end");
1766}
1767 )SOURCE", 6,
1768 ".tmp_source.zig:6:5: error: found compile log statement",
1769 ".tmp_source.zig:3:17: note: called from here",
1770 ".tmp_source.zig:7:5: error: found compile log statement",
1771 ".tmp_source.zig:3:17: note: called from here",
1772 ".tmp_source.zig:8:5: error: found compile log statement",
1773 ".tmp_source.zig:3:17: note: called from here");
1774
1775 add_compile_fail_case("casting bit offset pointer to regular pointer", R"SOURCE(
1776const u2 = @IntType(false, 2);
1777const u3 = @IntType(false, 3);
1778
1779const BitField = packed struct {
1780 a: u3,
1781 b: u3,
1782 c: u2,
1783};
1784
1785fn foo(bit_field: &const BitField) -> u3 {
1786 return bar(&bit_field.b);
1787}
1788
1789fn bar(x: &const u3) -> u3 {
1790 return *x;
1791}
1792
1793export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1794 )SOURCE", 1, ".tmp_source.zig:12:26: error: expected type '&const u3', found '&:3:6 const u3'");
1795
1796 add_compile_fail_case("referring to a struct that is invalid", R"SOURCE(
1797const UsbDeviceRequest = struct {
1798 Type: u8,
1799};
1800
1801export fn foo() {
1802 comptime assert(@sizeOf(UsbDeviceRequest) == 0x8);
1803}
1804
1805fn assert(ok: bool) {
1806 if (!ok) unreachable;
1807}
1808 )SOURCE", 2,
1809 ".tmp_source.zig:11:14: error: unable to evaluate constant expression",
1810 ".tmp_source.zig:7:20: note: called from here");
1811
1812 add_compile_fail_case("control flow uses comptime var at runtime", R"SOURCE(
1813export fn foo() {
1814 comptime var i = 0;
1815 while (i < 5; i += 1) {
1816 bar();
1817 }
1818}
1819
1820fn bar() { }
1821 )SOURCE", 2,
1822 ".tmp_source.zig:4:5: error: control flow attempts to use compile-time variable at runtime",
1823 ".tmp_source.zig:4:21: note: compile-time variable assigned here");
1824
1825 add_compile_fail_case("ignored return value", R"SOURCE(
1826export fn foo() {
1827 bar();
1828}
1829fn bar() -> i32 { 0 }
1830 )SOURCE", 1, ".tmp_source.zig:3:8: error: return value ignored");
1831
1832 add_compile_fail_case("integer literal on a non-comptime var", R"SOURCE(
1833export fn foo() {
1834 var i = 0;
1835 while (i < 10; i += 1) { }
1836}
1837 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type");
1838
1839 add_compile_fail_case("undefined literal on a non-comptime var", R"SOURCE(
1840export fn foo() {
1841 var i = undefined;
1842 i = i32(1);
1843}
1844 )SOURCE", 1, ".tmp_source.zig:3:5: error: unable to infer variable type");
1845
1846 add_compile_fail_case("dereference an array", R"SOURCE(
1847var s_buffer: [10]u8 = undefined;
1848pub fn pass(in: []u8) -> []u8 {
1849 var out = &s_buffer;
1850 *out[0] = in[0];
1851 return (*out)[0...1];
1852}
1853
1854export fn entry() -> usize { @sizeOf(@typeOf(pass)) }
1855 )SOURCE", 1, ".tmp_source.zig:5:5: error: attempt to dereference non pointer type '[10]u8'");
1856
1857 add_compile_fail_case("pass const ptr to mutable ptr fn", R"SOURCE(
1858fn foo() -> bool {
1859 const a = ([]const u8)("a");
1860 const b = &a;
1861 return ptrEql(b, b);
1862}
1863fn ptrEql(a: &[]const u8, b: &[]const u8) -> bool {
1864 return true;
1865}
1866
1867export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1868 )SOURCE", 1, ".tmp_source.zig:5:19: error: expected type '&[]const u8', found '&const []const u8'");
1869
1870 {
1871 TestCase *tc = add_compile_fail_case("export collision", R"SOURCE(
1872const foo = @import("foo.zig");
1873
1874export fn bar() -> usize {
1875 return foo.baz;
1876}
1877 )SOURCE", 2,
1878 "foo.zig:2:8: error: exported symbol collision: 'bar'",
1879 ".tmp_source.zig:4:8: note: other symbol is here");
1880
1881 add_source_file(tc, "foo.zig", R"SOURCE(
1882export fn bar() {}
1883pub const baz = 1234;
1884 )SOURCE");
1885 }
1886
1887 add_compile_fail_case("pass non-copyable type by value to function", R"SOURCE(
1888const Point = struct { x: i32, y: i32, };
1889fn foo(p: Point) { }
1890export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1891 )SOURCE", 1, ".tmp_source.zig:3:11: error: type 'Point' is not copyable; cannot pass by value");
1892
1893 add_compile_fail_case("implicit cast from array to mutable slice", R"SOURCE(
1894var global_array: [10]i32 = undefined;
1895fn foo(param: []i32) {}
1896export fn entry() {
1897 foo(global_array);
1898}
1899 )SOURCE", 1, ".tmp_source.zig:5:9: error: expected type '[]i32', found '[10]i32'");
1900
1901 add_compile_fail_case("ptrcast to non-pointer", R"SOURCE(
1902export fn entry(a: &i32) -> usize {
1903 return @ptrcast(usize, a);
1904}
1905 )SOURCE", 1, ".tmp_source.zig:3:21: error: expected pointer, found 'usize'");
1906
1907 add_compile_fail_case("too many error values to cast to small integer", R"SOURCE(
1908error A; error B; error C; error D; error E; error F; error G; error H;
1909const u2 = @IntType(false, 2);
1910fn foo(e: error) -> u2 {
1911 return u2(e);
1912}
1913export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
1914 )SOURCE", 1, ".tmp_source.zig:5:14: error: too many error values to fit in 'u2'");
1915
1916 add_compile_fail_case("asm at compile time", R"SOURCE(
1917comptime {
1918 doSomeAsm();
1919}
1920
1921fn doSomeAsm() {
1922 asm volatile (
1923 \\.globl aoeu;
1924 \\.type aoeu, @function;
1925 \\.set aoeu, derp;
1926 );
1927}
1928 )SOURCE", 1, ".tmp_source.zig:7:5: error: unable to evaluate constant expression");
1929
1930 add_compile_fail_case("invalid member of builtin enum", R"SOURCE(
1931export fn entry() {
1932 const foo = Arch.x86;
1933}
1934 )SOURCE", 1, ".tmp_source.zig:3:21: error: container 'Arch' has no member called 'x86'");
1935
1936 add_compile_fail_case("int to ptr of 0 bits", R"SOURCE(
1937export fn foo() {
1938 var x: usize = 0x1000;
1939 var y: &void = @intToPtr(&void, x);
1940}
1941 )SOURCE", 1, ".tmp_source.zig:4:31: error: type '&void' has 0 bits and cannot store information");
1942
1943 add_compile_fail_case("@fieldParentPtr - non struct", R"SOURCE(
1944const Foo = i32;
1945export fn foo(a: &i32) -> &Foo {
1946 return @fieldParentPtr(Foo, "a", a);
1947}
1948 )SOURCE", 1, ".tmp_source.zig:4:28: error: expected struct type, found 'i32'");
1949
1950 add_compile_fail_case("@fieldParentPtr - bad field name", R"SOURCE(
1951const Foo = struct {
1952 derp: i32,
1953};
1954export fn foo(a: &i32) -> &Foo {
1955 return @fieldParentPtr(Foo, "a", a);
1956}
1957 )SOURCE", 1, ".tmp_source.zig:6:33: error: struct 'Foo' has no field 'a'");
1958
1959 add_compile_fail_case("@fieldParentPtr - field pointer is not pointer", R"SOURCE(
1960const Foo = struct {
1961 a: i32,
1962};
1963export fn foo(a: i32) -> &Foo {
1964 return @fieldParentPtr(Foo, "a", a);
1965}
1966 )SOURCE", 1, ".tmp_source.zig:6:38: error: expected pointer, found 'i32'");
1967
1968 add_compile_fail_case("@fieldParentPtr - comptime field ptr not based on struct", R"SOURCE(
1969const Foo = struct {
1970 a: i32,
1971 b: i32,
1972};
1973const foo = Foo { .a = 1, .b = 2, };
1974
1975comptime {
1976 const field_ptr = @intToPtr(&i32, 0x1234);
1977 const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
1978}
1979 )SOURCE", 1, ".tmp_source.zig:10:55: error: pointer value not based on parent struct");
1980
1981 add_compile_fail_case("@fieldParentPtr - comptime wrong field index", R"SOURCE(
1982const Foo = struct {
1983 a: i32,
1984 b: i32,
1985};
1986const foo = Foo { .a = 1, .b = 2, };
1987
1988comptime {
1989 const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
1990}
1991 )SOURCE", 1, ".tmp_source.zig:9:29: error: field 'b' has index 1 but pointer value is index 0 of struct 'Foo'");
1992
1993 add_compile_fail_case_exe("missing main fn in executable", R"SOURCE(
1994 )SOURCE", 1, "error: no member named 'main' in '");
1995
1996 add_compile_fail_case_exe("private main fn", R"SOURCE(
1997fn main() {}
1998 )SOURCE", 2,
1999 "error: 'main' is private",
2000 ".tmp_source.zig:2:1: note: declared here");
2001
2002}
2003
2004//////////////////////////////////////////////////////////////////////////////
2005
2006static void add_parse_error_tests(void) {
2007 add_compile_fail_case("implicit semicolon - block statement", R"SOURCE(
2008export fn entry() {
2009 {}
2010 var good = {};
2011 ({})
2012 var bad = {};
2013}
2014 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2015
2016 add_compile_fail_case("implicit semicolon - block expr", R"SOURCE(
2017export fn entry() {
2018 _ = {};
2019 var good = {};
2020 _ = {}
2021 var bad = {};
2022}
2023 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2024
2025 add_compile_fail_case("implicit semicolon - comptime statement", R"SOURCE(
2026export fn entry() {
2027 comptime {}
2028 var good = {};
2029 comptime ({})
2030 var bad = {};
2031}
2032 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2033
2034 add_compile_fail_case("implicit semicolon - comptime expression", R"SOURCE(
2035export fn entry() {
2036 _ = comptime {};
2037 var good = {};
2038 _ = comptime {}
2039 var bad = {};
2040}
2041 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2042
2043 add_compile_fail_case("implicit semicolon - defer", R"SOURCE(
2044export fn entry() {
2045 defer {}
2046 var good = {};
2047 defer ({})
2048 var bad = {};
2049}
2050 )SOURCE", 1, ".tmp_source.zig:6:5: error: expected token ';', found 'var'");
2051
2052 add_compile_fail_case("implicit semicolon - if statement", R"SOURCE(
2053export fn entry() {
2054 if(true) {}
2055 var good = {};
2056 if(true) ({})
2057 var bad = {};
2058}
2059 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2060
2061 add_compile_fail_case("implicit semicolon - if expression", R"SOURCE(
2062export fn entry() {
2063 _ = if(true) {};
2064 var good = {};
2065 _ = if(true) {}
2066 var bad = {};
2067}
2068 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2069
2070 add_compile_fail_case("implicit semicolon - if-else statement", R"SOURCE(
2071export fn entry() {
2072 if(true) {} else {}
2073 var good = {};
2074 if(true) ({}) else ({})
2075 var bad = {};
2076}
2077 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2078
2079 add_compile_fail_case("implicit semicolon - if-else expression", R"SOURCE(
2080export fn entry() {
2081 _ = if(true) {} else {};
2082 var good = {};
2083 _ = if(true) {} else {}
2084 var bad = {};
2085}
2086 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2087
2088 add_compile_fail_case("implicit semicolon - if-else-if statement", R"SOURCE(
2089export fn entry() {
2090 if(true) {} else if(true) {}
2091 var good = {};
2092 if(true) ({}) else if(true) ({})
2093 var bad = {};
2094}
2095 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2096
2097 add_compile_fail_case("implicit semicolon - if-else-if expression", R"SOURCE(
2098export fn entry() {
2099 _ = if(true) {} else if(true) {};
2100 var good = {};
2101 _ = if(true) {} else if(true) {}
2102 var bad = {};
2103}
2104 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2105
2106 add_compile_fail_case("implicit semicolon - if-else-if-else statement", R"SOURCE(
2107export fn entry() {
2108 if(true) {} else if(true) {} else {}
2109 var good = {};
2110 if(true) ({}) else if(true) ({}) else ({})
2111 var bad = {};
2112}
2113 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2114
2115 add_compile_fail_case("implicit semicolon - if-else-if-else expression", R"SOURCE(
2116export fn entry() {
2117 _ = if(true) {} else if(true) {} else {};
2118 var good = {};
2119 _ = if(true) {} else if(true) {} else {}
2120 var bad = {};
2121}
2122 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2123
2124 add_compile_fail_case("implicit semicolon - if(var) statement", R"SOURCE(
2125export fn entry() {
2126 if(_=foo()) {}
2127 var good = {};
2128 if(_=foo()) ({})
2129 var bad = {};
2130}
2131 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2132
2133 add_compile_fail_case("implicit semicolon - if(var) expression", R"SOURCE(
2134export fn entry() {
2135 _ = if(_=foo()) {};
2136 var good = {};
2137 _ = if(_=foo()) {}
2138 var bad = {};
2139}
2140 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2141
2142 add_compile_fail_case("implicit semicolon - if(var)-else statement", R"SOURCE(
2143export fn entry() {
2144 if(_=foo()) {} else {}
2145 var good = {};
2146 if(_=foo()) ({}) else ({})
2147 var bad = {};
2148}
2149 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2150
2151 add_compile_fail_case("implicit semicolon - if(var)-else expression", R"SOURCE(
2152export fn entry() {
2153 _ = if(_=foo()) {} else {};
2154 var good = {};
2155 _ = if(_=foo()) {} else {}
2156 var bad = {};
2157}
2158 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2159
2160 add_compile_fail_case("implicit semicolon - if(var)-else-if(var) statement", R"SOURCE(
2161export fn entry() {
2162 if(_=foo()) {} else if(_=foo()) {}
2163 var good = {};
2164 if(_=foo()) ({}) else if(_=foo()) ({})
2165 var bad = {};
2166}
2167 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2168
2169 add_compile_fail_case("implicit semicolon - if(var)-else-if(var) expression", R"SOURCE(
2170export fn entry() {
2171 _ = if(_=foo()) {} else if(_=foo()) {};
2172 var good = {};
2173 _ = if(_=foo()) {} else if(_=foo()) {}
2174 var bad = {};
2175}
2176 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2177
2178 add_compile_fail_case("implicit semicolon - if(var)-else-if(var)-else statement", R"SOURCE(
2179export fn entry() {
2180 if(_=foo()) {} else if(_=foo()) {} else {}
2181 var good = {};
2182 if(_=foo()) ({}) else if(_=foo()) ({}) else ({})
2183 var bad = {};
2184}
2185 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2186
2187 add_compile_fail_case("implicit semicolon - if(var)-else-if(var)-else expression", R"SOURCE(
2188export fn entry() {
2189 _ = if(_=foo()) {} else if(_=foo()) {} else {};
2190 var good = {};
2191 _ = if(_=foo()) {} else if(_=foo()) {} else {}
2192 var bad = {};
2193}
2194 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2195
2196 add_compile_fail_case("implicit semicolon - try statement", R"SOURCE(
2197export fn entry() {
2198 try (_ = foo()) {}
2199 var good = {};
2200 try (_ = foo()) ({})
2201 var bad = {};
2202}
2203 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2204
2205 add_compile_fail_case("implicit semicolon - try expression", R"SOURCE(
2206export fn entry() {
2207 _ = try (_ = foo()) {};
2208 var good = {};
2209 _ = try (_ = foo()) {}
2210 var bad = {};
2211}
2212 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2213
2214 add_compile_fail_case("implicit semicolon - while statement", R"SOURCE(
2215export fn entry() {
2216 while(true) {}
2217 var good = {};
2218 while(true) ({})
2219 var bad = {};
2220}
2221 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2222
2223 add_compile_fail_case("implicit semicolon - while expression", R"SOURCE(
2224export fn entry() {
2225 _ = while(true) {};
2226 var good = {};
2227 _ = while(true) {}
2228 var bad = {};
2229}
2230 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2231
2232 add_compile_fail_case("implicit semicolon - while-continue statement", R"SOURCE(
2233export fn entry() {
2234 while(true;{}) {}
2235 var good = {};
2236 while(true;{}) ({})
2237 var bad = {};
2238}
2239 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2240
2241 add_compile_fail_case("implicit semicolon - while-continue expression", R"SOURCE(
2242export fn entry() {
2243 _ = while(true;{}) {};
2244 var good = {};
2245 _ = while(true;{}) {}
2246 var bad = {};
2247}
2248 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2249
2250 add_compile_fail_case("implicit semicolon - for statement", R"SOURCE(
2251export fn entry() {
2252 for(foo()) {}
2253 var good = {};
2254 for(foo()) ({})
2255 var bad = {};
2256}
2257 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2258
2259 add_compile_fail_case("implicit semicolon - for expression", R"SOURCE(
2260export fn entry() {
2261 _ = for(foo()) {};
2262 var good = {};
2263 _ = for(foo()) {}
2264 var bad = {};
2265}
2266 )SOURCE", 1, ".tmp_source.zig:6:5: error: invalid token: 'var'");
2267}
2268
2269//////////////////////////////////////////////////////////////////////////////
2270
2271static void add_debug_safety_test_cases(void) {
2272 add_debug_safety_case("calling panic", R"SOURCE(
2273pub fn panic(message: []const u8) -> noreturn {
2274 @breakpoint();
2275 while (true) {}
2276}
2277pub fn main() -> %void {
2278 @panic("oh no");
2279}
2280 )SOURCE");
2281
2282 add_debug_safety_case("out of bounds slice access", R"SOURCE(
2283pub fn panic(message: []const u8) -> noreturn {
2284 @breakpoint();
2285 while (true) {}
2286}
2287pub fn main() -> %void {
2288 const a = []i32{1, 2, 3, 4};
2289 baz(bar(a));
2290}
2291fn bar(a: []const i32) -> i32 {
2292 a[4]
2293}
2294fn baz(a: i32) { }
2295 )SOURCE");
2296
2297 add_debug_safety_case("integer addition overflow", R"SOURCE(
2298pub fn panic(message: []const u8) -> noreturn {
2299 @breakpoint();
2300 while (true) {}
2301}
2302error Whatever;
2303pub fn main() -> %void {
2304 const x = add(65530, 10);
2305 if (x == 0) return error.Whatever;
2306}
2307fn add(a: u16, b: u16) -> u16 {
2308 a + b
2309}
2310 )SOURCE");
2311
2312 add_debug_safety_case("integer subtraction overflow", R"SOURCE(
2313pub fn panic(message: []const u8) -> noreturn {
2314 @breakpoint();
2315 while (true) {}
2316}
2317error Whatever;
2318pub fn main() -> %void {
2319 const x = sub(10, 20);
2320 if (x == 0) return error.Whatever;
2321}
2322fn sub(a: u16, b: u16) -> u16 {
2323 a - b
2324}
2325 )SOURCE");
2326
2327 add_debug_safety_case("integer multiplication overflow", R"SOURCE(
2328pub fn panic(message: []const u8) -> noreturn {
2329 @breakpoint();
2330 while (true) {}
2331}
2332error Whatever;
2333pub fn main() -> %void {
2334 const x = mul(300, 6000);
2335 if (x == 0) return error.Whatever;
2336}
2337fn mul(a: u16, b: u16) -> u16 {
2338 a * b
2339}
2340 )SOURCE");
2341
2342 add_debug_safety_case("integer negation overflow", R"SOURCE(
2343pub fn panic(message: []const u8) -> noreturn {
2344 @breakpoint();
2345 while (true) {}
2346}
2347error Whatever;
2348pub fn main() -> %void {
2349 const x = neg(-32768);
2350 if (x == 32767) return error.Whatever;
2351}
2352fn neg(a: i16) -> i16 {
2353 -a
2354}
2355 )SOURCE");
2356
2357 add_debug_safety_case("signed integer division overflow", R"SOURCE(
2358pub fn panic(message: []const u8) -> noreturn {
2359 @breakpoint();
2360 while (true) {}
2361}
2362error Whatever;
2363pub fn main() -> %void {
2364 const x = div(-32768, -1);
2365 if (x == 32767) return error.Whatever;
2366}
2367fn div(a: i16, b: i16) -> i16 {
2368 a / b
2369}
2370 )SOURCE");
2371
2372 add_debug_safety_case("signed shift left overflow", R"SOURCE(
2373pub fn panic(message: []const u8) -> noreturn {
2374 @breakpoint();
2375 while (true) {}
2376}
2377error Whatever;
2378pub fn main() -> %void {
2379 const x = shl(-16385, 1);
2380 if (x == 0) return error.Whatever;
2381}
2382fn shl(a: i16, b: i16) -> i16 {
2383 a << b
2384}
2385 )SOURCE");
2386
2387 add_debug_safety_case("unsigned shift left overflow", R"SOURCE(
2388pub fn panic(message: []const u8) -> noreturn {
2389 @breakpoint();
2390 while (true) {}
2391}
2392error Whatever;
2393pub fn main() -> %void {
2394 const x = shl(0b0010111111111111, 3);
2395 if (x == 0) return error.Whatever;
2396}
2397fn shl(a: u16, b: u16) -> u16 {
2398 a << b
2399}
2400 )SOURCE");
2401
2402 add_debug_safety_case("integer division by zero", R"SOURCE(
2403pub fn panic(message: []const u8) -> noreturn {
2404 @breakpoint();
2405 while (true) {}
2406}
2407error Whatever;
2408pub fn main() -> %void {
2409 const x = div0(999, 0);
2410}
2411fn div0(a: i32, b: i32) -> i32 {
2412 a / b
2413}
2414 )SOURCE");
2415
2416 add_debug_safety_case("exact division failure", R"SOURCE(
2417pub fn panic(message: []const u8) -> noreturn {
2418 @breakpoint();
2419 while (true) {}
2420}
2421error Whatever;
2422pub fn main() -> %void {
2423 const x = divExact(10, 3);
2424 if (x == 0) return error.Whatever;
2425}
2426fn divExact(a: i32, b: i32) -> i32 {
2427 @divExact(a, b)
2428}
2429 )SOURCE");
2430
2431 add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(
2432pub fn panic(message: []const u8) -> noreturn {
2433 @breakpoint();
2434 while (true) {}
2435}
2436error Whatever;
2437pub fn main() -> %void {
2438 const x = widenSlice([]u8{1, 2, 3, 4, 5});
2439 if (x.len == 0) return error.Whatever;
2440}
2441fn widenSlice(slice: []const u8) -> []const i32 {
2442 ([]const i32)(slice)
2443}
2444 )SOURCE");
2445
2446 add_debug_safety_case("value does not fit in shortening cast", R"SOURCE(
2447pub fn panic(message: []const u8) -> noreturn {
2448 @breakpoint();
2449 while (true) {}
2450}
2451error Whatever;
2452pub fn main() -> %void {
2453 const x = shorten_cast(200);
2454 if (x == 0) return error.Whatever;
2455}
2456fn shorten_cast(x: i32) -> i8 {
2457 i8(x)
2458}
2459 )SOURCE");
2460
2461 add_debug_safety_case("signed integer not fitting in cast to unsigned integer", R"SOURCE(
2462pub fn panic(message: []const u8) -> noreturn {
2463 @breakpoint();
2464 while (true) {}
2465}
2466error Whatever;
2467pub fn main() -> %void {
2468 const x = unsigned_cast(-10);
2469 if (x == 0) return error.Whatever;
2470}
2471fn unsigned_cast(x: i32) -> u32 {
2472 u32(x)
2473}
2474 )SOURCE");
2475
2476 add_debug_safety_case("unwrap error", R"SOURCE(
2477pub fn panic(message: []const u8) -> noreturn {
2478 @breakpoint();
2479 while (true) {}
2480}
2481error Whatever;
2482pub fn main() -> %void {
2483 %%bar();
2484}
2485fn bar() -> %void {
2486 return error.Whatever;
2487}
2488 )SOURCE");
2489
2490 add_debug_safety_case("cast integer to error and no code matches", R"SOURCE(
2491pub fn panic(message: []const u8) -> noreturn {
2492 @breakpoint();
2493 while (true) {}
2494}
2495pub fn main() -> %void {
2496 _ = bar(9999);
2497}
2498fn bar(x: u32) -> error {
2499 return error(x);
2500}
2501 )SOURCE");
2502}
2503
2504//////////////////////////////////////////////////////////////////////////////
2505
2506static void add_parseh_test_cases(void) {
2507 add_parseh_case("simple data types", AllowWarningsYes, R"SOURCE(
2508#include <stdint.h>
2509int foo(char a, unsigned char b, signed char c);
2510int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
2511void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
2512void baz(int8_t a, int16_t b, int32_t c, int64_t d);
2513 )SOURCE", 3,
2514 "pub extern fn foo(a: u8, b: u8, c: i8) -> c_int;",
2515 "pub extern fn bar(a: u8, b: u16, c: u32, d: u64);",
2516 "pub extern fn baz(a: i8, b: i16, c: i32, d: i64);");
2517
2518 add_parseh_case("noreturn attribute", AllowWarningsNo, R"SOURCE(
2519void foo(void) __attribute__((noreturn));
2520 )SOURCE", 1, R"OUTPUT(pub extern fn foo() -> noreturn;)OUTPUT");
2521
2522 add_parseh_case("enums", AllowWarningsNo, R"SOURCE(
2523enum Foo {
2524 FooA,
2525 FooB,
2526 Foo1,
2527};
2528 )SOURCE", 5, R"(pub const enum_Foo = extern enum {
2529 A,
2530 B,
2531 @"1",
2532};)",
2533 R"(pub const FooA = 0;)",
2534 R"(pub const FooB = 1;)",
2535 R"(pub const Foo1 = 2;)",
2536 R"(pub const Foo = enum_Foo;)");
2537
2538 add_parseh_case("restrict -> noalias", AllowWarningsNo, R"SOURCE(
2539void foo(void *restrict bar, void *restrict);
2540 )SOURCE", 1, R"OUTPUT(pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);)OUTPUT");
2541
2542 add_parseh_case("simple struct", AllowWarningsNo, R"SOURCE(
2543struct Foo {
2544 int x;
2545 char *y;
2546};
2547 )SOURCE", 2,
2548 R"OUTPUT(const struct_Foo = extern struct {
2549 x: c_int,
2550 y: ?&u8,
2551};)OUTPUT", R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
2552
2553 add_parseh_case("qualified struct and enum", AllowWarningsNo, R"SOURCE(
2554struct Foo {
2555 int x;
2556 int y;
2557};
2558enum Bar {
2559 BarA,
2560 BarB,
2561};
2562void func(struct Foo *a, enum Bar **b);
2563 )SOURCE", 7, R"OUTPUT(pub const struct_Foo = extern struct {
2564 x: c_int,
2565 y: c_int,
2566};)OUTPUT", R"OUTPUT(pub const enum_Bar = extern enum {
2567 A,
2568 B,
2569};)OUTPUT",
2570 R"OUTPUT(pub const BarA = 0;)OUTPUT",
2571 R"OUTPUT(pub const BarB = 1;)OUTPUT",
2572 "pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar);",
2573 R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT",
2574 R"OUTPUT(pub const Bar = enum_Bar;)OUTPUT");
2575
2576 add_parseh_case("constant size array", AllowWarningsNo, R"SOURCE(
2577void func(int array[20]);
2578 )SOURCE", 1, "pub extern fn func(array: ?&c_int);");
2579
2580
2581 add_parseh_case("self referential struct with function pointer",
2582 AllowWarningsNo, R"SOURCE(
2583struct Foo {
2584 void (*derp)(struct Foo *foo);
2585};
2586 )SOURCE", 2, R"OUTPUT(pub const struct_Foo = extern struct {
2587 derp: ?extern fn(?&struct_Foo),
2588};)OUTPUT", R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
2589
2590
2591 add_parseh_case("struct prototype used in func", AllowWarningsNo, R"SOURCE(
2592struct Foo;
2593struct Foo *some_func(struct Foo *foo, int x);
2594 )SOURCE", 3, R"OUTPUT(pub const struct_Foo = @OpaqueType();)OUTPUT",
2595 R"OUTPUT(pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;)OUTPUT",
2596 R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
2597
2598
2599 add_parseh_case("#define a char literal", AllowWarningsNo, R"SOURCE(
2600#define A_CHAR 'a'
2601 )SOURCE", 1, R"OUTPUT(pub const A_CHAR = 97;)OUTPUT");
2602
2603
2604 add_parseh_case("#define an unsigned integer literal", AllowWarningsNo,
2605 R"SOURCE(
2606#define CHANNEL_COUNT 24
2607 )SOURCE", 1, R"OUTPUT(pub const CHANNEL_COUNT = 24;)OUTPUT");
2608
2609
2610 add_parseh_case("#define referencing another #define", AllowWarningsNo,
2611 R"SOURCE(
2612#define THING2 THING1
2613#define THING1 1234
2614 )SOURCE", 2,
2615 "pub const THING1 = 1234;",
2616 "pub const THING2 = THING1;");
2617
2618
2619 add_parseh_case("variables", AllowWarningsNo, R"SOURCE(
2620extern int extern_var;
2621static const int int_var = 13;
2622 )SOURCE", 2,
2623 "pub extern var extern_var: c_int;",
2624 "pub const int_var: c_int = 13;");
2625
2626
2627 add_parseh_case("circular struct definitions", AllowWarningsNo, R"SOURCE(
2628struct Bar;
2629
2630struct Foo {
2631 struct Bar *next;
2632};
2633
2634struct Bar {
2635 struct Foo *next;
2636};
2637 )SOURCE", 2,
2638 R"SOURCE(pub const struct_Bar = extern struct {
2639 next: ?&struct_Foo,
2640};)SOURCE",
2641 R"SOURCE(pub const struct_Foo = extern struct {
2642 next: ?&struct_Bar,
2643};)SOURCE");
2644
2645
2646 add_parseh_case("typedef void", AllowWarningsNo, R"SOURCE(
2647typedef void Foo;
2648Foo fun(Foo *a);
2649 )SOURCE", 2,
2650 "pub const Foo = c_void;",
2651 "pub extern fn fun(a: ?&c_void);");
2652
2653 add_parseh_case("generate inline func for #define global extern fn", AllowWarningsNo,
2654 R"SOURCE(
2655extern void (*fn_ptr)(void);
2656#define foo fn_ptr
2657
2658extern char (*fn_ptr2)(int, float);
2659#define bar fn_ptr2
2660 )SOURCE", 4,
2661 "pub extern var fn_ptr: ?extern fn();",
2662 "pub fn foo();",
2663 "pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;",
2664 "pub fn bar(arg0: c_int, arg1: f32) -> u8;");
2665
2666
2667 add_parseh_case("#define string", AllowWarningsNo, R"SOURCE(
2668#define foo "a string"
2669 )SOURCE", 1, "pub const foo: &const u8 = &(c str lit);");
2670
2671 add_parseh_case("__cdecl doesn't mess up function pointers", AllowWarningsNo, R"SOURCE(
2672void foo(void (__cdecl *fn_ptr)(void));
2673 )SOURCE", 1, "pub extern fn foo(fn_ptr: ?extern fn());");
2674
2675 add_parseh_case("comment after integer literal", AllowWarningsNo, R"SOURCE(
2676#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
2677 )SOURCE", 1, "pub const SDL_INIT_VIDEO = 32;");
2678
2679 add_parseh_case("zig keywords in C code", AllowWarningsNo, R"SOURCE(
2680struct comptime {
2681 int defer;
2682};
2683 )SOURCE", 2, R"(pub const struct_comptime = extern struct {
2684 @"defer": c_int,
2685};)", R"(pub const @"comptime" = struct_comptime;)");
2686
2687 add_parseh_case("macro defines string literal with octal", AllowWarningsNo, R"SOURCE(
2688#define FOO "aoeu\023 derp"
2689#define FOO2 "aoeu\0234 derp"
2690#define FOO_CHAR '\077'
2691 )SOURCE", 3,
2692 R"(pub const FOO: &const u8 = &(c str lit);)",
2693 R"(pub const FOO2: &const u8 = &(c str lit);)",
2694 R"(pub const FOO_CHAR = 63;)");
2695}
2696
2697static void run_self_hosted_test(bool is_release_mode) {
2698 Buf self_hosted_tests_file = BUF_INIT;
2699 os_path_join(buf_create_from_str(ZIG_TEST_DIR),
2700 buf_create_from_str("self_hosted.zig"), &self_hosted_tests_file);
2701
2702 Buf zig_stderr = BUF_INIT;
2703 Buf zig_stdout = BUF_INIT;
2704 ZigList<const char *> args = {0};
2705 args.append("test");
2706 args.append(buf_ptr(&self_hosted_tests_file));
2707 if (is_release_mode) {
2708 args.append("--release");
2709 }
2710 Termination term;
2711 os_exec_process(zig_exe, args, &term, &zig_stderr, &zig_stdout);
2712
2713 if (term.how != TerminationIdClean || term.code != 0) {
2714 printf("\nSelf-hosted tests failed:\n");
2715 printf("./zig");
2716 for (size_t i = 0; i < args.length; i += 1) {
2717 printf(" %s", args.at(i));
2718 }
2719 printf("\n%s\n", buf_ptr(&zig_stderr));
2720 exit(1);
2721 }
2722}
2723
2724static void run_std_lib_test(bool is_release_mode) {
2725 Buf std_index_file = BUF_INIT;
2726 os_path_join(buf_create_from_str(ZIG_STD_DIR),
2727 buf_create_from_str("index.zig"), &std_index_file);
2728
2729 Buf zig_stderr = BUF_INIT;
2730 Buf zig_stdout = BUF_INIT;
2731 ZigList<const char *> args = {0};
2732 args.append("test");
2733 args.append(buf_ptr(&std_index_file));
2734 if (is_release_mode) {
2735 args.append("--release");
2736 }
2737 Termination term;
2738 os_exec_process(zig_exe, args, &term, &zig_stderr, &zig_stdout);
2739
2740 if (term.how != TerminationIdClean || term.code != 0) {
2741 printf("\nstd lib tests failed:\n");
2742 printf("./zig");
2743 for (size_t i = 0; i < args.length; i += 1) {
2744 printf(" %s", args.at(i));
2745 }
2746 printf("\n%s\n", buf_ptr(&zig_stderr));
2747 exit(1);
2748 }
2749}
2750
2751
2752static void add_self_hosted_tests(void) {
2753 {
2754 TestCase *test_case = allocate<TestCase>(1);
2755 test_case->case_name = "self hosted tests (debug)";
2756 test_case->special = TestSpecialSelfHosted;
2757 test_case->is_release_mode = false;
2758 test_cases.append(test_case);
2759 }
2760 {
2761 TestCase *test_case = allocate<TestCase>(1);
2762 test_case->case_name = "self hosted tests (release)";
2763 test_case->special = TestSpecialSelfHosted;
2764 test_case->is_release_mode = true;
2765 test_cases.append(test_case);
2766 }
2767}
2768
2769static void add_std_lib_tests(void) {
2770 {
2771 TestCase *test_case = allocate<TestCase>(1);
2772 test_case->case_name = "std (debug)";
2773 test_case->special = TestSpecialStd;
2774 test_case->is_release_mode = false;
2775 test_cases.append(test_case);
2776 }
2777 {
2778 TestCase *test_case = allocate<TestCase>(1);
2779 test_case->case_name = "std (release)";
2780 test_case->special = TestSpecialStd;
2781 test_case->is_release_mode = true;
2782 test_cases.append(test_case);
2783 }
2784}
2785
2786static void add_asm_tests(void) {
2787#if defined(ZIG_OS_LINUX) && defined(ZIG_ARCH_X86_64)
2788 add_asm_case("assemble and link hello world linux x86_64", R"SOURCE(
2789.text
2790.globl _start
2791
2792_start:
2793 mov rax, 1
2794 mov rdi, 1
2795 lea rsi, msg
2796 mov rdx, 14
2797 syscall
2798
2799 mov rax, 60
2800 mov rdi, 0
2801 syscall
2802
2803.data
2804
2805msg:
2806 .ascii "Hello, world!\n"
2807 )SOURCE", "Hello, world!\n");
2808
2809#endif
2810}
2811
2812
2813static void print_compiler_invocation(TestCase *test_case) {
2814 printf("%s", zig_exe);
2815 for (size_t i = 0; i < test_case->compiler_args.length; i += 1) {
2816 printf(" %s", test_case->compiler_args.at(i));
2817 }
2818 printf("\n");
2819}
2820
2821static void print_linker_invocation(TestCase *test_case) {
2822 printf("%s", zig_exe);
2823 for (size_t i = 0; i < test_case->linker_args.length; i += 1) {
2824 printf(" %s", test_case->linker_args.at(i));
2825 }
2826 printf("\n");
2827}
2828
2829
2830static void print_exe_invocation(TestCase *test_case) {
2831 printf("%s", tmp_exe_path);
2832 for (size_t i = 0; i < test_case->program_args.length; i += 1) {
2833 printf(" %s", test_case->program_args.at(i));
2834 }
2835 printf("\n");
2836}
2837
2838static void run_test(TestCase *test_case) {
2839 if (test_case->special == TestSpecialSelfHosted) {
2840 return run_self_hosted_test(test_case->is_release_mode);
2841 } else if (test_case->special == TestSpecialStd) {
2842 return run_std_lib_test(test_case->is_release_mode);
2843 }
2844
2845 for (size_t i = 0; i < test_case->source_files.length; i += 1) {
2846 TestSourceFile *test_source = &test_case->source_files.at(i);
2847 os_write_file(
2848 buf_create_from_str(test_source->relative_path),
2849 buf_create_from_str(test_source->source_code));
2850 }
2851
2852 Buf zig_stderr = BUF_INIT;
2853 Buf zig_stdout = BUF_INIT;
2854 int err;
2855 Termination term;
2856 if ((err = os_exec_process(zig_exe, test_case->compiler_args, &term, &zig_stderr, &zig_stdout))) {
2857 fprintf(stderr, "Unable to exec %s: %s\n", zig_exe, err_str(err));
2858 }
2859
2860 if (!test_case->is_parseh && test_case->compile_errors.length) {
2861 if (term.how != TerminationIdClean || term.code != 0) {
2862 for (size_t i = 0; i < test_case->compile_errors.length; i += 1) {
2863 const char *err_text = test_case->compile_errors.at(i);
2864 if (!strstr(buf_ptr(&zig_stderr), err_text)) {
2865 printf("\n");
2866 printf("========= Expected this compile error: =========\n");
2867 printf("%s\n", err_text);
2868 printf("================================================\n");
2869 print_compiler_invocation(test_case);
2870 printf("%s\n", buf_ptr(&zig_stderr));
2871 exit(1);
2872 }
2873 }
2874 return; // success
2875 } else {
2876 printf("\nCompile failed with return code 0 (Expected failure):\n");
2877 print_compiler_invocation(test_case);
2878 printf("%s\n", buf_ptr(&zig_stderr));
2879 exit(1);
2880 }
2881 }
2882
2883 if (term.how != TerminationIdClean || term.code != 0) {
2884 printf("\nCompile failed:\n");
2885 print_compiler_invocation(test_case);
2886 printf("%s\n", buf_ptr(&zig_stderr));
2887 exit(1);
2888 }
2889
2890 if (test_case->is_parseh) {
2891 if (buf_len(&zig_stderr) > 0) {
2892 printf("\nparseh emitted warnings:\n");
2893 printf("------------------------------\n");
2894 print_compiler_invocation(test_case);
2895 printf("%s\n", buf_ptr(&zig_stderr));
2896 printf("------------------------------\n");
2897 if (test_case->allow_warnings == AllowWarningsNo) {
2898 exit(1);
2899 }
2900 }
2901
2902 for (size_t i = 0; i < test_case->compile_errors.length; i += 1) {
2903 const char *output = test_case->compile_errors.at(i);
2904
2905 if (!strstr(buf_ptr(&zig_stdout), output)) {
2906 printf("\n");
2907 printf("========= Expected this output: =========\n");
2908 printf("%s\n", output);
2909 printf("================================================\n");
2910 print_compiler_invocation(test_case);
2911 printf("%s\n", buf_ptr(&zig_stdout));
2912 exit(1);
2913 }
2914 }
2915 } else {
2916 if (test_case->special == TestSpecialLinkStep) {
2917 Buf link_stderr = BUF_INIT;
2918 Buf link_stdout = BUF_INIT;
2919 int err;
2920 Termination term;
2921 if ((err = os_exec_process(zig_exe, test_case->linker_args, &term, &link_stderr, &link_stdout))) {
2922 fprintf(stderr, "Unable to exec %s: %s\n", zig_exe, err_str(err));
2923 }
2924
2925 if (term.how != TerminationIdClean || term.code != 0) {
2926 printf("\nLink failed:\n");
2927 print_linker_invocation(test_case);
2928 printf("%s\n", buf_ptr(&zig_stderr));
2929 exit(1);
2930 }
2931 }
2932
2933 Buf program_stderr = BUF_INIT;
2934 Buf program_stdout = BUF_INIT;
2935 os_exec_process(tmp_exe_path, test_case->program_args, &term, &program_stderr, &program_stdout);
2936
2937 if (test_case->is_debug_safety) {
2938 int debug_trap_signal = 5;
2939 if (term.how != TerminationIdSignaled || term.code != debug_trap_signal) {
2940 if (term.how == TerminationIdClean) {
2941 printf("\nProgram expected to hit debug trap (signal %d) but exited with return code %d\n",
2942 debug_trap_signal, term.code);
2943 } else if (term.how == TerminationIdSignaled) {
2944 printf("\nProgram expected to hit debug trap (signal %d) but signaled with code %d\n",
2945 debug_trap_signal, term.code);
2946 } else {
2947 printf("\nProgram expected to hit debug trap (signal %d) exited in an unexpected way\n",
2948 debug_trap_signal);
2949 }
2950 print_compiler_invocation(test_case);
2951 print_exe_invocation(test_case);
2952 exit(1);
2953 }
2954 } else {
2955 if (term.how != TerminationIdClean || term.code != 0) {
2956 printf("\nProgram exited with error\n");
2957 print_compiler_invocation(test_case);
2958 print_exe_invocation(test_case);
2959 printf("%s\n", buf_ptr(&program_stderr));
2960 exit(1);
2961 }
2962
2963 if (test_case->output != nullptr && !buf_eql_str(&program_stdout, test_case->output)) {
2964 printf("\n");
2965 print_compiler_invocation(test_case);
2966 print_exe_invocation(test_case);
2967 printf("==== Test failed. Expected output: ====\n");
2968 printf("%s\n", test_case->output);
2969 printf("========= Actual output: ==============\n");
2970 printf("%s\n", buf_ptr(&program_stdout));
2971 printf("=======================================\n");
2972 exit(1);
2973 }
2974 }
2975 }
2976
2977 for (size_t i = 0; i < test_case->source_files.length; i += 1) {
2978 TestSourceFile *test_source = &test_case->source_files.at(i);
2979 remove(test_source->relative_path);
2980 }
2981}
2982
2983static void run_all_tests(const char *grep_text) {
2984 for (size_t i = 0; i < test_cases.length; i += 1) {
2985 TestCase *test_case = test_cases.at(i);
2986 if (grep_text != nullptr && strstr(test_case->case_name, grep_text) == nullptr) {
2987 continue;
2988 }
2989
2990 printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
2991 fflush(stdout);
2992 run_test(test_case);
2993 printf("OK\n");
2994 }
2995 printf("%zu tests passed.\n", test_cases.length);
2996}
2997
2998static void cleanup(void) {
2999 remove(tmp_source_path);
3000 remove(tmp_h_path);
3001 remove(tmp_exe_path);
3002}
3003
3004static int usage(const char *arg0) {
3005 fprintf(stderr, "Usage: %s [--grep text]\n", arg0);
3006 return 1;
3007}
3008
3009int main(int argc, char **argv) {
3010 const char *grep_text = nullptr;
3011 for (int i = 1; i < argc; i += 1) {
3012 const char *arg = argv[i];
3013 if (i + 1 >= argc) {
3014 return usage(argv[0]);
3015 } else {
3016 i += 1;
3017 if (strcmp(arg, "--grep") == 0) {
3018 grep_text = argv[i];
3019 } else {
3020 return usage(argv[0]);
3021 }
3022 }
3023 }
3024 add_compiling_test_cases();
3025 add_build_examples();
3026 add_debug_safety_test_cases();
3027 add_compile_failure_test_cases();
3028 add_parse_error_tests();
3029 add_parseh_test_cases();
3030 add_self_hosted_tests();
3031 add_std_lib_tests();
3032 add_asm_tests();
3033 run_all_tests(grep_text);
3034 cleanup();
3035}
test/self_hosted.zig deleted-39
...@@ -1,39 +0,0 @@
1comptime {
2 _ = @import("cases/array.zig");
3 _ = @import("cases/asm.zig");
4 _ = @import("cases/atomics.zig");
5 _ = @import("cases/bool.zig");
6 _ = @import("cases/cast.zig");
7 _ = @import("cases/const_slice_child.zig");
8 _ = @import("cases/defer.zig");
9 _ = @import("cases/enum.zig");
10 _ = @import("cases/enum_with_members.zig");
11 _ = @import("cases/error.zig");
12 _ = @import("cases/eval.zig");
13 _ = @import("cases/field_parent_ptr.zig");
14 _ = @import("cases/fn.zig");
15 _ = @import("cases/for.zig");
16 _ = @import("cases/generics.zig");
17 _ = @import("cases/goto.zig");
18 _ = @import("cases/if.zig");
19 _ = @import("cases/import.zig");
20 _ = @import("cases/incomplete_struct_param_tld.zig");
21 _ = @import("cases/ir_block_deps.zig");
22 _ = @import("cases/math.zig");
23 _ = @import("cases/misc.zig");
24 _ = @import("cases/namespace_depends_on_compile_var/index.zig");
25 _ = @import("cases/null.zig");
26 _ = @import("cases/pub_enum/index.zig");
27 _ = @import("cases/sizeof_and_typeof.zig");
28 _ = @import("cases/struct.zig");
29 _ = @import("cases/struct_contains_slice_of_itself.zig");
30 _ = @import("cases/switch.zig");
31 _ = @import("cases/switch_prong_err_enum.zig");
32 _ = @import("cases/switch_prong_implicit_cast.zig");
33 _ = @import("cases/this.zig");
34 _ = @import("cases/try.zig");
35 _ = @import("cases/undefined.zig");
36 _ = @import("cases/var_args.zig");
37 _ = @import("cases/void.zig");
38 _ = @import("cases/while.zig");
39}
test/tests.zig created+868
...@@ -0,0 +1,868 @@
1const std = @import("std");
2const debug = std.debug;
3const build = std.build;
4const os = std.os;
5const StdIo = os.ChildProcess.StdIo;
6const Term = os.ChildProcess.Term;
7const Buffer0 = std.cstr.Buffer0;
8const io = std.io;
9const mem = std.mem;
10const fmt = std.fmt;
11const List = std.list.List;
12
13const compare_output = @import("compare_output.zig");
14const build_examples = @import("build_examples.zig");
15const compile_errors = @import("compile_errors.zig");
16const assemble_and_link = @import("assemble_and_link.zig");
17const debug_safety = @import("debug_safety.zig");
18const parseh = @import("parseh.zig");
19
20error TestFailed;
21
22pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
23 const cases = %%b.allocator.create(CompareOutputContext);
24 *cases = CompareOutputContext {
25 .b = b,
26 .step = b.step("test-compare-output", "Run the compare output tests"),
27 .test_index = 0,
28 .test_filter = test_filter,
29 };
30
31 compare_output.addCases(cases);
32
33 return cases.step;
34}
35
36pub fn addDebugSafetyTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
37 const cases = %%b.allocator.create(CompareOutputContext);
38 *cases = CompareOutputContext {
39 .b = b,
40 .step = b.step("test-debug-safety", "Run the debug safety tests"),
41 .test_index = 0,
42 .test_filter = test_filter,
43 };
44
45 debug_safety.addCases(cases);
46
47 return cases.step;
48}
49
50pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
51 const cases = %%b.allocator.create(CompileErrorContext);
52 *cases = CompileErrorContext {
53 .b = b,
54 .step = b.step("test-compile-errors", "Run the compile error tests"),
55 .test_index = 0,
56 .test_filter = test_filter,
57 };
58
59 compile_errors.addCases(cases);
60
61 return cases.step;
62}
63
64pub fn addBuildExampleTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
65 const cases = %%b.allocator.create(BuildExamplesContext);
66 *cases = BuildExamplesContext {
67 .b = b,
68 .step = b.step("test-build-examples", "Build the examples"),
69 .test_index = 0,
70 .test_filter = test_filter,
71 };
72
73 build_examples.addCases(cases);
74
75 return cases.step;
76}
77
78pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
79 const cases = %%b.allocator.create(CompareOutputContext);
80 *cases = CompareOutputContext {
81 .b = b,
82 .step = b.step("test-asm-link", "Run the assemble and link tests"),
83 .test_index = 0,
84 .test_filter = test_filter,
85 };
86
87 assemble_and_link.addCases(cases);
88
89 return cases.step;
90}
91
92pub fn addParseHTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
93 const cases = %%b.allocator.create(ParseHContext);
94 *cases = ParseHContext {
95 .b = b,
96 .step = b.step("test-parseh", "Run the C header file parsing tests"),
97 .test_index = 0,
98 .test_filter = test_filter,
99 };
100
101 parseh.addCases(cases);
102
103 return cases.step;
104}
105
106pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []const u8,
107 name:[] const u8, desc: []const u8) -> &build.Step
108{
109 const step = b.step(b.fmt("test-{}", name), desc);
110 for ([]bool{false, true}) |release| {
111 for ([]bool{false, true}) |link_libc| {
112 const these_tests = b.addTest(root_src);
113 these_tests.setNamePrefix(b.fmt("{}-{}-{} ", name,
114 if (release) "release" else "debug",
115 if (link_libc) "c" else "bare"));
116 these_tests.setFilter(test_filter);
117 these_tests.setRelease(release);
118 if (link_libc) {
119 these_tests.linkLibrary("c");
120 }
121 step.dependOn(&these_tests.step);
122 }
123 }
124 return step;
125}
126
127pub const CompareOutputContext = struct {
128 b: &build.Builder,
129 step: &build.Step,
130 test_index: usize,
131 test_filter: ?[]const u8,
132
133 const Special = enum {
134 None,
135 Asm,
136 DebugSafety,
137 };
138
139 const TestCase = struct {
140 name: []const u8,
141 sources: List(SourceFile),
142 expected_output: []const u8,
143 link_libc: bool,
144 special: Special,
145
146 const SourceFile = struct {
147 filename: []const u8,
148 source: []const u8,
149 };
150
151 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) {
152 %%self.sources.append(SourceFile {
153 .filename = filename,
154 .source = source,
155 });
156 }
157 };
158
159 const RunCompareOutputStep = struct {
160 step: build.Step,
161 context: &CompareOutputContext,
162 exe_path: []const u8,
163 name: []const u8,
164 expected_output: []const u8,
165 test_index: usize,
166
167 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
168 name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep
169 {
170 const allocator = context.b.allocator;
171 const ptr = %%allocator.create(RunCompareOutputStep);
172 *ptr = RunCompareOutputStep {
173 .context = context,
174 .exe_path = exe_path,
175 .name = name,
176 .expected_output = expected_output,
177 .test_index = context.test_index,
178 .step = build.Step.init("RunCompareOutput", allocator, make),
179 };
180 context.test_index += 1;
181 return ptr;
182 }
183
184 fn make(step: &build.Step) -> %void {
185 const self = @fieldParentPtr(RunCompareOutputStep, "step", step);
186 const b = self.context.b;
187
188 const full_exe_path = b.pathFromRoot(self.exe_path);
189
190 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
191
192 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map,
193 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
194 {
195 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
196 };
197
198 const term = child.wait() %% |err| {
199 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
200 };
201 switch (term) {
202 Term.Clean => |code| {
203 if (code != 0) {
204 %%io.stderr.printf("Process {} exited with error code {}\n", full_exe_path, code);
205 return error.TestFailed;
206 }
207 },
208 else => {
209 %%io.stderr.printf("Process {} terminated unexpectedly\n", full_exe_path);
210 return error.TestFailed;
211 },
212 };
213
214 var stdout = %%Buffer0.initEmpty(b.allocator);
215 var stderr = %%Buffer0.initEmpty(b.allocator);
216
217 %%(??child.stdout).readAll(&stdout);
218 %%(??child.stderr).readAll(&stderr);
219
220 if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) {
221 %%io.stderr.printf(
222 \\
223 \\========= Expected this output: =========
224 \\{}
225 \\================================================
226 \\{}
227 \\
228 , self.expected_output, stdout.toSliceConst());
229 return error.TestFailed;
230 }
231 %%io.stderr.printf("OK\n");
232 }
233 };
234
235 const DebugSafetyRunStep = struct {
236 step: build.Step,
237 context: &CompareOutputContext,
238 exe_path: []const u8,
239 name: []const u8,
240 test_index: usize,
241
242 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
243 name: []const u8) -> &DebugSafetyRunStep
244 {
245 const allocator = context.b.allocator;
246 const ptr = %%allocator.create(DebugSafetyRunStep);
247 *ptr = DebugSafetyRunStep {
248 .context = context,
249 .exe_path = exe_path,
250 .name = name,
251 .test_index = context.test_index,
252 .step = build.Step.init("DebugSafetyRun", allocator, make),
253 };
254 context.test_index += 1;
255 return ptr;
256 }
257
258 fn make(step: &build.Step) -> %void {
259 const self = @fieldParentPtr(DebugSafetyRunStep, "step", step);
260 const b = self.context.b;
261
262 const full_exe_path = b.pathFromRoot(self.exe_path);
263
264 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
265
266 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map,
267 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
268 {
269 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
270 };
271
272 const term = child.wait() %% |err| {
273 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
274 };
275
276 const debug_trap_signal: i32 = 5;
277 switch (term) {
278 Term.Clean => |code| {
279 %%io.stderr.printf("\nProgram expected to hit debug trap (signal {}) " ++
280 "but exited with return code {}\n", debug_trap_signal, code);
281 return error.TestFailed;
282 },
283 Term.Signal => |sig| {
284 if (sig != debug_trap_signal) {
285 %%io.stderr.printf("\nProgram expected to hit debug trap (signal {}) " ++
286 "but instead signaled {}\n", debug_trap_signal, sig);
287 return error.TestFailed;
288 }
289 },
290 else => {
291 %%io.stderr.printf("\nProgram expected to hit debug trap (signal {}) " ++
292 " but exited in an unexpected way\n", debug_trap_signal);
293 return error.TestFailed;
294 },
295 }
296
297 %%io.stderr.printf("OK\n");
298 }
299 };
300
301 pub fn createExtra(self: &CompareOutputContext, name: []const u8, source: []const u8,
302 expected_output: []const u8, special: Special) -> TestCase
303 {
304 var tc = TestCase {
305 .name = name,
306 .sources = List(TestCase.SourceFile).init(self.b.allocator),
307 .expected_output = expected_output,
308 .link_libc = false,
309 .special = special,
310 };
311 const root_src_name = if (special == Special.Asm) "source.s" else "source.zig";
312 tc.addSourceFile(root_src_name, source);
313 return tc;
314 }
315
316 pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8,
317 expected_output: []const u8) -> TestCase
318 {
319 return createExtra(self, name, source, expected_output, Special.None);
320 }
321
322 pub fn addC(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) {
323 var tc = self.create(name, source, expected_output);
324 tc.link_libc = true;
325 self.addCase(tc);
326 }
327
328 pub fn add(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) {
329 const tc = self.create(name, source, expected_output);
330 self.addCase(tc);
331 }
332
333 pub fn addAsm(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) {
334 const tc = self.createExtra(name, source, expected_output, Special.Asm);
335 self.addCase(tc);
336 }
337
338 pub fn addDebugSafety(self: &CompareOutputContext, name: []const u8, source: []const u8) {
339 const tc = self.createExtra(name, source, undefined, Special.DebugSafety);
340 self.addCase(tc);
341 }
342
343 pub fn addCase(self: &CompareOutputContext, case: &const TestCase) {
344 const b = self.b;
345
346 const root_src = %%os.path.join(b.allocator, "test_artifacts", case.sources.items[0].filename);
347 const exe_path = %%os.path.join(b.allocator, "test_artifacts", "test");
348
349 switch (case.special) {
350 Special.Asm => {
351 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
352 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "assemble-and-link {}", case.name);
353 if (const filter ?= self.test_filter) {
354 if (mem.indexOf(u8, annotated_case_name, filter) == null)
355 return;
356 }
357
358 const obj = b.addAssemble("test", root_src);
359 obj.setOutputPath(obj_path);
360
361 for (case.sources.toSliceConst()) |src_file| {
362 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
363 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
364 obj.step.dependOn(&write_src.step);
365 }
366
367 const exe = b.addLinkExecutable("test");
368 exe.step.dependOn(&obj.step);
369 exe.addObjectFile(obj_path);
370 exe.setOutputPath(exe_path);
371
372 const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name,
373 case.expected_output);
374 run_and_cmp_output.step.dependOn(&exe.step);
375
376 self.step.dependOn(&run_and_cmp_output.step);
377 },
378 Special.None => {
379 for ([]bool{false, true}) |release| {
380 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} {} ({})",
381 "compare-output", case.name, if (release) "release" else "debug");
382 if (const filter ?= self.test_filter) {
383 if (mem.indexOf(u8, annotated_case_name, filter) == null)
384 continue;
385 }
386
387 const exe = b.addExecutable("test", root_src);
388 exe.setOutputPath(exe_path);
389 exe.setRelease(release);
390 if (case.link_libc) {
391 exe.linkLibrary("c");
392 }
393
394 for (case.sources.toSliceConst()) |src_file| {
395 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
396 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
397 exe.step.dependOn(&write_src.step);
398 }
399
400 const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name,
401 case.expected_output);
402 run_and_cmp_output.step.dependOn(&exe.step);
403
404 self.step.dependOn(&run_and_cmp_output.step);
405 }
406 },
407 Special.DebugSafety => {
408 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
409 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "debug-safety {}", case.name);
410 if (const filter ?= self.test_filter) {
411 if (mem.indexOf(u8, annotated_case_name, filter) == null)
412 return;
413 }
414
415 const exe = b.addExecutable("test", root_src);
416 exe.setOutputPath(exe_path);
417 if (case.link_libc) {
418 exe.linkLibrary("c");
419 }
420
421 for (case.sources.toSliceConst()) |src_file| {
422 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
423 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
424 exe.step.dependOn(&write_src.step);
425 }
426
427 const run_and_cmp_output = DebugSafetyRunStep.create(self, exe_path, annotated_case_name);
428 run_and_cmp_output.step.dependOn(&exe.step);
429
430 self.step.dependOn(&run_and_cmp_output.step);
431 },
432 }
433 }
434};
435
436pub const CompileErrorContext = struct {
437 b: &build.Builder,
438 step: &build.Step,
439 test_index: usize,
440 test_filter: ?[]const u8,
441
442 const TestCase = struct {
443 name: []const u8,
444 sources: List(SourceFile),
445 expected_errors: List([]const u8),
446 link_libc: bool,
447 is_exe: bool,
448
449 const SourceFile = struct {
450 filename: []const u8,
451 source: []const u8,
452 };
453
454 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) {
455 %%self.sources.append(SourceFile {
456 .filename = filename,
457 .source = source,
458 });
459 }
460
461 pub fn addExpectedError(self: &TestCase, text: []const u8) {
462 %%self.expected_errors.append(text);
463 }
464 };
465
466 const CompileCmpOutputStep = struct {
467 step: build.Step,
468 context: &CompileErrorContext,
469 name: []const u8,
470 test_index: usize,
471 case: &const TestCase,
472 release: bool,
473
474 pub fn create(context: &CompileErrorContext, name: []const u8,
475 case: &const TestCase, release: bool) -> &CompileCmpOutputStep
476 {
477 const allocator = context.b.allocator;
478 const ptr = %%allocator.create(CompileCmpOutputStep);
479 *ptr = CompileCmpOutputStep {
480 .step = build.Step.init("CompileCmpOutput", allocator, make),
481 .context = context,
482 .name = name,
483 .test_index = context.test_index,
484 .case = case,
485 .release = release,
486 };
487 context.test_index += 1;
488 return ptr;
489 }
490
491 fn make(step: &build.Step) -> %void {
492 const self = @fieldParentPtr(CompileCmpOutputStep, "step", step);
493 const b = self.context.b;
494
495 const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename);
496 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
497
498 var zig_args = List([]const u8).init(b.allocator);
499 %%zig_args.append(if (self.case.is_exe) "build_exe" else "build_obj");
500 %%zig_args.append(b.pathFromRoot(root_src));
501
502 %%zig_args.append("--name");
503 %%zig_args.append("test");
504
505 %%zig_args.append("--output");
506 %%zig_args.append(b.pathFromRoot(obj_path));
507
508 if (self.release) {
509 %%zig_args.append("--release");
510 }
511
512 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
513
514 if (b.verbose) {
515 printInvocation(b.zig_exe, zig_args.toSliceConst());
516 }
517
518 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map,
519 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
520 {
521 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
522 };
523
524 const term = child.wait() %% |err| {
525 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
526 };
527 switch (term) {
528 Term.Clean => |code| {
529 if (code == 0) {
530 %%io.stderr.printf("Compilation incorrectly succeeded\n");
531 return error.TestFailed;
532 }
533 },
534 else => {
535 %%io.stderr.printf("Process {} terminated unexpectedly\n", b.zig_exe);
536 return error.TestFailed;
537 },
538 };
539
540 var stdout_buf = %%Buffer0.initEmpty(b.allocator);
541 var stderr_buf = %%Buffer0.initEmpty(b.allocator);
542
543 %%(??child.stdout).readAll(&stdout_buf);
544 %%(??child.stderr).readAll(&stderr_buf);
545
546 const stdout = stdout_buf.toSliceConst();
547 const stderr = stderr_buf.toSliceConst();
548
549 if (stdout.len != 0) {
550 %%io.stderr.printf(
551 \\
552 \\Expected empty stdout, instead found:
553 \\================================================
554 \\{}
555 \\================================================
556 \\
557 , stdout);
558 return error.TestFailed;
559 }
560
561 for (self.case.expected_errors.toSliceConst()) |expected_error| {
562 if (mem.indexOf(u8, stderr, expected_error) == null) {
563 %%io.stderr.printf(
564 \\
565 \\========= Expected this compile error: =========
566 \\{}
567 \\================================================
568 \\{}
569 \\
570 , expected_error, stderr);
571 return error.TestFailed;
572 }
573 }
574 %%io.stderr.printf("OK\n");
575 }
576 };
577
578 fn printInvocation(exe_path: []const u8, args: []const []const u8) {
579 %%io.stderr.printf("{}", exe_path);
580 for (args) |arg| {
581 %%io.stderr.printf(" {}", arg);
582 }
583 %%io.stderr.printf("\n");
584 }
585
586 pub fn create(self: &CompileErrorContext, name: []const u8, source: []const u8,
587 expected_lines: ...) -> &TestCase
588 {
589 const tc = %%self.b.allocator.create(TestCase);
590 *tc = TestCase {
591 .name = name,
592 .sources = List(TestCase.SourceFile).init(self.b.allocator),
593 .expected_errors = List([]const u8).init(self.b.allocator),
594 .link_libc = false,
595 .is_exe = false,
596 };
597 tc.addSourceFile(".tmp_source.zig", source);
598 comptime var arg_i = 0;
599 inline while (arg_i < expected_lines.len; arg_i += 1) {
600 // TODO mem.dupe is because of issue #336
601 tc.addExpectedError(%%mem.dupe(self.b.allocator, u8, expected_lines[arg_i]));
602 }
603 return tc;
604 }
605
606 pub fn addC(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) {
607 var tc = self.create(name, source, expected_lines);
608 tc.link_libc = true;
609 self.addCase(tc);
610 }
611
612 pub fn addExe(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) {
613 var tc = self.create(name, source, expected_lines);
614 tc.is_exe = true;
615 self.addCase(tc);
616 }
617
618 pub fn add(self: &CompileErrorContext, name: []const u8, source: []const u8, expected_lines: ...) {
619 const tc = self.create(name, source, expected_lines);
620 self.addCase(tc);
621 }
622
623 pub fn addCase(self: &CompileErrorContext, case: &const TestCase) {
624 const b = self.b;
625
626 for ([]bool{false, true}) |release| {
627 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
628 case.name, if (release) "release" else "debug");
629 if (const filter ?= self.test_filter) {
630 if (mem.indexOf(u8, annotated_case_name, filter) == null)
631 continue;
632 }
633
634 const compile_and_cmp_errors = CompileCmpOutputStep.create(self, annotated_case_name, case, release);
635 self.step.dependOn(&compile_and_cmp_errors.step);
636
637 for (case.sources.toSliceConst()) |src_file| {
638 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
639 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
640 compile_and_cmp_errors.step.dependOn(&write_src.step);
641 }
642 }
643 }
644};
645
646pub const BuildExamplesContext = struct {
647 b: &build.Builder,
648 step: &build.Step,
649 test_index: usize,
650 test_filter: ?[]const u8,
651
652 pub fn addC(self: &BuildExamplesContext, root_src: []const u8) {
653 self.addAllArgs(root_src, true);
654 }
655
656 pub fn add(self: &BuildExamplesContext, root_src: []const u8) {
657 self.addAllArgs(root_src, false);
658 }
659
660 pub fn addAllArgs(self: &BuildExamplesContext, root_src: []const u8, link_libc: bool) {
661 const b = self.b;
662
663 for ([]bool{false, true}) |release| {
664 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "build {} ({})",
665 root_src, if (release) "release" else "debug");
666 if (const filter ?= self.test_filter) {
667 if (mem.indexOf(u8, annotated_case_name, filter) == null)
668 continue;
669 }
670
671 const exe = b.addExecutable("test", root_src);
672 exe.setRelease(release);
673 if (link_libc) {
674 exe.linkLibrary("c");
675 }
676
677 const log_step = b.addLog("PASS {}\n", annotated_case_name);
678 log_step.step.dependOn(&exe.step);
679
680 self.step.dependOn(&log_step.step);
681 }
682 }
683};
684
685pub const ParseHContext = struct {
686 b: &build.Builder,
687 step: &build.Step,
688 test_index: usize,
689 test_filter: ?[]const u8,
690
691 const TestCase = struct {
692 name: []const u8,
693 sources: List(SourceFile),
694 expected_lines: List([]const u8),
695 allow_warnings: bool,
696
697 const SourceFile = struct {
698 filename: []const u8,
699 source: []const u8,
700 };
701
702 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) {
703 %%self.sources.append(SourceFile {
704 .filename = filename,
705 .source = source,
706 });
707 }
708
709 pub fn addExpectedError(self: &TestCase, text: []const u8) {
710 %%self.expected_lines.append(text);
711 }
712 };
713
714 const ParseHCmpOutputStep = struct {
715 step: build.Step,
716 context: &ParseHContext,
717 name: []const u8,
718 test_index: usize,
719 case: &const TestCase,
720
721 pub fn create(context: &ParseHContext, name: []const u8, case: &const TestCase) -> &ParseHCmpOutputStep {
722 const allocator = context.b.allocator;
723 const ptr = %%allocator.create(ParseHCmpOutputStep);
724 *ptr = ParseHCmpOutputStep {
725 .step = build.Step.init("ParseHCmpOutput", allocator, make),
726 .context = context,
727 .name = name,
728 .test_index = context.test_index,
729 .case = case,
730 };
731 context.test_index += 1;
732 return ptr;
733 }
734
735 fn make(step: &build.Step) -> %void {
736 const self = @fieldParentPtr(ParseHCmpOutputStep, "step", step);
737 const b = self.context.b;
738
739 const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename);
740
741 var zig_args = List([]const u8).init(b.allocator);
742 %%zig_args.append("parseh");
743 %%zig_args.append(b.pathFromRoot(root_src));
744
745 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
746
747 if (b.verbose) {
748 printInvocation(b.zig_exe, zig_args.toSliceConst());
749 }
750
751 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map,
752 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
753 {
754 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
755 };
756
757 const term = child.wait() %% |err| {
758 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
759 };
760 switch (term) {
761 Term.Clean => |code| {
762 if (code != 0) {
763 %%io.stderr.printf("Compilation failed with exit code {}\n", code);
764 return error.TestFailed;
765 }
766 },
767 Term.Signal => |code| {
768 %%io.stderr.printf("Compilation failed with signal {}\n", code);
769 return error.TestFailed;
770 },
771 else => {
772 %%io.stderr.printf("Compilation terminated unexpectedly\n");
773 return error.TestFailed;
774 },
775 };
776
777 var stdout_buf = %%Buffer0.initEmpty(b.allocator);
778 var stderr_buf = %%Buffer0.initEmpty(b.allocator);
779
780 %%(??child.stdout).readAll(&stdout_buf);
781 %%(??child.stderr).readAll(&stderr_buf);
782
783 const stdout = stdout_buf.toSliceConst();
784 const stderr = stderr_buf.toSliceConst();
785
786 if (stderr.len != 0 and !self.case.allow_warnings) {
787 %%io.stderr.printf(
788 \\====== parseh emitted warnings: ============
789 \\{}
790 \\============================================
791 \\
792 , stderr);
793 return error.TestFailed;
794 }
795
796 for (self.case.expected_lines.toSliceConst()) |expected_line| {
797 if (mem.indexOf(u8, stdout, expected_line) == null) {
798 %%io.stderr.printf(
799 \\
800 \\========= Expected this output: ================
801 \\{}
802 \\================================================
803 \\{}
804 \\
805 , expected_line, stdout);
806 return error.TestFailed;
807 }
808 }
809 %%io.stderr.printf("OK\n");
810 }
811 };
812
813 fn printInvocation(exe_path: []const u8, args: []const []const u8) {
814 %%io.stderr.printf("{}", exe_path);
815 for (args) |arg| {
816 %%io.stderr.printf(" {}", arg);
817 }
818 %%io.stderr.printf("\n");
819 }
820
821 pub fn create(self: &ParseHContext, allow_warnings: bool, name: []const u8,
822 source: []const u8, expected_lines: ...) -> &TestCase
823 {
824 const tc = %%self.b.allocator.create(TestCase);
825 *tc = TestCase {
826 .name = name,
827 .sources = List(TestCase.SourceFile).init(self.b.allocator),
828 .expected_lines = List([]const u8).init(self.b.allocator),
829 .allow_warnings = allow_warnings,
830 };
831 tc.addSourceFile("source.h", source);
832 comptime var arg_i = 0;
833 inline while (arg_i < expected_lines.len; arg_i += 1) {
834 // TODO mem.dupe is because of issue #336
835 tc.addExpectedError(%%mem.dupe(self.b.allocator, u8, expected_lines[arg_i]));
836 }
837 return tc;
838 }
839
840 pub fn add(self: &ParseHContext, name: []const u8, source: []const u8, expected_lines: ...) {
841 const tc = self.create(false, name, source, expected_lines);
842 self.addCase(tc);
843 }
844
845 pub fn addAllowWarnings(self: &ParseHContext, name: []const u8, source: []const u8, expected_lines: ...) {
846 const tc = self.create(true, name, source, expected_lines);
847 self.addCase(tc);
848 }
849
850 pub fn addCase(self: &ParseHContext, case: &const TestCase) {
851 const b = self.b;
852
853 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "parseh {}", case.name);
854 if (const filter ?= self.test_filter) {
855 if (mem.indexOf(u8, annotated_case_name, filter) == null)
856 return;
857 }
858
859 const parseh_and_cmp = ParseHCmpOutputStep.create(self, annotated_case_name, case);
860 self.step.dependOn(&parseh_and_cmp.step);
861
862 for (case.sources.toSliceConst()) |src_file| {
863 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
864 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
865 parseh_and_cmp.step.dependOn(&write_src.step);
866 }
867 }
868};