From d656c2a7abe90d00ef6dbc3731b82bd26180038a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sun, 25 Feb 2024 14:04:06 +0100 Subject: [PATCH] test: rework how filtering works * make test names contain the fully qualified name * make test filters match the fully qualified name * allow multiple test filters, where a test is skipped if it does not match any of the specified filters --- build.zig | 26 ++-- doc/langref.html.in | 8 +- lib/std/Build.zig | 13 +- lib/std/Build/Step/Compile.zig | 8 +- src/Compilation.zig | 10 +- src/InternPool.zig | 2 +- src/Module.zig | 252 +++++++++++++++++---------------- src/Sema.zig | 48 +++---- src/arch/wasm/CodeGen.zig | 2 +- src/codegen/llvm.zig | 24 ++-- src/codegen/spirv.zig | 4 +- src/link/Coff.zig | 4 +- src/link/Dwarf.zig | 2 +- src/link/Elf/ZigObject.zig | 8 +- src/link/MachO/ZigObject.zig | 6 +- src/link/Plan9.zig | 2 +- src/link/Wasm.zig | 8 +- src/main.zig | 33 ++--- test/src/Cases.zig | 32 ++--- test/src/CompareOutput.zig | 20 +-- test/src/RunTranslatedC.zig | 103 ++++++++++++++ test/src/StackTrace.zig | 8 +- test/src/TranslateC.zig | 118 +++++++++++++++ test/src/run_translated_c.zig | 106 -------------- test/src/translate_c.zig | 121 ---------------- test/tests.zig | 32 ++--- 26 files changed, 494 insertions(+), 506 deletions(-) create mode 100644 test/src/RunTranslatedC.zig create mode 100644 test/src/TranslateC.zig delete mode 100644 test/src/run_translated_c.zig delete mode 100644 test/src/translate_c.zig diff --git a/build.zig b/build.zig index d8860eabae..072f781750 100644 --- a/build.zig +++ b/build.zig @@ -390,7 +390,7 @@ pub fn build(b: *std.Build) !void { } } - const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); + const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{}; const test_cases_options = b.addOptions(); check_case_exe.root_module.addOptions("build_options", test_cases_options); @@ -418,7 +418,7 @@ pub fn build(b: *std.Build) !void { test_cases_options.addOption(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir); test_cases_options.addOption([:0]const u8, "version", version); test_cases_options.addOption(std.SemanticVersion, "semver", semver); - test_cases_options.addOption(?[]const u8, "test_filter", test_filter); + test_cases_options.addOption([]const []const u8, "test_filters", test_filters); var chosen_opt_modes_buf: [4]builtin.OptimizeMode = undefined; var chosen_mode_index: usize = 0; @@ -454,7 +454,7 @@ pub fn build(b: *std.Build) !void { }).step); const test_cases_step = b.step("test-cases", "Run the main compiler test cases"); - try tests.addCases(b, test_cases_step, test_filter, check_case_exe, .{ + try tests.addCases(b, test_cases_step, test_filters, check_case_exe, .{ .enable_llvm = enable_llvm, .llvm_has_m68k = llvm_has_m68k, .llvm_has_csky = llvm_has_csky, @@ -464,7 +464,7 @@ pub fn build(b: *std.Build) !void { test_step.dependOn(test_cases_step); test_step.dependOn(tests.addModuleTests(b, .{ - .test_filter = test_filter, + .test_filters = test_filters, .root_src = "test/behavior.zig", .name = "behavior", .desc = "Run the behavior tests", @@ -477,7 +477,7 @@ pub fn build(b: *std.Build) !void { })); test_step.dependOn(tests.addModuleTests(b, .{ - .test_filter = test_filter, + .test_filters = test_filters, .root_src = "test/c_import.zig", .name = "c-import", .desc = "Run the @cImport tests", @@ -489,7 +489,7 @@ pub fn build(b: *std.Build) !void { })); test_step.dependOn(tests.addModuleTests(b, .{ - .test_filter = test_filter, + .test_filters = test_filters, .root_src = "lib/compiler_rt.zig", .name = "compiler-rt", .desc = "Run the compiler_rt tests", @@ -501,7 +501,7 @@ pub fn build(b: *std.Build) !void { })); test_step.dependOn(tests.addModuleTests(b, .{ - .test_filter = test_filter, + .test_filters = test_filters, .root_src = "lib/c.zig", .name = "universal-libc", .desc = "Run the universal libc tests", @@ -512,7 +512,7 @@ pub fn build(b: *std.Build) !void { .skip_libc = true, })); - test_step.dependOn(tests.addCompareOutputTests(b, test_filter, optimization_modes)); + test_step.dependOn(tests.addCompareOutputTests(b, test_filters, optimization_modes)); test_step.dependOn(tests.addStandaloneTests( b, optimization_modes, @@ -523,16 +523,16 @@ pub fn build(b: *std.Build) !void { )); test_step.dependOn(tests.addCAbiTests(b, skip_non_native, skip_release)); test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, false, enable_symlinks_windows)); - test_step.dependOn(tests.addStackTraceTests(b, test_filter, optimization_modes)); + test_step.dependOn(tests.addStackTraceTests(b, test_filters, optimization_modes)); test_step.dependOn(tests.addCliTests(b)); - test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, optimization_modes)); - test_step.dependOn(tests.addTranslateCTests(b, test_filter)); + test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes)); + test_step.dependOn(tests.addTranslateCTests(b, test_filters)); if (!skip_run_translated_c) { - test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter, target)); + test_step.dependOn(tests.addRunTranslatedCTests(b, test_filters, target)); } test_step.dependOn(tests.addModuleTests(b, .{ - .test_filter = test_filter, + .test_filters = test_filters, .root_src = "lib/std/std.zig", .name = "std", .desc = "Run the standard library tests", diff --git a/doc/langref.html.in b/doc/langref.html.in index 885dbe41f6..a787f5dd2a 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -988,13 +988,13 @@ fn addOne(number: i32) i32 { printed to standard error by the default test runner:

-
Test [1/2] test.expect addOne adds one to 41...
+
1/2 testing_introduction.test.expect addOne adds one to 41...
Lines like this indicate which test, out of the total number of tests, is being run. - In this case, [1/2] indicates that the first test, out of a total of - two test, is being run. Note that, when the test runner program's standard error is output + In this case, 1/2 indicates that the first test, out of a total of two tests, + is being run. Note that, when the test runner program's standard error is output to the terminal, these lines are cleared when a test succeeds.
-
Test [2/2] decltest.addOne...
+
2/2 testing_introduction.decltest.addOne...
When the test name is an identifier, the default test runner uses the text decltest instead of test.
diff --git a/lib/std/Build.zig b/lib/std/Build.zig index ca00a7d15a..3892b9ca73 100644 --- a/lib/std/Build.zig +++ b/lib/std/Build.zig @@ -855,7 +855,9 @@ pub const TestOptions = struct { optimize: std.builtin.OptimizeMode = .Debug, version: ?std.SemanticVersion = null, max_rss: usize = 0, + /// deprecated: use `.filters = &.{filter}` instead of `.filter = filter`. filter: ?[]const u8 = null, + filters: []const []const u8 = &.{}, test_runner: ?[]const u8 = null, link_libc: ?bool = null, single_threaded: ?bool = null, @@ -888,7 +890,12 @@ pub fn addTest(b: *Build, options: TestOptions) *Step.Compile { .error_tracing = options.error_tracing, }, .max_rss = options.max_rss, - .filter = options.filter, + .filters = if (options.filter != null and options.filters.len > 0) filters: { + const filters = b.allocator.alloc([]const u8, 1 + options.filters.len) catch @panic("OOM"); + filters[0] = b.dupe(options.filter.?); + for (filters[1..], options.filters) |*dest, source| dest.* = b.dupe(source); + break :filters filters; + } else b.dupeStrings(if (options.filter) |filter| &.{filter} else options.filters), .test_runner = options.test_runner, .use_llvm = options.use_llvm, .use_lld = options.use_lld, @@ -993,9 +1000,7 @@ pub fn dupe(self: *Build, bytes: []const u8) []u8 { /// Duplicates an array of strings without the need to handle out of memory. pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 { const array = self.allocator.alloc([]u8, strings.len) catch @panic("OOM"); - for (strings, 0..) |s, i| { - array[i] = self.dupe(s); - } + for (array, strings) |*dest, source| dest.* = self.dupe(source); return array; } diff --git a/lib/std/Build/Step/Compile.zig b/lib/std/Build/Step/Compile.zig index 51b5b2e52a..5ee92ffc22 100644 --- a/lib/std/Build/Step/Compile.zig +++ b/lib/std/Build/Step/Compile.zig @@ -54,7 +54,7 @@ global_base: ?u64 = null, /// Set via options; intended to be read-only after that. zig_lib_dir: ?LazyPath, exec_cmd_args: ?[]const ?[]const u8, -filter: ?[]const u8, +filters: []const []const u8, test_runner: ?[]const u8, test_server_mode: bool, wasi_exec_model: ?std.builtin.WasiExecModel = null, @@ -223,7 +223,7 @@ pub const Options = struct { linkage: ?Linkage = null, version: ?std.SemanticVersion = null, max_rss: usize = 0, - filter: ?[]const u8 = null, + filters: []const []const u8 = &.{}, test_runner: ?[]const u8 = null, use_llvm: ?bool = null, use_lld: ?bool = null, @@ -310,7 +310,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile { .installed_headers = ArrayList(*Step).init(owner.allocator), .zig_lib_dir = null, .exec_cmd_args = null, - .filter = options.filter, + .filters = options.filters, .test_runner = options.test_runner, .test_server_mode = options.test_runner == null, .rdynamic = false, @@ -1297,7 +1297,7 @@ fn make(step: *Step, prog_node: *std.Progress.Node) !void { try zig_args.append(b.fmt("0x{x}", .{image_base})); } - if (self.filter) |filter| { + for (self.filters) |filter| { try zig_args.append("--test-filter"); try zig_args.append(filter); } diff --git a/src/Compilation.zig b/src/Compilation.zig index 91879094dd..5fa93fa677 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -217,7 +217,7 @@ libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default, /// This mutex guards all `Compilation` mutable state. mutex: std.Thread.Mutex = .{}, -test_filter: ?[]const u8, +test_filters: []const []const u8, test_name_prefix: ?[]const u8, emit_asm: ?EmitLoc, @@ -1097,7 +1097,7 @@ pub const CreateOptions = struct { native_system_include_paths: []const []const u8 = &.{}, clang_preprocessor_mode: ClangPreprocessorMode = .no, reference_trace: ?u32 = null, - test_filter: ?[]const u8 = null, + test_filters: []const []const u8 = &.{}, test_name_prefix: ?[]const u8 = null, test_runner_path: ?[]const u8 = null, subsystem: ?std.Target.SubSystem = null, @@ -1506,7 +1506,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil .formatted_panics = formatted_panics, .time_report = options.time_report, .stack_report = options.stack_report, - .test_filter = options.test_filter, + .test_filters = options.test_filters, .test_name_prefix = options.test_name_prefix, .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, .debug_compile_errors = options.debug_compile_errors, @@ -1613,7 +1613,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil hash.add(options.config.use_lib_llvm); hash.add(options.config.dll_export_fns); hash.add(options.config.is_test); - hash.addOptionalBytes(options.test_filter); + hash.addListOfBytes(options.test_filters); hash.addOptionalBytes(options.test_name_prefix); hash.add(options.skip_linker_dependencies); hash.add(formatted_panics); @@ -2475,7 +2475,7 @@ fn addNonIncrementalStuffToCacheManifest( try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.root_mod, mod.main_mod, .{ .files = man }); // Synchronize with other matching comments: ZigOnlyHashStuff - man.hash.addOptionalBytes(comp.test_filter); + man.hash.addListOfBytes(comp.test_filters); man.hash.addOptionalBytes(comp.test_name_prefix); man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.formatted_panics); diff --git a/src/InternPool.zig b/src/InternPool.zig index 19be12c129..a9f2f68d4f 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -7904,7 +7904,7 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex) ip.namespacePtr(index).* = .{ .parent = undefined, .file_scope = undefined, - .ty = undefined, + .decl_index = undefined, }; ip.namespaces_free_list.append(gpa, index) catch { // In order to keep `destroyNamespace` a non-fallible function, we ignore memory diff --git a/src/Module.zig b/src/Module.zig index c27b8ea4be..a4cedd9077 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -411,15 +411,15 @@ pub const Decl = struct { /// This state detects dependency loops. in_progress, /// The file corresponding to this Decl had a parse error or ZIR error. - /// There will be a corresponding ErrorMsg in Module.failed_files. + /// There will be a corresponding ErrorMsg in Zcu.failed_files. file_failure, /// This Decl might be OK but it depends on another one which did not /// successfully complete semantic analysis. dependency_failure, /// Semantic analysis failure. - /// There will be a corresponding ErrorMsg in Module.failed_decls. + /// There will be a corresponding ErrorMsg in Zcu.failed_decls. sema_failure, - /// There will be a corresponding ErrorMsg in Module.failed_decls. + /// There will be a corresponding ErrorMsg in Zcu.failed_decls. codegen_failure, /// Sematic analysis and constant value codegen of this Decl has /// succeeded. However, the Decl may be outdated due to an in-progress @@ -494,77 +494,45 @@ pub const Decl = struct { return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index)); } - pub fn srcLoc(decl: Decl, mod: *Module) SrcLoc { - return decl.nodeOffsetSrcLoc(0, mod); + pub fn srcLoc(decl: Decl, zcu: *Zcu) SrcLoc { + return decl.nodeOffsetSrcLoc(0, zcu); } - pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32, mod: *Module) SrcLoc { + pub fn nodeOffsetSrcLoc(decl: Decl, node_offset: i32, zcu: *Zcu) SrcLoc { return .{ - .file_scope = decl.getFileScope(mod), + .file_scope = decl.getFileScope(zcu), .parent_decl_node = decl.src_node, .lazy = LazySrcLoc.nodeOffset(node_offset), }; } - pub fn srcToken(decl: Decl, mod: *Module) Ast.TokenIndex { - const tree = &decl.getFileScope(mod).tree; + pub fn srcToken(decl: Decl, zcu: *Zcu) Ast.TokenIndex { + const tree = &decl.getFileScope(zcu).tree; return tree.firstToken(decl.src_node); } - pub fn srcByteOffset(decl: Decl, mod: *Module) u32 { - const tree = &decl.getFileScope(mod).tree; + pub fn srcByteOffset(decl: Decl, zcu: *Zcu) u32 { + const tree = &decl.getFileScope(zcu).tree; return tree.tokens.items(.start)[decl.srcToken()]; } - pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { + pub fn renderFullyQualifiedName(decl: Decl, zcu: *Zcu, writer: anytype) !void { if (decl.name_fully_qualified) { - try writer.print("{}", .{decl.name.fmt(&mod.intern_pool)}); + try writer.print("{}", .{decl.name.fmt(&zcu.intern_pool)}); } else { - try mod.namespacePtr(decl.src_namespace).renderFullyQualifiedName(mod, decl.name, writer); + try zcu.namespacePtr(decl.src_namespace).renderFullyQualifiedName(zcu, decl.name, writer); } } - pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { - return mod.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(mod, decl.name, writer); + pub fn renderFullyQualifiedDebugName(decl: Decl, zcu: *Zcu, writer: anytype) !void { + return zcu.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(zcu, decl.name, writer); } - pub fn getFullyQualifiedName(decl: Decl, mod: *Module) !InternPool.NullTerminatedString { - if (decl.name_fully_qualified) return decl.name; - - const ip = &mod.intern_pool; - const count = count: { - var count: usize = ip.stringToSlice(decl.name).len + 1; - var ns: Namespace.Index = decl.src_namespace; - while (true) { - const namespace = mod.namespacePtr(ns); - const ns_decl = mod.declPtr(namespace.getDeclIndex(mod)); - count += ip.stringToSlice(ns_decl.name).len + 1; - ns = namespace.parent.unwrap() orelse { - count += namespace.file_scope.sub_file_path.len; - break :count count; - }; - } - }; - - const gpa = mod.gpa; - const start = ip.string_bytes.items.len; - // Protects reads of interned strings from being reallocated during the call to - // renderFullyQualifiedName. - try ip.string_bytes.ensureUnusedCapacity(gpa, count); - decl.renderFullyQualifiedName(mod, ip.string_bytes.writer(gpa)) catch unreachable; - - // Sanitize the name for nvptx which is more restrictive. - // TODO This should be handled by the backend, not the frontend. Have a - // look at how the C backend does it for inspiration. - const cpu_arch = mod.root_mod.resolved_target.result.cpu.arch; - if (cpu_arch.isNvptx()) { - for (ip.string_bytes.items[start..]) |*byte| switch (byte.*) { - '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', - else => {}, - }; - } - - return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); + pub fn fullyQualifiedName(decl: Decl, zcu: *Zcu) !InternPool.NullTerminatedString { + return if (decl.name_fully_qualified) + decl.name + else + zcu.namespacePtr(decl.src_namespace).fullyQualifiedName(zcu, decl.name); } pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { @@ -572,38 +540,38 @@ pub const Decl = struct { return TypedValue{ .ty = decl.ty, .val = decl.val }; } - pub fn internValue(decl: *Decl, mod: *Module) Allocator.Error!InternPool.Index { + pub fn internValue(decl: *Decl, zcu: *Zcu) Allocator.Error!InternPool.Index { assert(decl.has_tv); - const ip_index = try decl.val.intern(decl.ty, mod); + const ip_index = try decl.val.intern(decl.ty, zcu); decl.val = Value.fromInterned(ip_index); return ip_index; } - pub fn isFunction(decl: Decl, mod: *const Module) !bool { + pub fn isFunction(decl: Decl, zcu: *const Zcu) !bool { const tv = try decl.typedValue(); - return tv.ty.zigTypeTag(mod) == .Fn; + return tv.ty.zigTypeTag(zcu) == .Fn; } /// If the Decl owns its value and it is a struct, return it, /// otherwise null. - pub fn getOwnedStruct(decl: Decl, mod: *Module) ?InternPool.Key.StructType { + pub fn getOwnedStruct(decl: Decl, zcu: *Zcu) ?InternPool.Key.StructType { if (!decl.owns_tv) return null; if (decl.val.ip_index == .none) return null; - return mod.typeToStruct(decl.val.toType()); + return zcu.typeToStruct(decl.val.toType()); } /// If the Decl owns its value and it is a union, return it, /// otherwise null. - pub fn getOwnedUnion(decl: Decl, mod: *Module) ?InternPool.UnionType { + pub fn getOwnedUnion(decl: Decl, zcu: *Zcu) ?InternPool.UnionType { if (!decl.owns_tv) return null; if (decl.val.ip_index == .none) return null; - return mod.typeToUnion(decl.val.toType()); + return zcu.typeToUnion(decl.val.toType()); } - pub fn getOwnedFunction(decl: Decl, mod: *Module) ?InternPool.Key.Func { + pub fn getOwnedFunction(decl: Decl, zcu: *Zcu) ?InternPool.Key.Func { const i = decl.getOwnedFunctionIndex(); if (i == .none) return null; - return switch (mod.intern_pool.indexToKey(i)) { + return switch (zcu.intern_pool.indexToKey(i)) { .func => |func| func, else => null, }; @@ -616,24 +584,24 @@ pub const Decl = struct { /// If the Decl owns its value and it is an extern function, returns it, /// otherwise null. - pub fn getOwnedExternFunc(decl: Decl, mod: *Module) ?InternPool.Key.ExternFunc { - return if (decl.owns_tv) decl.val.getExternFunc(mod) else null; + pub fn getOwnedExternFunc(decl: Decl, zcu: *Zcu) ?InternPool.Key.ExternFunc { + return if (decl.owns_tv) decl.val.getExternFunc(zcu) else null; } /// If the Decl owns its value and it is a variable, returns it, /// otherwise null. - pub fn getOwnedVariable(decl: Decl, mod: *Module) ?InternPool.Key.Variable { - return if (decl.owns_tv) decl.val.getVariable(mod) else null; + pub fn getOwnedVariable(decl: Decl, zcu: *Zcu) ?InternPool.Key.Variable { + return if (decl.owns_tv) decl.val.getVariable(zcu) else null; } /// Gets the namespace that this Decl creates by being a struct, union, /// enum, or opaque. - pub fn getInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { + pub fn getInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex { if (!decl.has_tv) return .none; return switch (decl.val.ip_index) { .empty_struct_type => .none, .none => .none, - else => switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { + else => switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) { .opaque_type => |opaque_type| opaque_type.namespace.toOptional(), .struct_type => |struct_type| struct_type.namespace, .union_type => |union_type| union_type.namespace.toOptional(), @@ -644,19 +612,19 @@ pub const Decl = struct { } /// Like `getInnerNamespaceIndex`, but only returns it if the Decl is the owner. - pub fn getOwnedInnerNamespaceIndex(decl: Decl, mod: *Module) Namespace.OptionalIndex { + pub fn getOwnedInnerNamespaceIndex(decl: Decl, zcu: *Zcu) Namespace.OptionalIndex { if (!decl.owns_tv) return .none; - return decl.getInnerNamespaceIndex(mod); + return decl.getInnerNamespaceIndex(zcu); } /// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer. - pub fn getOwnedInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { - return mod.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(mod)); + pub fn getOwnedInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace { + return zcu.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(zcu)); } /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. - pub fn getInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { - return mod.namespacePtrUnwrap(decl.getInnerNamespaceIndex(mod)); + pub fn getInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace { + return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu)); } pub fn dump(decl: *Decl) void { @@ -674,27 +642,27 @@ pub const Decl = struct { std.debug.print("\n", .{}); } - pub fn getFileScope(decl: Decl, mod: *Module) *File { - return mod.namespacePtr(decl.src_namespace).file_scope; + pub fn getFileScope(decl: Decl, zcu: *Zcu) *File { + return zcu.namespacePtr(decl.src_namespace).file_scope; } - pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex { + pub fn getExternDecl(decl: Decl, zcu: *Zcu) OptionalIndex { assert(decl.has_tv); - return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { + return switch (zcu.intern_pool.indexToKey(decl.val.toIntern())) { .variable => |variable| if (variable.is_extern) variable.decl.toOptional() else .none, .extern_func => |extern_func| extern_func.decl.toOptional(), else => .none, }; } - pub fn isExtern(decl: Decl, mod: *Module) bool { - return decl.getExternDecl(mod) != .none; + pub fn isExtern(decl: Decl, zcu: *Zcu) bool { + return decl.getExternDecl(zcu) != .none; } - pub fn getAlignment(decl: Decl, mod: *Module) Alignment { + pub fn getAlignment(decl: Decl, zcu: *Zcu) Alignment { assert(decl.has_tv); if (decl.alignment != .none) return decl.alignment; - return decl.ty.abiAlignment(mod); + return decl.ty.abiAlignment(zcu); } }; @@ -704,7 +672,7 @@ pub const EmitH = struct { }; pub const DeclAdapter = struct { - mod: *Module, + zcu: *Zcu, pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 { _ = self; @@ -713,8 +681,7 @@ pub const DeclAdapter = struct { pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool { _ = b_index; - const b_decl = self.mod.declPtr(b_decl_index); - return a == b_decl.name; + return a == self.zcu.declPtr(b_decl_index).name; } }; @@ -723,7 +690,7 @@ pub const Namespace = struct { parent: OptionalIndex, file_scope: *File, /// Will be a struct, enum, union, or opaque. - ty: Type, + decl_index: Decl.Index, /// Direct children of the namespace. /// Declaration order is preserved via entry order. /// These are only declarations named directly by the AST; anonymous @@ -739,7 +706,7 @@ pub const Namespace = struct { const OptionalIndex = InternPool.OptionalNamespaceIndex; const DeclContext = struct { - module: *Module, + zcu: *Zcu, pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { const decl = ctx.module.declPtr(decl_index); @@ -757,39 +724,87 @@ pub const Namespace = struct { // This renders e.g. "std.fs.Dir.OpenOptions" pub fn renderFullyQualifiedName( ns: Namespace, - mod: *Module, + zcu: *Zcu, name: InternPool.NullTerminatedString, writer: anytype, ) @TypeOf(writer).Error!void { if (ns.parent.unwrap()) |parent| { - const decl = mod.declPtr(ns.getDeclIndex(mod)); - try mod.namespacePtr(parent).renderFullyQualifiedName(mod, decl.name, writer); + try zcu.namespacePtr(parent).renderFullyQualifiedName( + zcu, + zcu.declPtr(ns.decl_index).name, + writer, + ); } else { try ns.file_scope.renderFullyQualifiedName(writer); } - if (name != .empty) try writer.print(".{}", .{name.fmt(&mod.intern_pool)}); + if (name != .empty) try writer.print(".{}", .{name.fmt(&zcu.intern_pool)}); } /// This renders e.g. "std/fs.zig:Dir.OpenOptions" pub fn renderFullyQualifiedDebugName( ns: Namespace, - mod: *Module, + zcu: *Zcu, name: InternPool.NullTerminatedString, writer: anytype, ) @TypeOf(writer).Error!void { - const separator_char: u8 = if (ns.parent.unwrap()) |parent| sep: { - const decl = mod.declPtr(ns.getDeclIndex(mod)); - try mod.namespacePtr(parent).renderFullyQualifiedDebugName(mod, decl.name, writer); + const sep: u8 = if (ns.parent.unwrap()) |parent| sep: { + try zcu.namespacePtr(parent).renderFullyQualifiedDebugName( + zcu, + zcu.declPtr(ns.decl_index).name, + writer, + ); break :sep '.'; } else sep: { try ns.file_scope.renderFullyQualifiedDebugName(writer); break :sep ':'; }; - if (name != .empty) try writer.print("{c}{}", .{ separator_char, name.fmt(&mod.intern_pool) }); + if (name != .empty) try writer.print("{c}{}", .{ sep, name.fmt(&zcu.intern_pool) }); } - pub fn getDeclIndex(ns: Namespace, mod: *Module) Decl.Index { - return ns.ty.getOwnerDecl(mod); + pub fn fullyQualifiedName( + ns: Namespace, + zcu: *Zcu, + name: InternPool.NullTerminatedString, + ) !InternPool.NullTerminatedString { + const ip = &zcu.intern_pool; + const count = count: { + var count: usize = ip.stringToSlice(name).len + 1; + var cur_ns = &ns; + while (true) { + const decl = zcu.declPtr(cur_ns.decl_index); + count += ip.stringToSlice(decl.name).len + 1; + cur_ns = zcu.namespacePtr(cur_ns.parent.unwrap() orelse { + count += ns.file_scope.sub_file_path.len; + break :count count; + }); + } + }; + + const gpa = zcu.gpa; + const start = ip.string_bytes.items.len; + // Protects reads of interned strings from being reallocated during the call to + // renderFullyQualifiedName. + try ip.string_bytes.ensureUnusedCapacity(gpa, count); + ns.renderFullyQualifiedName(zcu, name, ip.string_bytes.writer(gpa)) catch unreachable; + + // Sanitize the name for nvptx which is more restrictive. + // TODO This should be handled by the backend, not the frontend. Have a + // look at how the C backend does it for inspiration. + const cpu_arch = zcu.root_mod.resolved_target.result.cpu.arch; + if (cpu_arch.isNvptx()) { + for (ip.string_bytes.items[start..]) |*byte| switch (byte.*) { + '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', + else => {}, + }; + } + + return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); + } + + pub fn getType(ns: Namespace, zcu: *Zcu) Type { + const decl = zcu.declPtr(ns.decl_index); + assert(decl.has_tv); + return decl.val.toType(); } }; @@ -2559,9 +2574,8 @@ pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namesp pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { const decl = mod.declPtr(decl_index); const namespace = mod.namespacePtr(decl.src_namespace); - if (namespace.parent != .none) - return false; - return decl_index == namespace.getDeclIndex(mod); + if (namespace.parent != .none) return false; + return decl_index == namespace.decl_index; } fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { @@ -3592,7 +3606,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError defer liveness.deinit(gpa); if (dump_air) { - const fqn = try decl.getFullyQualifiedName(zcu); + const fqn = try decl.fullyQualifiedName(zcu); std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)}); @import("print_air.zig").dump(zcu, air, liveness); std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)}); @@ -3738,7 +3752,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { // InternPool index. const new_namespace_index = try mod.createNamespace(.{ .parent = .none, - .ty = undefined, + .decl_index = undefined, .file_scope = file, }); const new_namespace = mod.namespacePtr(new_namespace_index); @@ -3749,6 +3763,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { errdefer @panic("TODO error handling"); file.root_decl = new_decl_index.toOptional(); + new_namespace.decl_index = new_decl_index; new_decl.name = try file.fullyQualifiedName(mod); new_decl.name_fully_qualified = true; @@ -3808,7 +3823,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { _ = try decl.internValue(mod); } - new_namespace.ty = Type.fromInterned(struct_ty); new_decl.val = Value.fromInterned(struct_ty); new_decl.has_tv = true; new_decl.owns_tv = true; @@ -3881,7 +3895,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { const std_decl = mod.declPtr(std_file.root_decl.unwrap().?); const std_namespace = std_decl.getInnerNamespace(mod).?; const builtin_str = try ip.getOrPutString(gpa, "builtin"); - const builtin_decl = mod.declPtr(std_namespace.decls.getKeyAdapted(builtin_str, DeclAdapter{ .mod = mod }) orelse break :blk .none); + const builtin_decl = mod.declPtr(std_namespace.decls.getKeyAdapted(builtin_str, DeclAdapter{ .zcu = mod }) orelse break :blk .none); const builtin_namespace = builtin_decl.getInnerNamespaceIndex(mod).unwrap() orelse break :blk .none; if (decl.src_namespace != builtin_namespace) break :blk .none; // We're in builtin.zig. This could be a builtin we need to add to a specific InternPool index. @@ -4576,8 +4590,8 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void const gop = try namespace.decls.getOrPutContextAdapted( gpa, decl_name, - DeclAdapter{ .mod = zcu }, - Namespace.DeclContext{ .module = zcu }, + DeclAdapter{ .zcu = zcu }, + Namespace.DeclContext{ .zcu = zcu }, ); const comp = zcu.comp; if (!gop.found_existing) { @@ -4600,12 +4614,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void .@"test" => a: { if (!comp.config.is_test) break :a false; if (decl_mod != zcu.main_mod) break :a false; - if (is_named_test) { - if (comp.test_filter) |test_filter| { - if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) { - break :a false; - } - } + if (is_named_test and comp.test_filters.len > 0) { + const decl_fqn = ip.stringToSlice(try namespace.fullyQualifiedName(zcu, decl_name)); + for (comp.test_filters) |test_filter| { + if (mem.indexOf(u8, decl_fqn, test_filter)) |_| break; + } else break :a false; } try zcu.test_functions.put(gpa, new_decl_index, {}); break :a true; @@ -5622,7 +5635,7 @@ pub fn populateTestFunctions( const test_functions_str = try ip.getOrPutString(gpa, "test_functions"); const decl_index = builtin_namespace.decls.getKeyAdapted( test_functions_str, - DeclAdapter{ .mod = mod }, + DeclAdapter{ .zcu = mod }, ).?; { // We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` @@ -5646,8 +5659,7 @@ pub fn populateTestFunctions( for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| { const test_decl = mod.declPtr(test_decl_index); - // TODO: write something like getCoercedInts to avoid needing to dupe - const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(test_decl.name)); + const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(try test_decl.fullyQualifiedName(mod))); defer gpa.free(test_decl_name); const test_name_decl_index = n: { const test_name_decl_ty = try mod.arrayType(.{ @@ -6359,17 +6371,13 @@ pub fn opaqueSrcLoc(mod: *Module, opaque_type: InternPool.Key.OpaqueType) SrcLoc } pub fn opaqueFullyQualifiedName(mod: *Module, opaque_type: InternPool.Key.OpaqueType) !InternPool.NullTerminatedString { - return mod.declPtr(opaque_type.decl).getFullyQualifiedName(mod); + return mod.declPtr(opaque_type.decl).fullyQualifiedName(mod); } pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File { return mod.declPtr(decl_index).getFileScope(mod); } -pub fn namespaceDeclIndex(mod: *Module, namespace_index: Namespace.Index) Decl.Index { - return mod.namespacePtr(namespace_index).getDeclIndex(mod); -} - /// Returns null in the following cases: /// * `@TypeOf(.{})` /// * A struct which has no fields (`struct {}`). diff --git a/src/Sema.zig b/src/Sema.zig index 0a38cf93dc..309e968482 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2801,10 +2801,9 @@ fn zirStructDecl( const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), - .ty = undefined, + .decl_index = new_decl_index, .file_scope = block.getFileScope(mod), }); - const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); const struct_ty = ty: { @@ -2821,7 +2820,6 @@ fn zirStructDecl( new_decl.ty = Type.type; new_decl.val = Value.fromInterned(struct_ty); - new_namespace.ty = Type.fromInterned(struct_ty); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); @@ -2990,10 +2988,9 @@ fn zirEnumDecl( const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), - .ty = undefined, + .decl_index = new_decl_index, .file_scope = block.getFileScope(mod), }); - const new_namespace = mod.namespacePtr(new_namespace_index); errdefer if (!done) mod.destroyNamespace(new_namespace_index); const decls = sema.code.bodySlice(extra_index, decls_len); @@ -3036,7 +3033,6 @@ fn zirEnumDecl( new_decl.ty = Type.type; new_decl.val = Value.fromInterned(incomplete_enum.index); - new_namespace.ty = Type.fromInterned(incomplete_enum.index); const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); @@ -3248,10 +3244,9 @@ fn zirUnionDecl( const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), - .ty = undefined, + .decl_index = new_decl_index, .file_scope = block.getFileScope(mod), }); - const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); const union_ty = ty: { @@ -3292,7 +3287,6 @@ fn zirUnionDecl( new_decl.ty = Type.type; new_decl.val = Value.fromInterned(union_ty); - new_namespace.ty = Type.fromInterned(union_ty); const decls = sema.code.bodySlice(extra_index, decls_len); try mod.scanNamespace(new_namespace_index, decls, new_decl); @@ -3346,10 +3340,9 @@ fn zirOpaqueDecl( const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), - .ty = undefined, + .decl_index = new_decl_index, .file_scope = block.getFileScope(mod), }); - const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); const opaque_ty = try mod.intern(.{ .opaque_type = .{ @@ -3362,7 +3355,6 @@ fn zirOpaqueDecl( new_decl.ty = Type.type; new_decl.val = Value.fromInterned(opaque_ty); - new_namespace.ty = Type.fromInterned(opaque_ty); const decls = sema.code.bodySlice(extra_index, decls_len); try mod.scanNamespace(new_namespace_index, decls, new_decl); @@ -4834,7 +4826,7 @@ fn validateStructInit( if (root_msg) |msg| { if (mod.typeToStruct(struct_ty)) |struct_type| { const decl = mod.declPtr(struct_type.decl.unwrap().?); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.fullyQualifiedName(mod); try mod.errNoteNonLazy( decl.srcLoc(mod), msg, @@ -4961,7 +4953,7 @@ fn validateStructInit( if (root_msg) |msg| { if (mod.typeToStruct(struct_ty)) |struct_type| { const decl = mod.declPtr(struct_type.decl.unwrap().?); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.fullyQualifiedName(mod); try mod.errNoteNonLazy( decl.srcLoc(mod), msg, @@ -5355,7 +5347,7 @@ fn failWithBadStructFieldAccess( const mod = sema.mod; const gpa = sema.gpa; const decl = mod.declPtr(struct_type.decl.unwrap().?); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.fullyQualifiedName(mod); const msg = msg: { const msg = try sema.errMsg( @@ -5382,7 +5374,7 @@ fn failWithBadUnionFieldAccess( const gpa = sema.gpa; const decl = mod.declPtr(union_obj.decl); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.fullyQualifiedName(mod); const msg = msg: { const msg = try sema.errMsg( @@ -6504,8 +6496,7 @@ fn lookupInNamespace( const mod = sema.mod; const namespace = mod.namespacePtr(namespace_index); - const namespace_decl_index = namespace.getDeclIndex(mod); - const namespace_decl = mod.declPtr(namespace_decl_index); + const namespace_decl = mod.declPtr(namespace.decl_index); if (namespace_decl.analysis == .file_failure) { return error.AnalysisFail; } @@ -6526,7 +6517,7 @@ fn lookupInNamespace( while (check_i < checked_namespaces.count()) : (check_i += 1) { const check_ns = checked_namespaces.keys()[check_i]; - if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| { + if (check_ns.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .zcu = mod })) |decl_index| { // Skip decls which are not marked pub, which are in a different // file than the `a.b`/`@hasDecl` syntax. const decl = mod.declPtr(decl_index); @@ -6584,7 +6575,7 @@ fn lookupInNamespace( return sema.failWithOwnedErrorMsg(block, msg); }, } - } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .mod = mod })) |decl_index| { + } else if (namespace.decls.getKeyAdapted(ident_name, Module.DeclAdapter{ .zcu = mod })) |decl_index| { return decl_index; } @@ -17210,7 +17201,7 @@ fn zirThis( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const this_decl_index = mod.namespaceDeclIndex(block.namespace); + const this_decl_index = mod.namespacePtr(block.namespace).decl_index; const src = LazySrcLoc.nodeOffset(@bitCast(extended.operand)); return sema.analyzeDeclVal(block, src, this_decl_index); } @@ -20075,7 +20066,7 @@ fn finishStructInit( if (root_msg) |msg| { if (mod.typeToStruct(struct_ty)) |struct_type| { const decl = mod.declPtr(struct_type.decl.unwrap().?); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.fullyQualifiedName(mod); try mod.errNoteNonLazy( decl.srcLoc(mod), msg, @@ -21404,10 +21395,9 @@ fn zirReify( const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), - .ty = undefined, + .decl_index = new_decl_index, .file_scope = block.getFileScope(mod), }); - const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); const opaque_ty = try mod.intern(.{ .opaque_type = .{ @@ -21420,7 +21410,6 @@ fn zirReify( new_decl.ty = Type.type; new_decl.val = Value.fromInterned(opaque_ty); - new_namespace.ty = Type.fromInterned(opaque_ty); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); @@ -21614,10 +21603,9 @@ fn zirReify( const new_namespace_index = try mod.createNamespace(.{ .parent = block.namespace.toOptional(), - .ty = undefined, + .decl_index = new_decl_index, .file_scope = block.getFileScope(mod), }); - const new_namespace = mod.namespacePtr(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index); const union_ty = try ip.getUnionType(gpa, .{ @@ -21649,7 +21637,6 @@ fn zirReify( new_decl.ty = Type.type; new_decl.val = Value.fromInterned(union_ty); - new_namespace.ty = Type.fromInterned(union_ty); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); @@ -37260,7 +37247,7 @@ fn generateUnionTagTypeNumbered( const src_decl = mod.declPtr(block.src_decl); const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); errdefer mod.destroyDecl(new_decl_index); - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.fullyQualifiedName(mod); const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)}); try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{ .ty = Type.noreturn, @@ -37269,7 +37256,6 @@ fn generateUnionTagTypeNumbered( errdefer mod.abortAnonDecl(new_decl_index); const new_decl = mod.declPtr(new_decl_index); - new_decl.name_fully_qualified = true; new_decl.owns_tv = true; new_decl.name_fully_qualified = true; @@ -37310,7 +37296,7 @@ fn generateUnionTagTypeSimple( .val = Value.@"unreachable", }); }; - const fqn = try mod.declPtr(decl_index).getFullyQualifiedName(mod); + const fqn = try mod.declPtr(decl_index).fullyQualifiedName(mod); const src_decl = mod.declPtr(block.src_decl); const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); errdefer mod.destroyDecl(new_decl_index); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 4540724778..781190e13b 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -7223,7 +7223,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const fqn = ip.stringToSlice(try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod)); + const fqn = ip.stringToSlice(try mod.declPtr(enum_decl_index).fullyQualifiedName(mod)); const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); // check if we already generated code for this. diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 2031603696..4d444c686b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1163,7 +1163,7 @@ pub const Object = struct { const fwd_ref = self.debug_unresolved_namespace_scopes.values()[i]; const namespace = self.module.namespacePtr(namespace_index); - const debug_type = try self.lowerDebugType(namespace.ty); + const debug_type = try self.lowerDebugType(namespace.getType(self.module)); self.builder.debugForwardReferenceSetType(fwd_ref, debug_type); } @@ -1797,7 +1797,7 @@ pub const Object = struct { return updateExportedGlobal(self, mod, global_index, exports); } else { const fqn = try self.builder.string( - mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)), + mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)), ); try global_index.rename(fqn, &self.builder); global_index.setLinkage(.internal, &self.builder); @@ -2835,15 +2835,13 @@ pub const Object = struct { const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin"); const std_namespace = mod.namespacePtr(mod.declPtr(std_file.root_decl.unwrap().?).src_namespace); - const builtin_decl = std_namespace.decls - .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?; + const builtin_decl = std_namespace.decls.getKeyAdapted(builtin_str, Module.DeclAdapter{ .zcu = mod }).?; const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace"); // buffer is only used for int_type, `builtin` is a struct. const builtin_ty = mod.declPtr(builtin_decl).val.toType(); const builtin_namespace = builtin_ty.getNamespace(mod).?; - const stack_trace_decl_index = builtin_namespace.decls - .getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?; + const stack_trace_decl_index = builtin_namespace.decls.getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .zcu = mod }).?; const stack_trace_decl = mod.declPtr(stack_trace_decl_index); // Sema should have ensured that StackTrace was analyzed. @@ -2886,7 +2884,7 @@ pub const Object = struct { try o.builder.string(ip.stringToSlice(if (is_extern) decl.name else - try decl.getFullyQualifiedName(zcu))), + try decl.fullyQualifiedName(zcu))), toLlvmAddressSpace(decl.@"addrspace", target), ); gop.value_ptr.* = function_index.ptrConst(&o.builder).global; @@ -3100,7 +3098,7 @@ pub const Object = struct { const variable_index = try o.builder.addVariable( try o.builder.string(mod.intern_pool.stringToSlice( - if (is_extern) decl.name else try decl.getFullyQualifiedName(mod), + if (is_extern) decl.name else try decl.fullyQualifiedName(mod), )), try o.lowerType(decl.ty), toLlvmGlobalAddressSpace(decl.@"addrspace", mod.getTarget()), @@ -3325,7 +3323,7 @@ pub const Object = struct { } const name = try o.builder.string(ip.stringToSlice( - try mod.declPtr(struct_type.decl.unwrap().?).getFullyQualifiedName(mod), + try mod.declPtr(struct_type.decl.unwrap().?).fullyQualifiedName(mod), )); var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){}; @@ -3481,7 +3479,7 @@ pub const Object = struct { } const name = try o.builder.string(ip.stringToSlice( - try mod.declPtr(union_obj.decl).getFullyQualifiedName(mod), + try mod.declPtr(union_obj.decl).fullyQualifiedName(mod), )); const aligned_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[layout.most_aligned_field]); @@ -4599,7 +4597,7 @@ pub const Object = struct { const usize_ty = try o.lowerType(Type.usize); const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0); - const fqn = try zcu.declPtr(enum_type.decl).getFullyQualifiedName(zcu); + const fqn = try zcu.declPtr(enum_type.decl).fullyQualifiedName(zcu); const target = zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), @@ -6613,7 +6611,7 @@ pub const FuncGen = struct { .base_line = self.base_line, }); - const fqn = try decl.getFullyQualifiedName(zcu); + const fqn = try decl.fullyQualifiedName(zcu); const is_internal_linkage = !zcu.decl_exports.contains(decl_index); const fn_ty = try zcu.funcType(.{ @@ -9643,7 +9641,7 @@ pub const FuncGen = struct { if (gop.found_existing) return gop.value_ptr.*; errdefer assert(o.named_enum_map.remove(enum_type.decl)); - const fqn = try zcu.declPtr(enum_type.decl).getFullyQualifiedName(zcu); + const fqn = try zcu.declPtr(enum_type.decl).fullyQualifiedName(zcu); const target = zcu.root_mod.resolved_target.result; const function_index = try o.builder.addFunction( try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index cbc6ae1eb3..dc3b646ab7 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -2019,7 +2019,7 @@ const DeclGen = struct { // Append the actual code into the functions section. try self.spv.addFunction(spv_decl_index, self.func); - const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); + const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module)); try self.spv.debugName(decl_id, fqn); // Temporarily generate a test kernel declaration if this is a test function. @@ -2055,7 +2055,7 @@ const DeclGen = struct { .id_result = decl_id, .storage_class = actual_storage_class, }); - const fqn = ip.stringToSlice(try decl.getFullyQualifiedName(self.module)); + const fqn = ip.stringToSlice(try decl.fullyQualifiedName(self.module)); try self.spv.debugName(decl_id, fqn); if (opt_init_val) |init_val| { diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 9be6d18df1..5bf83b52ea 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1176,7 +1176,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.Dec gop.value_ptr.* = .{}; } const unnamed_consts = gop.value_ptr; - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); const index = unnamed_consts.items.len; const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(sym_name); @@ -1427,7 +1427,7 @@ fn updateDeclCode(self: *Coff, decl_index: InternPool.DeclIndex, code: []u8, com const mod = self.base.comp.module.?; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0)); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index f5f754e03b..a9a6942299 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -1082,7 +1082,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde defer tracy.end(); const decl = mod.declPtr(decl_index); - const decl_linkage_name = try decl.getFullyQualifiedName(mod); + const decl_linkage_name = try decl.fullyQualifiedName(mod); log.debug("initDeclState {}{*}", .{ decl_linkage_name.fmt(&mod.intern_pool), decl }); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index ea32f93584..b6413f7d45 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -903,7 +903,7 @@ fn updateDeclCode( const gpa = elf_file.base.comp.gpa; const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); @@ -1001,7 +1001,7 @@ fn updateTlv( const gpa = elf_file.base.comp.gpa; const mod = elf_file.base.comp.module.?; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateTlv {s} ({*})", .{ decl_name, decl }); @@ -1300,7 +1300,7 @@ pub fn lowerUnnamedConst( } const unnamed_consts = gop.value_ptr; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); const index = unnamed_consts.items.len; const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(name); @@ -1482,7 +1482,7 @@ pub fn updateDeclLineNumber( defer tracy.end(); const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 3a28e824d5..fadf80b2c0 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -792,7 +792,7 @@ fn updateDeclCode( const gpa = macho_file.base.comp.gpa; const mod = macho_file.base.comp.module.?; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); @@ -876,7 +876,7 @@ fn updateTlv( ) !void { const mod = macho_file.base.comp.module.?; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateTlv {s} ({*})", .{ decl_name, decl }); @@ -1079,7 +1079,7 @@ pub fn lowerUnnamedConst( } const unnamed_consts = gop.value_ptr; const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); const index = unnamed_consts.items.len; const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(name); diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 2e937a3904..be68465af7 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -478,7 +478,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De } const unnamed_consts = gop.value_ptr; - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); const index = unnamed_consts.items.len; // name is freed when the unnamed const is freed diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 1a06d0fc6e..f4bc2f8f0f 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -662,7 +662,7 @@ pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !At const symbol = atom.symbolLoc().getSymbol(wasm); const mod = wasm.base.comp.module.?; const decl = mod.declPtr(decl_index); - const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); symbol.name = try wasm.string_table.put(gpa, full_name); } return gop.value_ptr.*; @@ -1598,7 +1598,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.De defer tracy.end(); const decl = mod.declPtr(decl_index); - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const decl_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); try dw.updateDeclLineNumber(mod, decl_index); @@ -1612,7 +1612,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex, code: []const const atom_index = wasm.decls.get(decl_index).?; const atom = wasm.getAtomPtr(atom_index); const symbol = &wasm.symbols.items[atom.sym_index]; - const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const full_name = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); symbol.name = try wasm.string_table.put(gpa, full_name); symbol.tag = symbol_tag; try atom.code.appendSlice(gpa, code); @@ -1678,7 +1678,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: InternPool.Dec const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index); const parent_atom = wasm.getAtom(parent_atom_index); const local_index = parent_atom.locals.items.len; - const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const fqn = mod.intern_pool.stringToSlice(try decl.fullyQualifiedName(mod)); const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{ fqn, local_index, }); diff --git a/src/main.zig b/src/main.zig index db739ebce7..bb8b25c60e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -596,7 +596,7 @@ const usage_build_generic = \\ --export=[value] (WebAssembly) Force a symbol to be exported \\ \\Test Options: - \\ --test-filter [text] Skip tests that do not match filter + \\ --test-filter [text] Skip tests that do not match any filter \\ --test-name-prefix [text] Add prefix to all tests \\ --test-cmd [arg] Specify test execution command one arg at a time \\ --test-cmd-bin Appends test binary path to test cmd args @@ -869,7 +869,7 @@ fn buildOutputType( var link_emit_relocs = false; var build_id: ?std.zig.BuildId = null; var runtime_args_start: ?usize = null; - var test_filter: ?[]const u8 = null; + var test_filters: std.ArrayListUnmanaged([]const u8) = .{}; var test_name_prefix: ?[]const u8 = null; var test_runner_path: ?[]const u8 = null; var override_local_cache_dir: ?[]const u8 = try EnvVar.ZIG_LOCAL_CACHE_DIR.get(arena); @@ -909,7 +909,7 @@ fn buildOutputType( var rc_source_files_owner_index: usize = 0; // null means replace with the test executable binary - var test_exec_args = std.ArrayList(?[]const u8).init(arena); + var test_exec_args: std.ArrayListUnmanaged(?[]const u8) = .{}; // These get set by CLI flags and then snapshotted when a `--mod` flag is // encountered. @@ -1278,13 +1278,13 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "--libc")) { create_module.libc_paths_file = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--test-filter")) { - test_filter = args_iter.nextOrFatal(); + try test_filters.append(arena, args_iter.nextOrFatal()); } else if (mem.eql(u8, arg, "--test-name-prefix")) { test_name_prefix = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--test-runner")) { test_runner_path = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--test-cmd")) { - try test_exec_args.append(args_iter.nextOrFatal()); + try test_exec_args.append(arena, args_iter.nextOrFatal()); } else if (mem.eql(u8, arg, "--cache-dir")) { override_local_cache_dir = args_iter.nextOrFatal(); } else if (mem.eql(u8, arg, "--global-cache-dir")) { @@ -1334,7 +1334,7 @@ fn buildOutputType( } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) { create_module.each_lib_rpath = false; } else if (mem.eql(u8, arg, "--test-cmd-bin")) { - try test_exec_args.append(null); + try test_exec_args.append(arena, null); } else if (mem.eql(u8, arg, "--test-no-exec")) { test_no_exec = true; } else if (mem.eql(u8, arg, "-ftime-report")) { @@ -3246,7 +3246,7 @@ fn buildOutputType( .time_report = time_report, .stack_report = stack_report, .build_id = build_id, - .test_filter = test_filter, + .test_filters = test_filters.items, .test_name_prefix = test_name_prefix, .test_runner_path = test_runner_path, .disable_lld_caching = disable_lld_caching, @@ -3369,16 +3369,15 @@ fn buildOutputType( const c_code_path = try fs.path.join(arena, &[_][]const u8{ c_code_directory.path orelse ".", c_code_loc.basename, }); - try test_exec_args.append(self_exe_path); - try test_exec_args.append("run"); + try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" }); if (zig_lib_directory.path) |p| { - try test_exec_args.appendSlice(&.{ "-I", p }); + try test_exec_args.appendSlice(arena, &.{ "-I", p }); } if (create_module.resolved_options.link_libc) { - try test_exec_args.append("-lc"); + try test_exec_args.append(arena, "-lc"); } else if (target.os.tag == .windows) { - try test_exec_args.appendSlice(&.{ + try test_exec_args.appendSlice(arena, &.{ "--subsystem", "console", "-lkernel32", "-lntdll", }); @@ -3386,17 +3385,15 @@ fn buildOutputType( const first_cli_mod = create_module.modules.values()[0]; if (first_cli_mod.target_arch_os_abi) |triple| { - try test_exec_args.append("-target"); - try test_exec_args.append(triple); + try test_exec_args.appendSlice(arena, &.{ "-target", triple }); } if (first_cli_mod.target_mcpu) |mcpu| { - try test_exec_args.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu})); + try test_exec_args.append(arena, try std.fmt.allocPrint(arena, "-mcpu={s}", .{mcpu})); } if (create_module.dynamic_linker) |dl| { - try test_exec_args.append("--dynamic-linker"); - try test_exec_args.append(dl); + try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl }); } - try test_exec_args.append(c_code_path); + try test_exec_args.append(arena, c_code_path); } const run_or_test = switch (arg_mode) { diff --git a/test/src/Cases.zig b/test/src/Cases.zig index 3e3470dfe5..58e41fc4fe 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -537,7 +537,7 @@ pub fn lowerToBuildSteps( self: *Cases, b: *std.Build, parent_step: *std.Build.Step, - opt_test_filter: ?[]const u8, + test_filters: []const []const u8, cases_dir_path: []const u8, incremental_exe: *std.Build.Step.Compile, ) void { @@ -552,9 +552,9 @@ pub fn lowerToBuildSteps( // compilation is in a happier state. continue; } - if (opt_test_filter) |test_filter| { - if (std.mem.indexOf(u8, incr_case.base_path, test_filter) == null) continue; - } + for (test_filters) |test_filter| { + if (std.mem.indexOf(u8, incr_case.base_path, test_filter)) |_| break; + } else if (test_filters.len > 0) continue; const case_base_path_with_dir = std.fs.path.join(b.allocator, &.{ cases_dir_path, incr_case.base_path, }) catch @panic("OOM"); @@ -573,9 +573,9 @@ pub fn lowerToBuildSteps( assert(case.updates.items.len == 1); const update = case.updates.items[0]; - if (opt_test_filter) |test_filter| { - if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; - } + for (test_filters) |test_filter| { + if (std.mem.indexOf(u8, case.name, test_filter)) |_| break; + } else if (test_filters.len > 0) continue; const writefiles = b.addWriteFiles(); var file_sources = std.StringHashMap(std.Build.LazyPath).init(b.allocator); @@ -685,9 +685,9 @@ pub fn lowerToBuildSteps( for (self.translate.items) |case| switch (case.kind) { .run => |output| { const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name}); - if (opt_test_filter) |filter| { - if (std.mem.indexOf(u8, annotated_case_name, filter) == null) continue; - } + for (test_filters) |test_filter| { + if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (test_filters.len > 0) continue; if (!std.process.can_spawn) { std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)}); continue; // Pass test. @@ -721,9 +721,9 @@ pub fn lowerToBuildSteps( }, .translate => |output| { const annotated_case_name = b.fmt("zig translate-c {s}", .{case.name}); - if (opt_test_filter) |filter| { - if (std.mem.indexOf(u8, annotated_case_name, filter) == null) continue; - } + for (test_filters) |test_filter| { + if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (test_filters.len > 0) continue; const write_src = b.addWriteFiles(); const file_source = write_src.add("tmp.c", case.input); @@ -1440,9 +1440,9 @@ fn runCases(self: *Cases, zig_exe_path: []const u8) !void { assert(case.backend != .stage1); - if (build_options.test_filter) |test_filter| { - if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; - } + for (build_options.test_filters) |test_filter| { + if (std.mem.indexOf(u8, case.name, test_filter)) |_| break; + } else if (build_options.test_filters.len > 0) continue; var prg_node = root_node.start(case.name, case.updates.items.len); prg_node.activate(); diff --git a/test/src/CompareOutput.zig b/test/src/CompareOutput.zig index b3570b6ee2..7d0440c890 100644 --- a/test/src/CompareOutput.zig +++ b/test/src/CompareOutput.zig @@ -4,7 +4,7 @@ b: *std.Build, step: *std.Build.Step, test_index: usize, -test_filter: ?[]const u8, +test_filters: []const []const u8, optimize_modes: []const OptimizeMode, const Special = enum { @@ -90,9 +90,9 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { const annotated_case_name = fmt.allocPrint(self.b.allocator, "run assemble-and-link {s}", .{ case.name, }) catch @panic("OOM"); - if (self.test_filter) |filter| { - if (mem.indexOf(u8, annotated_case_name, filter) == null) return; - } + for (self.test_filters) |test_filter| { + if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (self.test_filters.len > 0) return; const exe = b.addExecutable(.{ .name = "test", @@ -113,9 +113,9 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { const annotated_case_name = fmt.allocPrint(self.b.allocator, "run compare-output {s} ({s})", .{ case.name, @tagName(optimize), }) catch @panic("OOM"); - if (self.test_filter) |filter| { - if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; - } + for (self.test_filters) |test_filter| { + if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (self.test_filters.len > 0) return; const exe = b.addExecutable(.{ .name = "test", @@ -139,9 +139,9 @@ pub fn addCase(self: *CompareOutput, case: TestCase) void { // TODO iterate over self.optimize_modes and test this in both // debug and release safe mode const annotated_case_name = fmt.allocPrint(self.b.allocator, "run safety {s}", .{case.name}) catch @panic("OOM"); - if (self.test_filter) |filter| { - if (mem.indexOf(u8, annotated_case_name, filter) == null) return; - } + for (self.test_filters) |test_filter| { + if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (self.test_filters.len > 0) return; const exe = b.addExecutable(.{ .name = "test", diff --git a/test/src/RunTranslatedC.zig b/test/src/RunTranslatedC.zig new file mode 100644 index 0000000000..8414bd15ac --- /dev/null +++ b/test/src/RunTranslatedC.zig @@ -0,0 +1,103 @@ +b: *std.Build, +step: *std.Build.Step, +test_index: usize, +test_filters: []const []const u8, +target: std.Build.ResolvedTarget, + +const TestCase = struct { + name: []const u8, + sources: ArrayList(SourceFile), + expected_stdout: []const u8, + allow_warnings: bool, + + const SourceFile = struct { + filename: []const u8, + source: []const u8, + }; + + pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void { + self.sources.append(SourceFile{ + .filename = filename, + .source = source, + }) catch unreachable; + } +}; + +pub fn create( + self: *RunTranslatedCContext, + allow_warnings: bool, + filename: []const u8, + name: []const u8, + source: []const u8, + expected_stdout: []const u8, +) *TestCase { + const tc = self.b.allocator.create(TestCase) catch unreachable; + tc.* = TestCase{ + .name = name, + .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), + .expected_stdout = expected_stdout, + .allow_warnings = allow_warnings, + }; + + tc.addSourceFile(filename, source); + return tc; +} + +pub fn add( + self: *RunTranslatedCContext, + name: []const u8, + source: []const u8, + expected_stdout: []const u8, +) void { + const tc = self.create(false, "source.c", name, source, expected_stdout); + self.addCase(tc); +} + +pub fn addAllowWarnings( + self: *RunTranslatedCContext, + name: []const u8, + source: []const u8, + expected_stdout: []const u8, +) void { + const tc = self.create(true, "source.c", name, source, expected_stdout); + self.addCase(tc); +} + +pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { + const b = self.b; + + const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {s}", .{case.name}) catch unreachable; + for (self.test_filters) |test_filter| { + if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (self.test_filters.len > 0) return; + + const write_src = b.addWriteFiles(); + for (case.sources.items) |src_file| { + _ = write_src.add(src_file.filename, src_file.source); + } + const translate_c = b.addTranslateC(.{ + .root_source_file = write_src.files.items[0].getPath(), + .target = b.host, + .optimize = .Debug, + }); + + translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name}); + const exe = translate_c.addExecutable(.{}); + exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name}); + exe.linkLibC(); + const run = b.addRunArtifact(exe); + run.step.name = b.fmt("{s} run", .{annotated_case_name}); + if (!case.allow_warnings) { + run.expectStdErrEqual(""); + } + run.expectStdOutEqual(case.expected_stdout); + + self.step.dependOn(&run.step); +} + +const RunTranslatedCContext = @This(); +const std = @import("std"); +const ArrayList = std.ArrayList; +const fmt = std.fmt; +const mem = std.mem; +const fs = std.fs; diff --git a/test/src/StackTrace.zig b/test/src/StackTrace.zig index 191c350091..80c6c2f548 100644 --- a/test/src/StackTrace.zig +++ b/test/src/StackTrace.zig @@ -1,7 +1,7 @@ b: *std.Build, step: *Step, test_index: usize, -test_filter: ?[]const u8, +test_filters: []const []const u8, optimize_modes: []const OptimizeMode, check_exe: *std.Build.Step.Compile, @@ -47,9 +47,9 @@ fn addExpect( const annotated_case_name = fmt.allocPrint(b.allocator, "check {s} ({s})", .{ name, @tagName(optimize_mode), }) catch @panic("OOM"); - if (self.test_filter) |filter| { - if (mem.indexOf(u8, annotated_case_name, filter) == null) return; - } + for (self.test_filters) |test_filter| { + if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (self.test_filters.len > 0) return; const write_src = b.addWriteFile("source.zig", source); const exe = b.addExecutable(.{ diff --git a/test/src/TranslateC.zig b/test/src/TranslateC.zig new file mode 100644 index 0000000000..7a75cd64b7 --- /dev/null +++ b/test/src/TranslateC.zig @@ -0,0 +1,118 @@ +b: *std.Build, +step: *std.Build.Step, +test_index: usize, +test_filters: []const []const u8, + +const TestCase = struct { + name: []const u8, + sources: ArrayList(SourceFile), + expected_lines: ArrayList([]const u8), + allow_warnings: bool, + target: std.Target.Query = .{}, + + const SourceFile = struct { + filename: []const u8, + source: []const u8, + }; + + pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void { + self.sources.append(SourceFile{ + .filename = filename, + .source = source, + }) catch unreachable; + } + + pub fn addExpectedLine(self: *TestCase, text: []const u8) void { + self.expected_lines.append(text) catch unreachable; + } +}; + +pub fn create( + self: *TranslateCContext, + allow_warnings: bool, + filename: []const u8, + name: []const u8, + source: []const u8, + expected_lines: []const []const u8, +) *TestCase { + const tc = self.b.allocator.create(TestCase) catch unreachable; + tc.* = TestCase{ + .name = name, + .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), + .expected_lines = ArrayList([]const u8).init(self.b.allocator), + .allow_warnings = allow_warnings, + }; + + tc.addSourceFile(filename, source); + var arg_i: usize = 0; + while (arg_i < expected_lines.len) : (arg_i += 1) { + tc.addExpectedLine(expected_lines[arg_i]); + } + return tc; +} + +pub fn add( + self: *TranslateCContext, + name: []const u8, + source: []const u8, + expected_lines: []const []const u8, +) void { + const tc = self.create(false, "source.h", name, source, expected_lines); + self.addCase(tc); +} + +pub fn addWithTarget( + self: *TranslateCContext, + name: []const u8, + target: std.Target.Query, + source: []const u8, + expected_lines: []const []const u8, +) void { + const tc = self.create(false, "source.h", name, source, expected_lines); + tc.target = target; + self.addCase(tc); +} + +pub fn addAllowWarnings( + self: *TranslateCContext, + name: []const u8, + source: []const u8, + expected_lines: []const []const u8, +) void { + const tc = self.create(true, "source.h", name, source, expected_lines); + self.addCase(tc); +} + +pub fn addCase(self: *TranslateCContext, case: *const TestCase) void { + const b = self.b; + + const translate_c_cmd = "translate-c"; + const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s}", .{ translate_c_cmd, case.name }) catch unreachable; + for (self.test_filters) |test_filter| { + if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break; + } else if (self.test_filters.len > 0) return; + + const write_src = b.addWriteFiles(); + for (case.sources.items) |src_file| { + _ = write_src.add(src_file.filename, src_file.source); + } + + const translate_c = b.addTranslateC(.{ + .root_source_file = write_src.files.items[0].getPath(), + .target = b.resolveTargetQuery(case.target), + .optimize = .Debug, + }); + + translate_c.step.name = annotated_case_name; + + const check_file = translate_c.addCheckFile(case.expected_lines.items); + + self.step.dependOn(&check_file.step); +} + +const TranslateCContext = @This(); +const std = @import("std"); +const ArrayList = std.ArrayList; +const fmt = std.fmt; +const mem = std.mem; +const fs = std.fs; diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig deleted file mode 100644 index 6db7396098..0000000000 --- a/test/src/run_translated_c.zig +++ /dev/null @@ -1,106 +0,0 @@ -// This is the implementation of the test harness for running translated -// C code. For the actual test cases, see test/run_translated_c.zig. -const std = @import("std"); -const ArrayList = std.ArrayList; -const fmt = std.fmt; -const mem = std.mem; -const fs = std.fs; - -pub const RunTranslatedCContext = struct { - b: *std.Build, - step: *std.Build.Step, - test_index: usize, - test_filter: ?[]const u8, - target: std.Build.ResolvedTarget, - - const TestCase = struct { - name: []const u8, - sources: ArrayList(SourceFile), - expected_stdout: []const u8, - allow_warnings: bool, - - const SourceFile = struct { - filename: []const u8, - source: []const u8, - }; - - pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void { - self.sources.append(SourceFile{ - .filename = filename, - .source = source, - }) catch unreachable; - } - }; - - pub fn create( - self: *RunTranslatedCContext, - allow_warnings: bool, - filename: []const u8, - name: []const u8, - source: []const u8, - expected_stdout: []const u8, - ) *TestCase { - const tc = self.b.allocator.create(TestCase) catch unreachable; - tc.* = TestCase{ - .name = name, - .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), - .expected_stdout = expected_stdout, - .allow_warnings = allow_warnings, - }; - - tc.addSourceFile(filename, source); - return tc; - } - - pub fn add( - self: *RunTranslatedCContext, - name: []const u8, - source: []const u8, - expected_stdout: []const u8, - ) void { - const tc = self.create(false, "source.c", name, source, expected_stdout); - self.addCase(tc); - } - - pub fn addAllowWarnings( - self: *RunTranslatedCContext, - name: []const u8, - source: []const u8, - expected_stdout: []const u8, - ) void { - const tc = self.create(true, "source.c", name, source, expected_stdout); - self.addCase(tc); - } - - pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { - const b = self.b; - - const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {s}", .{case.name}) catch unreachable; - if (self.test_filter) |filter| { - if (mem.indexOf(u8, annotated_case_name, filter) == null) return; - } - - const write_src = b.addWriteFiles(); - for (case.sources.items) |src_file| { - _ = write_src.add(src_file.filename, src_file.source); - } - const translate_c = b.addTranslateC(.{ - .root_source_file = write_src.files.items[0].getPath(), - .target = b.host, - .optimize = .Debug, - }); - - translate_c.step.name = b.fmt("{s} translate-c", .{annotated_case_name}); - const exe = translate_c.addExecutable(.{}); - exe.step.name = b.fmt("{s} build-exe", .{annotated_case_name}); - exe.linkLibC(); - const run = b.addRunArtifact(exe); - run.step.name = b.fmt("{s} run", .{annotated_case_name}); - if (!case.allow_warnings) { - run.expectStdErrEqual(""); - } - run.expectStdOutEqual(case.expected_stdout); - - self.step.dependOn(&run.step); - } -}; diff --git a/test/src/translate_c.zig b/test/src/translate_c.zig deleted file mode 100644 index 7858d1b37c..0000000000 --- a/test/src/translate_c.zig +++ /dev/null @@ -1,121 +0,0 @@ -// This is the implementation of the test harness. -// For the actual test cases, see test/translate_c.zig. -const std = @import("std"); -const ArrayList = std.ArrayList; -const fmt = std.fmt; -const mem = std.mem; -const fs = std.fs; - -pub const TranslateCContext = struct { - b: *std.Build, - step: *std.Build.Step, - test_index: usize, - test_filter: ?[]const u8, - - const TestCase = struct { - name: []const u8, - sources: ArrayList(SourceFile), - expected_lines: ArrayList([]const u8), - allow_warnings: bool, - target: std.Target.Query = .{}, - - const SourceFile = struct { - filename: []const u8, - source: []const u8, - }; - - pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void { - self.sources.append(SourceFile{ - .filename = filename, - .source = source, - }) catch unreachable; - } - - pub fn addExpectedLine(self: *TestCase, text: []const u8) void { - self.expected_lines.append(text) catch unreachable; - } - }; - - pub fn create( - self: *TranslateCContext, - allow_warnings: bool, - filename: []const u8, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) *TestCase { - const tc = self.b.allocator.create(TestCase) catch unreachable; - tc.* = TestCase{ - .name = name, - .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), - .expected_lines = ArrayList([]const u8).init(self.b.allocator), - .allow_warnings = allow_warnings, - }; - - tc.addSourceFile(filename, source); - var arg_i: usize = 0; - while (arg_i < expected_lines.len) : (arg_i += 1) { - tc.addExpectedLine(expected_lines[arg_i]); - } - return tc; - } - - pub fn add( - self: *TranslateCContext, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) void { - const tc = self.create(false, "source.h", name, source, expected_lines); - self.addCase(tc); - } - - pub fn addWithTarget( - self: *TranslateCContext, - name: []const u8, - target: std.Target.Query, - source: []const u8, - expected_lines: []const []const u8, - ) void { - const tc = self.create(false, "source.h", name, source, expected_lines); - tc.target = target; - self.addCase(tc); - } - - pub fn addAllowWarnings( - self: *TranslateCContext, - name: []const u8, - source: []const u8, - expected_lines: []const []const u8, - ) void { - const tc = self.create(true, "source.h", name, source, expected_lines); - self.addCase(tc); - } - - pub fn addCase(self: *TranslateCContext, case: *const TestCase) void { - const b = self.b; - - const translate_c_cmd = "translate-c"; - const annotated_case_name = fmt.allocPrint(self.b.allocator, "{s} {s}", .{ translate_c_cmd, case.name }) catch unreachable; - if (self.test_filter) |filter| { - if (mem.indexOf(u8, annotated_case_name, filter) == null) return; - } - - const write_src = b.addWriteFiles(); - for (case.sources.items) |src_file| { - _ = write_src.add(src_file.filename, src_file.source); - } - - const translate_c = b.addTranslateC(.{ - .root_source_file = write_src.files.items[0].getPath(), - .target = b.resolveTargetQuery(case.target), - .optimize = .Debug, - }); - - translate_c.step.name = annotated_case_name; - - const check_file = translate_c.addCheckFile(case.expected_lines.items); - - self.step.dependOn(&check_file.step); - } -}; diff --git a/test/tests.zig b/test/tests.zig index f7e65b6af9..e1ec5db610 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -15,8 +15,8 @@ const run_translated_c = @import("run_translated_c.zig"); const link = @import("link.zig"); // Implementations -pub const TranslateCContext = @import("src/translate_c.zig").TranslateCContext; -pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext; +pub const TranslateCContext = @import("src/TranslateC.zig"); +pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig"); pub const CompareOutputContext = @import("src/CompareOutput.zig"); pub const StackTracesContext = @import("src/StackTrace.zig"); @@ -619,7 +619,7 @@ const c_abi_targets = [_]CAbiTarget{ pub fn addCompareOutputTests( b: *std.Build, - test_filter: ?[]const u8, + test_filters: []const []const u8, optimize_modes: []const OptimizeMode, ) *Step { const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM"); @@ -627,7 +627,7 @@ pub fn addCompareOutputTests( .b = b, .step = b.step("test-compare-output", "Run the compare output tests"), .test_index = 0, - .test_filter = test_filter, + .test_filters = test_filters, .optimize_modes = optimize_modes, }; @@ -638,7 +638,7 @@ pub fn addCompareOutputTests( pub fn addStackTraceTests( b: *std.Build, - test_filter: ?[]const u8, + test_filters: []const []const u8, optimize_modes: []const OptimizeMode, ) *Step { const check_exe = b.addExecutable(.{ @@ -653,7 +653,7 @@ pub fn addStackTraceTests( .b = b, .step = b.step("test-stack-traces", "Run the stack trace tests"), .test_index = 0, - .test_filter = test_filter, + .test_filters = test_filters, .optimize_modes = optimize_modes, .check_exe = check_exe, }; @@ -983,13 +983,13 @@ pub fn addCliTests(b: *std.Build) *Step { return step; } -pub fn addAssembleAndLinkTests(b: *std.Build, test_filter: ?[]const u8, optimize_modes: []const OptimizeMode) *Step { +pub fn addAssembleAndLinkTests(b: *std.Build, test_filters: []const []const u8, optimize_modes: []const OptimizeMode) *Step { const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM"); cases.* = CompareOutputContext{ .b = b, .step = b.step("test-asm-link", "Run the assemble and link tests"), .test_index = 0, - .test_filter = test_filter, + .test_filters = test_filters, .optimize_modes = optimize_modes, }; @@ -998,13 +998,13 @@ pub fn addAssembleAndLinkTests(b: *std.Build, test_filter: ?[]const u8, optimize return cases.step; } -pub fn addTranslateCTests(b: *std.Build, test_filter: ?[]const u8) *Step { +pub fn addTranslateCTests(b: *std.Build, test_filters: []const []const u8) *Step { const cases = b.allocator.create(TranslateCContext) catch @panic("OOM"); cases.* = TranslateCContext{ .b = b, .step = b.step("test-translate-c", "Run the C translation tests"), .test_index = 0, - .test_filter = test_filter, + .test_filters = test_filters, }; translate_c.addCases(cases); @@ -1014,7 +1014,7 @@ pub fn addTranslateCTests(b: *std.Build, test_filter: ?[]const u8) *Step { pub fn addRunTranslatedCTests( b: *std.Build, - test_filter: ?[]const u8, + test_filters: []const []const u8, target: std.Build.ResolvedTarget, ) *Step { const cases = b.allocator.create(RunTranslatedCContext) catch @panic("OOM"); @@ -1022,7 +1022,7 @@ pub fn addRunTranslatedCTests( .b = b, .step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"), .test_index = 0, - .test_filter = test_filter, + .test_filters = test_filters, .target = target, }; @@ -1032,7 +1032,7 @@ pub fn addRunTranslatedCTests( } const ModuleTestOptions = struct { - test_filter: ?[]const u8, + test_filters: []const []const u8, root_src: []const u8, name: []const u8, desc: []const u8, @@ -1115,7 +1115,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { .optimize = test_target.optimize_mode, .target = resolved_target, .max_rss = max_rss, - .filter = options.test_filter, + .filters = options.test_filters, .link_libc = test_target.link_libc, .single_threaded = test_target.single_threaded, .use_llvm = test_target.use_llvm, @@ -1291,7 +1291,7 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S pub fn addCases( b: *std.Build, parent_step: *Step, - opt_test_filter: ?[]const u8, + test_filters: []const []const u8, check_case_exe: *std.Build.Step.Compile, build_options: @import("cases.zig").BuildOptions, ) !void { @@ -1310,7 +1310,7 @@ pub fn addCases( cases.lowerToBuildSteps( b, parent_step, - opt_test_filter, + test_filters, cases_dir_path, check_case_exe, );