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
6363 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
6464)
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
7466set(C_HEADERS
7567 "${CMAKE_SOURCE_DIR}/c_headers/Intrin.h"
7668 "${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
248240install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
249241install(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
258243if (ZIG_TEST_COVERAGE)
259244 add_custom_target(coverage
260245 DEPENDS run_tests
261246 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
262247 COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1
263 COMMAND ./run_tests
248 COMMAND ./zig build --build-file ../build.zig test
264249 COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1
265250 COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1
266251 COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1
README.md+3-3
......@@ -45,8 +45,8 @@ compromises backward compatibility.
4545 * Release mode produces heavily optimized code. What other projects call
4646 "Link Time Optimization" Zig does automatically.
4747 * Mark functions as tests and automatically run them with `zig test`.
48 * Currently supported architectures: `x86_64`, `i386`
49 * Currently supported operating systems: linux, macosx
48 * Currently supported architectures: `x86_64`
49 * Currently supported operating systems: linux
5050 * Friendly toward package maintainers. Reproducible build, bootstrapping
5151 process carefully documented. Issues filed by package maintainers are
5252 considered especially important.
......@@ -103,7 +103,7 @@ cd build
103103cmake .. -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))
104104make
105105make install
106./run_tests
106./zig build --build-file ../build.zig test
107107```
108108
109109### 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 {
14581458 ZigList<Buf *> link_objects;
14591459
14601460 ZigList<TypeTableEntry *> name_table_enums;
1461
1462 Buf *test_filter;
1463 Buf *test_name_prefix;
14611464};
14621465
14631466enum VarLinkage {
src/analyze.cpp+8-1
......@@ -1959,7 +1959,14 @@ static void preview_test_decl(CodeGen *g, AstNode *node, ScopeDecls *decls_scope
19591959 if (import->package != g->root_package)
19601960 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
19641971 TldFn *tld_fn = allocate<TldFn>(1);
19651972 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) {
147147 g->omit_zigrt = omit_zigrt;
148148}
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
150158void codegen_set_is_test(CodeGen *g, bool is_test_build) {
151159 g->is_test_build = is_test_build;
152160}
src/codegen.hpp+2
......@@ -44,6 +44,8 @@ void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);
4444void codegen_set_mios_version_min(CodeGen *g, Buf *mios_version_min);
4545void codegen_set_linker_script(CodeGen *g, const char *linker_script);
4646void 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
4850PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);
4951void 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) {
770770 if (g->want_h_file) {
771771 codegen_generate_h_file(g);
772772 }
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 }
773781 if (g->verbose) {
774782 fprintf(stderr, "OK\n");
775783 }
src/main.cpp+28-5
......@@ -64,6 +64,9 @@ static int usage(const char *arg0) {
6464 " -mwindows (windows only) --subsystem windows to the linker\n"
6565 " -rdynamic add all symbols to the dynamic symbol table\n"
6666 " -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"
6770 , arg0);
6871 return EXIT_FAILURE;
6972}
......@@ -151,6 +154,8 @@ int main(int argc, char **argv) {
151154 ZigList<const char *> rpath_list = {0};
152155 bool each_lib_rpath = false;
153156 ZigList<const char *> objects = {0};
157 const char *test_filter = nullptr;
158 const char *test_name_prefix = nullptr;
154159
155160 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
156161 const char *zig_exe_path = arg0;
......@@ -168,6 +173,7 @@ int main(int argc, char **argv) {
168173
169174 ZigList<const char *> args = {0};
170175 args.append(zig_exe_path);
176 args.append(NULL); // placeholder
171177 for (int i = 2; i < argc; i += 1) {
172178 if (strcmp(argv[i], "--debug-build-verbose") == 0) {
173179 verbose = true;
......@@ -202,6 +208,8 @@ int main(int argc, char **argv) {
202208 Buf build_file_dirname = BUF_INIT;
203209 os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename);
204210
211 args.items[1] = buf_ptr(&build_file_dirname);
212
205213 bool build_file_exists;
206214 if ((err = os_file_exists(&build_file_abs, &build_file_exists))) {
207215 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) {
214222 "Usage: %s build [options]\n"
215223 "\n"
216224 "General Options:\n"
217 " --help Print this help and exit.\n"
218 " --build-file [file] Override path to build.zig.\n"
219 " --verbose Print commands before executing them.\n"
220 " --debug-build-verbose Print verbose debugging information for the build system itself.\n"
221 " --prefix [prefix] Override default install prefix.\n"
225 " --help Print this help and exit\n"
226 " --build-file [file] Override path to build.zig\n"
227 " --verbose Print commands before executing them\n"
228 " --debug-build-verbose Print verbose debugging information for the build system itself\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"
222233 , zig_exe_path);
223234 return 0;
224235 }
......@@ -335,6 +346,10 @@ int main(int argc, char **argv) {
335346 linker_script = argv[i];
336347 } else if (strcmp(arg, "-rpath") == 0) {
337348 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];
338353 } else {
339354 fprintf(stderr, "Invalid argument: %s\n", arg);
340355 return usage(arg0);
......@@ -556,6 +571,14 @@ int main(int argc, char **argv) {
556571 codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min));
557572 }
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
559582 if (cmd == CmdBuild) {
560583 codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
561584 codegen_link(g, out_file);
src/os.cpp+7
......@@ -683,3 +683,10 @@ int os_delete_file(Buf *path) {
683683void os_init(void) {
684684 srand((unsigned)time(NULL));
685685}
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);
5555
5656int os_file_exists(Buf *full_path, bool *result);
5757
58int os_rename(Buf *src_path, Buf *dest_path);
59
5860#if defined(__APPLE__)
5961#define ZIG_OS_DARWIN
6062#elif defined(_WIN32)
std/build.zig+619-58
......@@ -10,13 +10,14 @@ const StdIo = os.ChildProcess.StdIo;
1010const Term = os.ChildProcess.Term;
1111const BufSet = @import("buf_set.zig").BufSet;
1212const BufMap = @import("buf_map.zig").BufMap;
13const fmt = @import("fmt.zig");
13const fmt_lib = @import("fmt.zig");
1414
1515error ExtraArg;
1616error UncleanExit;
1717error InvalidStepName;
1818error DependencyLoopDetected;
1919error NoCompilerFound;
20error NeedAnObject;
2021
2122pub const Builder = struct {
2223 uninstall_tls: TopLevelStep,
......@@ -38,6 +39,7 @@ pub const Builder = struct {
3839 lib_dir: []const u8,
3940 out_dir: []u8,
4041 installed_files: List([]const u8),
42 build_root: []const u8,
4143
4244 const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8);
4345 const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8);
......@@ -73,8 +75,10 @@ pub const Builder = struct {
7375 description: []const u8,
7476 };
7577
76 pub fn init(allocator: &Allocator) -> Builder {
78 pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8) -> Builder {
7779 var self = Builder {
80 .zig_exe = zig_exe,
81 .build_root = build_root,
7882 .verbose = false,
7983 .invalid_user_input = false,
8084 .allocator = allocator,
......@@ -85,7 +89,6 @@ pub const Builder = struct {
8589 .available_options_map = AvailableOptionsMap.init(allocator),
8690 .available_options_list = List(AvailableOption).init(allocator),
8791 .top_level_steps = List(&TopLevelStep).init(allocator),
88 .zig_exe = undefined,
8992 .default_step = undefined,
9093 .env_map = %%os.getEnvMap(allocator),
9194 .prefix = undefined,
......@@ -123,6 +126,36 @@ pub const Builder = struct {
123126 return exe;
124127 }
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
126159 pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary {
127160 const lib = %%self.allocator.create(CLibrary);
128161 *lib = CLibrary.initStatic(self, name);
......@@ -149,6 +182,25 @@ pub const Builder = struct {
149182 return cmd;
150183 }
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
152204 pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version {
153205 Version {
154206 .major = major,
......@@ -197,9 +249,8 @@ pub const Builder = struct {
197249 }
198250
199251 fn makeUninstall(uninstall_step: &Step) -> %void {
200 // TODO
201 // const self = @fieldParentPtr(Exe, "step", step);
202 const self = @ptrcast(&Builder, uninstall_step);
252 const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step);
253 const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls);
203254
204255 for (self.installed_files.toSliceConst()) |installed_file| {
205256 _ = os.deleteFile(self.allocator, installed_file);
......@@ -278,7 +329,7 @@ pub const Builder = struct {
278329 }
279330
280331 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);
282333 const available_option = AvailableOption {
283334 .name = name,
284335 .type_id = type_id,
......@@ -313,7 +364,19 @@ pub const Builder = struct {
313364 },
314365 TypeId.Int => debug.panic("TODO integer options to build script"),
315366 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 },
317380 TypeId.List => debug.panic("TODO list options to build script"),
318381 }
319382 }
......@@ -482,6 +545,14 @@ pub const Builder = struct {
482545 debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err));
483546 };
484547 }
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 }
485556};
486557
487558const Version = struct {
......@@ -510,6 +581,17 @@ const Target = enum {
510581 else => ".o",
511582 };
512583 }
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 }
513595};
514596
515597const LinkerScript = enum {
......@@ -518,7 +600,7 @@ const LinkerScript = enum {
518600 Path: []const u8,
519601};
520602
521const Exe = struct {
603pub const Exe = struct {
522604 step: Step,
523605 builder: &Builder,
524606 root_src: []const u8,
......@@ -528,6 +610,7 @@ const Exe = struct {
528610 link_libs: BufSet,
529611 verbose: bool,
530612 release: bool,
613 output_path: ?[]const u8,
531614
532615 pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe {
533616 Exe {
......@@ -540,6 +623,7 @@ const Exe = struct {
540623 .linker_script = LinkerScript.None,
541624 .link_libs = BufSet.init(builder.allocator),
542625 .step = Step.init(name, builder.allocator, make),
626 .output_path = null,
543627 }
544628 }
545629
......@@ -579,6 +663,10 @@ const Exe = struct {
579663 self.release = value;
580664 }
581665
666 pub fn setOutputPath(self: &Exe, value: []const u8) {
667 self.output_path = value;
668 }
669
582670 fn make(step: &Step) -> %void {
583671 const exe = @fieldParentPtr(Exe, "step", step);
584672 const builder = exe.builder;
......@@ -586,31 +674,36 @@ const Exe = struct {
586674 var zig_args = List([]const u8).init(builder.allocator);
587675 defer zig_args.deinit();
588676
589 %return zig_args.append("build_exe");
590 %return zig_args.append(exe.root_src);
677 %%zig_args.append("build_exe");
678 %%zig_args.append(builder.pathFromRoot(exe.root_src));
591679
592680 if (exe.verbose) {
593 %return zig_args.append("--verbose");
681 %%zig_args.append("--verbose");
594682 }
595683
596684 if (exe.release) {
597 %return zig_args.append("--release");
685 %%zig_args.append("--release");
598686 }
599687
600 %return zig_args.append("--name");
601 %return zig_args.append(exe.name);
688 if (const output_path ?= exe.output_path) {
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
603696 switch (exe.target) {
604697 Target.Native => {},
605698 Target.Cross => |cross_target| {
606 %return zig_args.append("--target-arch");
607 %return zig_args.append(@enumTagName(cross_target.arch));
699 %%zig_args.append("--target-arch");
700 %%zig_args.append(@enumTagName(cross_target.arch));
608701
609 %return zig_args.append("--target-os");
610 %return zig_args.append(@enumTagName(cross_target.os));
702 %%zig_args.append("--target-os");
703 %%zig_args.append(@enumTagName(cross_target.os));
611704
612 %return zig_args.append("--target-environ");
613 %return zig_args.append(@enumTagName(cross_target.environ));
705 %%zig_args.append("--target-environ");
706 %%zig_args.append(@enumTagName(cross_target.environ));
614707 },
615708 }
616709
......@@ -620,12 +713,12 @@ const Exe = struct {
620713 const tmp_file_name = "linker.ld.tmp"; // TODO issue #298
621714 io.writeFile(tmp_file_name, script, builder.allocator)
622715 %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err));
623 %return zig_args.append("--linker-script");
624 %return zig_args.append(tmp_file_name);
716 %%zig_args.append("--linker-script");
717 %%zig_args.append(tmp_file_name);
625718 },
626719 LinkerScript.Path => |path| {
627 %return zig_args.append("--linker-script");
628 %return zig_args.append(path);
720 %%zig_args.append("--linker-script");
721 %%zig_args.append(path);
629722 },
630723 }
631724
......@@ -633,31 +726,432 @@ const Exe = struct {
633726 var it = exe.link_libs.iterator();
634727 while (true) {
635728 const entry = it.next() ?? break;
636 %return zig_args.append("--library");
637 %return zig_args.append(entry.key);
729 %%zig_args.append("--library");
730 %%zig_args.append(entry.key);
638731 }
639732 }
640733
641734 for (builder.include_paths.toSliceConst()) |include_path| {
642 %return zig_args.append("-isystem");
643 %return zig_args.append(include_path);
735 %%zig_args.append("-isystem");
736 %%zig_args.append(include_path);
644737 }
645738
646739 for (builder.rpaths.toSliceConst()) |rpath| {
647 %return zig_args.append("-rpath");
648 %return zig_args.append(rpath);
740 %%zig_args.append("-rpath");
741 %%zig_args.append(rpath);
649742 }
650743
651744 for (builder.lib_paths.toSliceConst()) |lib_path| {
652 %return zig_args.append("--library-path");
653 %return zig_args.append(lib_path);
745 %%zig_args.append("--library-path");
746 %%zig_args.append(lib_path);
654747 }
655748
656749 builder.spawnChild(builder.zig_exe, zig_args.toSliceConst());
657750 }
658751};
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 {
6611155 step: Step,
6621156 name: []const u8,
6631157 out_filename: []const u8,
......@@ -678,7 +1172,7 @@ const CLibrary = struct {
6781172 }
6791173
6801174 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);
6821176 }
6831177
6841178 fn init(builder: &Builder, name: []const u8, version: &const Version, static: bool) -> CLibrary {
......@@ -704,14 +1198,12 @@ const CLibrary = struct {
7041198
7051199 fn computeOutFileName(self: &CLibrary) {
7061200 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);
7081202 } 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}",
7101204 self.name, self.version.major, self.version.minor, self.version.patch);
711 self.major_only_filename = %%fmt.allocPrint(self.builder.allocator,
712 "lib{}.so.{d}", self.name, self.version.major);
713 self.name_only_filename = %%fmt.allocPrint(self.builder.allocator,
714 "lib{}.so", self.name);
1205 self.major_only_filename = self.builder.fmt("lib{}.so.{d}", self.name, self.version.major);
1206 self.name_only_filename = self.builder.fmt("lib{}.so", self.name);
7151207 }
7161208 }
7171209
......@@ -770,7 +1262,7 @@ const CLibrary = struct {
7701262 %%cc_args.append(source_file);
7711263
7721264 // 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());
7741266 defer builder.allocator.free(o_file);
7751267 %%cc_args.append("-o");
7761268 %%cc_args.append(o_file);
......@@ -797,8 +1289,7 @@ const CLibrary = struct {
7971289 %%cc_args.append("-fPIC");
7981290 %%cc_args.append("-shared");
7991291
800 const soname_arg = %%fmt.allocPrint(builder.allocator, "-Wl,-soname,lib{}.so.{d}",
801 self.name, self.version.major);
1292 const soname_arg = builder.fmt("-Wl,-soname,lib{}.so.{d}", self.name, self.version.major);
8021293 defer builder.allocator.free(soname_arg);
8031294 %%cc_args.append(soname_arg);
8041295
......@@ -806,7 +1297,7 @@ const CLibrary = struct {
8061297 %%cc_args.append(self.out_filename);
8071298
8081299 for (self.object_files.toSliceConst()) |object_file| {
809 %%cc_args.append(object_file);
1300 %%cc_args.append(builder.pathFromRoot(object_file));
8101301 }
8111302
8121303 builder.spawnChild(cc, cc_args.toSliceConst());
......@@ -829,7 +1320,7 @@ const CLibrary = struct {
8291320 }
8301321};
8311322
832const CExecutable = struct {
1323pub const CExecutable = struct {
8331324 step: Step,
8341325 builder: &Builder,
8351326 name: []const u8,
......@@ -907,7 +1398,7 @@ const CExecutable = struct {
9071398 %%cc_args.append(source_file);
9081399
9091400 // 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());
9111402 defer builder.allocator.free(o_file);
9121403 %%cc_args.append("-o");
9131404 %%cc_args.append(o_file);
......@@ -935,7 +1426,7 @@ const CExecutable = struct {
9351426 %%cc_args.append("-o");
9361427 %%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);
9391430 defer builder.allocator.free(rpath_arg);
9401431 %%cc_args.append(rpath_arg);
9411432
......@@ -959,7 +1450,7 @@ const CExecutable = struct {
9591450 }
9601451};
9611452
962const CommandStep = struct {
1453pub const CommandStep = struct {
9631454 step: Step,
9641455 builder: &Builder,
9651456 exe_path: []const u8,
......@@ -988,7 +1479,7 @@ const CommandStep = struct {
9881479 }
9891480};
9901481
991const InstallCLibraryStep = struct {
1482pub const InstallCLibraryStep = struct {
9921483 step: Step,
9931484 builder: &Builder,
9941485 lib: &CLibrary,
......@@ -997,9 +1488,7 @@ const InstallCLibraryStep = struct {
9971488 pub fn init(builder: &Builder, lib: &CLibrary) -> InstallCLibraryStep {
9981489 var self = InstallCLibraryStep {
9991490 .builder = builder,
1000 .step = Step.init(
1001 %%fmt.allocPrint(builder.allocator, "install {}", lib.step.name),
1002 builder.allocator, make),
1491 .step = Step.init(builder.fmt("install {}", lib.step.name), builder.allocator, make),
10031492 .lib = lib,
10041493 .dest_file = undefined,
10051494 };
......@@ -1023,7 +1512,7 @@ const InstallCLibraryStep = struct {
10231512 }
10241513};
10251514
1026const InstallFileStep = struct {
1515pub const InstallFileStep = struct {
10271516 step: Step,
10281517 builder: &Builder,
10291518 src_path: []const u8,
......@@ -1032,9 +1521,7 @@ const InstallFileStep = struct {
10321521 pub fn init(builder: &Builder, src_path: []const u8, dest_path: []const u8) -> InstallFileStep {
10331522 return InstallFileStep {
10341523 .builder = builder,
1035 .step = Step.init(
1036 %%fmt.allocPrint(builder.allocator, "install {}", src_path),
1037 builder.allocator, make),
1524 .step = Step.init(builder.fmt("install {}", src_path), builder.allocator, make),
10381525 .src_path = src_path,
10391526 .dest_path = dest_path,
10401527 };
......@@ -1047,7 +1534,81 @@ const InstallFileStep = struct {
10471534 }
10481535};
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 {
10511612 name: []const u8,
10521613 makeFn: fn(self: &Step) -> %void,
10531614 dependencies: List(&Step),
std/io.zig+4-6
......@@ -57,8 +57,6 @@ error NoMem;
5757error Unseekable;
5858error Eof;
5959
60const buffer_size = 4 * 1024;
61
6260pub const OpenRead = 0b0001;
6361pub const OpenWrite = 0b0010;
6462pub const OpenCreate = 0b0100;
......@@ -66,7 +64,7 @@ pub const OpenTruncate = 0b1000;
6664
6765pub const OutStream = struct {
6866 fd: i32,
69 buffer: [buffer_size]u8,
67 buffer: [os.page_size]u8,
7068 index: usize,
7169
7270 /// `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 {
9795 }
9896
9997 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
100 if (bytes.len >= buffer_size) {
98 if (bytes.len >= self.buffer.len) {
10199 %return self.flush();
102100 return os.posixWrite(self.fd, bytes);
103101 }
......@@ -329,7 +327,7 @@ pub const InStream = struct {
329327 }
330328
331329 pub fn readAll(is: &InStream, buf: &Buffer0) -> %void {
332 %return buf.resize(buffer_size);
330 %return buf.resize(os.page_size);
333331
334332 var actual_buf_len: usize = 0;
335333 while (true) {
......@@ -341,7 +339,7 @@ pub const InStream = struct {
341339 return buf.resize(actual_buf_len);
342340 }
343341
344 %return buf.resize(actual_buf_len + buffer_size);
342 %return buf.resize(actual_buf_len + os.page_size);
345343 }
346344 }
347345};
std/list.zig+9-1
......@@ -61,10 +61,15 @@ pub fn List(comptime T: type) -> type{
6161 l.len = new_length;
6262 return result;
6363 }
64
65 pub fn pop(self: &Self) -> T {
66 self.len -= 1;
67 return self.items[self.len];
68 }
6469 }
6570}
6671
67test "basicListTest" {
72test "basic list test" {
6873 var list = List(i32).init(&debug.global_allocator);
6974 defer list.deinit();
7075
......@@ -75,4 +80,7 @@ test "basicListTest" {
7580 {var i: usize = 0; while (i < 10; i += 1) {
7681 assert(list.items[i] == i32(i + 1));
7782 }}
83
84 assert(list.pop() == 10);
85 assert(list.len == 9);
7886}
std/mem.zig+30
......@@ -9,6 +9,8 @@ error NoMem;
99
1010pub const Allocator = struct {
1111 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
1214 reallocFn: fn (self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8,
1315 freeFn: fn (self: &Allocator, mem: []u8),
1416
......@@ -134,6 +136,13 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool {
134136 return true;
135137}
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
137146/// Linear search for the index of a scalar value inside a slice.
138147pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {
139148 for (slice) |item, i| {
......@@ -144,6 +153,27 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize {
144153 return null;
145154}
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
147177/// Reads an integer from memory with size equal to bytes.len.
148178/// T specifies the return type, which must be large enough to store
149179/// the result.
std/os/index.zig+239-4
......@@ -12,6 +12,13 @@ pub const max_noalloc_path_len = 1024;
1212pub const ChildProcess = @import("child_process.zig").ChildProcess;
1313pub 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
1522const debug = @import("../debug.zig");
1623const assert = debug.assert;
1724
......@@ -27,6 +34,7 @@ const cstr = @import("../cstr.zig");
2734
2835const io = @import("../io.zig");
2936const base64 = @import("../base64.zig");
37const List = @import("../list.zig").List;
3038
3139error Unexpected;
3240error SystemResources;
......@@ -41,6 +49,7 @@ error SymLinkLoop;
4149error ReadOnlyFileSystem;
4250error LinkQuotaExceeded;
4351error RenameAcrossMountPoints;
52error DirNotEmpty;
4453
4554/// Fills `buf` with random bytes. If linking against libc, this calls the
4655/// appropriate OS-specific library call. Otherwise it uses the zig standard
......@@ -319,7 +328,8 @@ fn posixExecveErrnoToErr(err: usize) -> error {
319328 errno.EINVAL, errno.ENOEXEC => error.InvalidExe,
320329 errno.EIO, errno.ELOOP => error.FileSystem,
321330 errno.EISDIR => error.IsDir,
322 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
331 errno.ENOENT => error.FileNotFound,
332 errno.ENOTDIR => error.NotDir,
323333 errno.ETXTBSY => error.FileBusy,
324334 else => error.Unexpected,
325335 };
......@@ -413,7 +423,8 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con
413423 errno.EIO => error.FileSystem,
414424 errno.ELOOP => error.SymLinkLoop,
415425 errno.ENAMETOOLONG => error.NameTooLong,
416 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
426 errno.ENOENT => error.FileNotFound,
427 errno.ENOTDIR => error.NotDir,
417428 errno.ENOMEM => error.SystemResources,
418429 errno.ENOSPC => error.NoSpaceLeft,
419430 errno.EROFS => error.ReadOnlyFileSystem,
......@@ -471,7 +482,8 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void {
471482 errno.EISDIR => error.IsDir,
472483 errno.ELOOP => error.SymLinkLoop,
473484 errno.ENAMETOOLONG => error.NameTooLong,
474 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
485 errno.ENOENT => error.FileNotFound,
486 errno.ENOTDIR => error.NotDir,
475487 errno.ENOMEM => error.SystemResources,
476488 errno.EROFS => error.ReadOnlyFileSystem,
477489 else => error.Unexpected,
......@@ -518,7 +530,8 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
518530 errno.ELOOP => error.SymLinkLoop,
519531 errno.EMLINK => error.LinkQuotaExceeded,
520532 errno.ENAMETOOLONG => error.NameTooLong,
521 errno.ENOENT, errno.ENOTDIR => error.FileNotFound,
533 errno.ENOENT => error.FileNotFound,
534 errno.ENOTDIR => error.NotDir,
522535 errno.ENOMEM => error.SystemResources,
523536 errno.ENOSPC => error.NoSpaceLeft,
524537 errno.EEXIST, errno.ENOTEMPTY => error.PathAlreadyExists,
......@@ -528,3 +541,225 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8)
528541 };
529542 }
530543}
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;
241241pub const AF_VSOCK = PF_VSOCK;
242242pub 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
245254fn unsigned(s: i32) -> u32 { *@ptrcast(&u32, &s) }
246255fn signed(s: u32) -> i32 { *@ptrcast(&i32, &s) }
......@@ -273,6 +282,14 @@ pub fn getcwd(buf: &u8, size: usize) -> usize {
273282 arch.syscall2(arch.SYS_getcwd, usize(buf), size)
274283}
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
276293pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize)
277294 -> usize
278295{
......@@ -287,6 +304,10 @@ pub fn read(fd: i32, buf: &u8, count: usize) -> usize {
287304 arch.syscall3(arch.SYS_read, usize(fd), usize(buf), count)
288305}
289306
307pub fn rmdir(path: &const u8) -> usize {
308 arch.syscall1(arch.SYS_rmdir, usize(path))
309}
310
290311pub fn symlink(existing: &const u8, new: &const u8) -> usize {
291312 arch.syscall2(arch.SYS_symlink, usize(existing), usize(new))
292313}
std/os/path.zig+49-10
......@@ -4,22 +4,61 @@ const mem = @import("../mem.zig");
44const Allocator = mem.Allocator;
55
66/// 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 {
8 const buf = %return allocator.alloc(u8, dirname.len + basename.len + 1);
7pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 {
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);
919 %defer allocator.free(buf);
1020
11 mem.copy(u8, buf, dirname);
12 if (dirname[dirname.len - 1] == '/') {
13 mem.copy(u8, buf[dirname.len...], basename);
14 return buf[0...buf.len - 1];
15 } else {
16 buf[dirname.len] = '/';
17 mem.copy(u8, buf[dirname.len + 1 ...], basename);
18 return buf;
21 var buf_index: usize = 0;
22 comptime var path_i = 0;
23 inline while (true) {
24 const arg = ([]const u8)(paths[path_i]);
25 path_i += 1;
26 mem.copy(u8, buf[buf_index...], arg);
27 buf_index += arg.len;
28 if (path_i >= paths.len) break;
29 if (arg[arg.len - 1] != '/') {
30 buf[buf_index] = '/';
31 buf_index += 1;
32 }
1933 }
34
35 return buf[0...buf_index];
2036}
2137
2238test "os.path.join" {
2339 assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c"));
2440 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, ".");
2564}
std/special/build_file_template.zig+3-1
......@@ -3,6 +3,8 @@ const Builder = @import("std").build.Builder;
33pub fn build(b: &Builder) {
44 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");
77 exe.setRelease(release);
8
9 b.default_step.dependOn(&exe.step);
810}
std/special/build_runner.zig+32-21
......@@ -10,74 +10,85 @@ const List = std.list.List;
1010error InvalidArgs;
1111
1212pub 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
1335 // TODO use a more general purpose allocator here
1436 var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024);
1537 defer inc_allocator.deinit();
1638
1739 const allocator = &inc_allocator.allocator;
1840
19 var builder = Builder.init(allocator);
41 var builder = Builder.init(allocator, zig_exe, build_root);
2042 defer builder.deinit();
2143
22 var maybe_zig_exe: ?[]const u8 = null;
2344 var targets = List([]const u8).init(allocator);
2445
2546 var prefix: ?[]const u8 = null;
2647
27 var arg_i: usize = 1;
2848 while (arg_i < os.args.count(); arg_i += 1) {
2949 const arg = os.args.at(arg_i);
3050 if (mem.startsWith(u8, arg, "-D")) {
3151 const option_contents = arg[2...];
3252 if (option_contents.len == 0) {
3353 %%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);
3555 }
3656 if (const name_end ?= mem.indexOfScalar(u8, option_contents, '=')) {
3757 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...];
3959 if (builder.addUserInputOption(option_name, option_value))
40 return usage(&builder, maybe_zig_exe, false, &io.stderr);
60 return usage(&builder, false, &io.stderr);
4161 } else {
4262 if (builder.addUserInputFlag(option_contents))
43 return usage(&builder, maybe_zig_exe, false, &io.stderr);
63 return usage(&builder, false, &io.stderr);
4464 }
4565 } else if (mem.startsWith(u8, arg, "-")) {
4666 if (mem.eql(u8, arg, "--verbose")) {
4767 builder.verbose = true;
4868 } else if (mem.eql(u8, arg, "--help")) {
49 return usage(&builder, maybe_zig_exe, false, &io.stdout);
69 return usage(&builder, false, &io.stdout);
5070 } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) {
5171 arg_i += 1;
5272 prefix = os.args.at(arg_i);
5373 } else {
5474 %%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);
5676 }
57 } else if (maybe_zig_exe == null) {
58 maybe_zig_exe = arg;
5977 } else {
6078 %%targets.append(arg);
6179 }
6280 }
6381
64 builder.zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr);
6582 builder.setInstallPrefix(prefix);
66
6783 root.build(&builder);
6884
6985 if (builder.validateUserInputDidItFail())
70 return usage(&builder, maybe_zig_exe, true, &io.stderr);
86 return usage(&builder, true, &io.stderr);
7187
7288 %return builder.make(targets.toSliceConst());
7389}
7490
75fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, 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
91fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) -> %void {
8192 // run the build script to collect the options
8293 if (!already_ran_build) {
8394 builder.setInstallPrefix(null);
......@@ -90,7 +101,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool,
90101 \\
91102 \\Steps:
92103 \\
93 , zig_exe);
104 , builder.zig_exe);
94105
95106 const allocator = builder.allocator;
96107 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};