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
This commit is contained in:
Jacob Young 2024-02-25 14:04:06 +01:00 committed by Andrew Kelley
parent 429e542f3f
commit d656c2a7ab
26 changed files with 494 additions and 506 deletions

View file

@ -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(); const test_cases_options = b.addOptions();
check_case_exe.root_module.addOptions("build_options", test_cases_options); 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(?[]const u8, "glibc_runtimes_dir", b.glibc_runtimes_dir);
test_cases_options.addOption([:0]const u8, "version", version); test_cases_options.addOption([:0]const u8, "version", version);
test_cases_options.addOption(std.SemanticVersion, "semver", semver); 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_opt_modes_buf: [4]builtin.OptimizeMode = undefined;
var chosen_mode_index: usize = 0; var chosen_mode_index: usize = 0;
@ -454,7 +454,7 @@ pub fn build(b: *std.Build) !void {
}).step); }).step);
const test_cases_step = b.step("test-cases", "Run the main compiler test cases"); 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, .enable_llvm = enable_llvm,
.llvm_has_m68k = llvm_has_m68k, .llvm_has_m68k = llvm_has_m68k,
.llvm_has_csky = llvm_has_csky, .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(test_cases_step);
test_step.dependOn(tests.addModuleTests(b, .{ test_step.dependOn(tests.addModuleTests(b, .{
.test_filter = test_filter, .test_filters = test_filters,
.root_src = "test/behavior.zig", .root_src = "test/behavior.zig",
.name = "behavior", .name = "behavior",
.desc = "Run the behavior tests", .desc = "Run the behavior tests",
@ -477,7 +477,7 @@ pub fn build(b: *std.Build) !void {
})); }));
test_step.dependOn(tests.addModuleTests(b, .{ test_step.dependOn(tests.addModuleTests(b, .{
.test_filter = test_filter, .test_filters = test_filters,
.root_src = "test/c_import.zig", .root_src = "test/c_import.zig",
.name = "c-import", .name = "c-import",
.desc = "Run the @cImport tests", .desc = "Run the @cImport tests",
@ -489,7 +489,7 @@ pub fn build(b: *std.Build) !void {
})); }));
test_step.dependOn(tests.addModuleTests(b, .{ test_step.dependOn(tests.addModuleTests(b, .{
.test_filter = test_filter, .test_filters = test_filters,
.root_src = "lib/compiler_rt.zig", .root_src = "lib/compiler_rt.zig",
.name = "compiler-rt", .name = "compiler-rt",
.desc = "Run the compiler_rt tests", .desc = "Run the compiler_rt tests",
@ -501,7 +501,7 @@ pub fn build(b: *std.Build) !void {
})); }));
test_step.dependOn(tests.addModuleTests(b, .{ test_step.dependOn(tests.addModuleTests(b, .{
.test_filter = test_filter, .test_filters = test_filters,
.root_src = "lib/c.zig", .root_src = "lib/c.zig",
.name = "universal-libc", .name = "universal-libc",
.desc = "Run the universal libc tests", .desc = "Run the universal libc tests",
@ -512,7 +512,7 @@ pub fn build(b: *std.Build) !void {
.skip_libc = true, .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( test_step.dependOn(tests.addStandaloneTests(
b, b,
optimization_modes, 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.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.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.addCliTests(b));
test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, optimization_modes)); test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filters, optimization_modes));
test_step.dependOn(tests.addTranslateCTests(b, test_filter)); test_step.dependOn(tests.addTranslateCTests(b, test_filters));
if (!skip_run_translated_c) { 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_step.dependOn(tests.addModuleTests(b, .{
.test_filter = test_filter, .test_filters = test_filters,
.root_src = "lib/std/std.zig", .root_src = "lib/std/std.zig",
.name = "std", .name = "std",
.desc = "Run the standard library tests", .desc = "Run the standard library tests",

View file

@ -988,13 +988,13 @@ fn addOne(number: i32) i32 {
printed to standard error by the default test runner: printed to standard error by the default test runner:
</p> </p>
<dl> <dl>
<dt><samp>Test [1/2] test.expect addOne adds one to 41...</samp></dt> <dt><samp>1/2 testing_introduction.test.expect addOne adds one to 41...</samp></dt>
<dd>Lines like this indicate which test, out of the total number of tests, is being run. <dd>Lines like this indicate which test, out of the total number of tests, is being run.
In this case, <samp>[1/2]</samp> indicates that the first test, out of a total of In this case, <samp>1/2</samp> indicates that the first test, out of a total of two tests,
two test, is being run. Note that, when the test runner program's standard error is output 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. to the terminal, these lines are cleared when a test succeeds.
</dd> </dd>
<dt><samp>Test [2/2] decltest.addOne...</samp></dt> <dt><samp>2/2 testing_introduction.decltest.addOne...</samp></dt>
<dd>When the test name is an identifier, the default test runner uses the text <dd>When the test name is an identifier, the default test runner uses the text
decltest instead of test. decltest instead of test.
</dd> </dd>

View file

@ -855,7 +855,9 @@ pub const TestOptions = struct {
optimize: std.builtin.OptimizeMode = .Debug, optimize: std.builtin.OptimizeMode = .Debug,
version: ?std.SemanticVersion = null, version: ?std.SemanticVersion = null,
max_rss: usize = 0, max_rss: usize = 0,
/// deprecated: use `.filters = &.{filter}` instead of `.filter = filter`.
filter: ?[]const u8 = null, filter: ?[]const u8 = null,
filters: []const []const u8 = &.{},
test_runner: ?[]const u8 = null, test_runner: ?[]const u8 = null,
link_libc: ?bool = null, link_libc: ?bool = null,
single_threaded: ?bool = null, single_threaded: ?bool = null,
@ -888,7 +890,12 @@ pub fn addTest(b: *Build, options: TestOptions) *Step.Compile {
.error_tracing = options.error_tracing, .error_tracing = options.error_tracing,
}, },
.max_rss = options.max_rss, .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, .test_runner = options.test_runner,
.use_llvm = options.use_llvm, .use_llvm = options.use_llvm,
.use_lld = options.use_lld, .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. /// Duplicates an array of strings without the need to handle out of memory.
pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 { pub fn dupeStrings(self: *Build, strings: []const []const u8) [][]u8 {
const array = self.allocator.alloc([]u8, strings.len) catch @panic("OOM"); const array = self.allocator.alloc([]u8, strings.len) catch @panic("OOM");
for (strings, 0..) |s, i| { for (array, strings) |*dest, source| dest.* = self.dupe(source);
array[i] = self.dupe(s);
}
return array; return array;
} }

View file

@ -54,7 +54,7 @@ global_base: ?u64 = null,
/// Set via options; intended to be read-only after that. /// Set via options; intended to be read-only after that.
zig_lib_dir: ?LazyPath, zig_lib_dir: ?LazyPath,
exec_cmd_args: ?[]const ?[]const u8, exec_cmd_args: ?[]const ?[]const u8,
filter: ?[]const u8, filters: []const []const u8,
test_runner: ?[]const u8, test_runner: ?[]const u8,
test_server_mode: bool, test_server_mode: bool,
wasi_exec_model: ?std.builtin.WasiExecModel = null, wasi_exec_model: ?std.builtin.WasiExecModel = null,
@ -223,7 +223,7 @@ pub const Options = struct {
linkage: ?Linkage = null, linkage: ?Linkage = null,
version: ?std.SemanticVersion = null, version: ?std.SemanticVersion = null,
max_rss: usize = 0, max_rss: usize = 0,
filter: ?[]const u8 = null, filters: []const []const u8 = &.{},
test_runner: ?[]const u8 = null, test_runner: ?[]const u8 = null,
use_llvm: ?bool = null, use_llvm: ?bool = null,
use_lld: ?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), .installed_headers = ArrayList(*Step).init(owner.allocator),
.zig_lib_dir = null, .zig_lib_dir = null,
.exec_cmd_args = null, .exec_cmd_args = null,
.filter = options.filter, .filters = options.filters,
.test_runner = options.test_runner, .test_runner = options.test_runner,
.test_server_mode = options.test_runner == null, .test_server_mode = options.test_runner == null,
.rdynamic = false, .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})); 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("--test-filter");
try zig_args.append(filter); try zig_args.append(filter);
} }

View file

@ -217,7 +217,7 @@ libcxx_abi_version: libcxx.AbiVersion = libcxx.AbiVersion.default,
/// This mutex guards all `Compilation` mutable state. /// This mutex guards all `Compilation` mutable state.
mutex: std.Thread.Mutex = .{}, mutex: std.Thread.Mutex = .{},
test_filter: ?[]const u8, test_filters: []const []const u8,
test_name_prefix: ?[]const u8, test_name_prefix: ?[]const u8,
emit_asm: ?EmitLoc, emit_asm: ?EmitLoc,
@ -1097,7 +1097,7 @@ pub const CreateOptions = struct {
native_system_include_paths: []const []const u8 = &.{}, native_system_include_paths: []const []const u8 = &.{},
clang_preprocessor_mode: ClangPreprocessorMode = .no, clang_preprocessor_mode: ClangPreprocessorMode = .no,
reference_trace: ?u32 = null, reference_trace: ?u32 = null,
test_filter: ?[]const u8 = null, test_filters: []const []const u8 = &.{},
test_name_prefix: ?[]const u8 = null, test_name_prefix: ?[]const u8 = null,
test_runner_path: ?[]const u8 = null, test_runner_path: ?[]const u8 = null,
subsystem: ?std.Target.SubSystem = null, subsystem: ?std.Target.SubSystem = null,
@ -1506,7 +1506,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
.formatted_panics = formatted_panics, .formatted_panics = formatted_panics,
.time_report = options.time_report, .time_report = options.time_report,
.stack_report = options.stack_report, .stack_report = options.stack_report,
.test_filter = options.test_filter, .test_filters = options.test_filters,
.test_name_prefix = options.test_name_prefix, .test_name_prefix = options.test_name_prefix,
.debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
.debug_compile_errors = options.debug_compile_errors, .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.use_lib_llvm);
hash.add(options.config.dll_export_fns); hash.add(options.config.dll_export_fns);
hash.add(options.config.is_test); hash.add(options.config.is_test);
hash.addOptionalBytes(options.test_filter); hash.addListOfBytes(options.test_filters);
hash.addOptionalBytes(options.test_name_prefix); hash.addOptionalBytes(options.test_name_prefix);
hash.add(options.skip_linker_dependencies); hash.add(options.skip_linker_dependencies);
hash.add(formatted_panics); hash.add(formatted_panics);
@ -2475,7 +2475,7 @@ fn addNonIncrementalStuffToCacheManifest(
try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.root_mod, mod.main_mod, .{ .files = man }); try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.root_mod, mod.main_mod, .{ .files = man });
// Synchronize with other matching comments: ZigOnlyHashStuff // 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.addOptionalBytes(comp.test_name_prefix);
man.hash.add(comp.skip_linker_dependencies); man.hash.add(comp.skip_linker_dependencies);
man.hash.add(comp.formatted_panics); man.hash.add(comp.formatted_panics);

View file

@ -7904,7 +7904,7 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex)
ip.namespacePtr(index).* = .{ ip.namespacePtr(index).* = .{
.parent = undefined, .parent = undefined,
.file_scope = undefined, .file_scope = undefined,
.ty = undefined, .decl_index = undefined,
}; };
ip.namespaces_free_list.append(gpa, index) catch { ip.namespaces_free_list.append(gpa, index) catch {
// In order to keep `destroyNamespace` a non-fallible function, we ignore memory // In order to keep `destroyNamespace` a non-fallible function, we ignore memory

View file

@ -411,15 +411,15 @@ pub const Decl = struct {
/// This state detects dependency loops. /// This state detects dependency loops.
in_progress, in_progress,
/// The file corresponding to this Decl had a parse error or ZIR error. /// 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, file_failure,
/// This Decl might be OK but it depends on another one which did not /// This Decl might be OK but it depends on another one which did not
/// successfully complete semantic analysis. /// successfully complete semantic analysis.
dependency_failure, dependency_failure,
/// Semantic analysis 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, sema_failure,
/// There will be a corresponding ErrorMsg in Module.failed_decls. /// There will be a corresponding ErrorMsg in Zcu.failed_decls.
codegen_failure, codegen_failure,
/// Sematic analysis and constant value codegen of this Decl has /// Sematic analysis and constant value codegen of this Decl has
/// succeeded. However, the Decl may be outdated due to an in-progress /// 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)); return LazySrcLoc.nodeOffset(decl.nodeIndexToRelative(node_index));
} }
pub fn srcLoc(decl: Decl, mod: *Module) SrcLoc { pub fn srcLoc(decl: Decl, zcu: *Zcu) SrcLoc {
return decl.nodeOffsetSrcLoc(0, mod); 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 .{ return .{
.file_scope = decl.getFileScope(mod), .file_scope = decl.getFileScope(zcu),
.parent_decl_node = decl.src_node, .parent_decl_node = decl.src_node,
.lazy = LazySrcLoc.nodeOffset(node_offset), .lazy = LazySrcLoc.nodeOffset(node_offset),
}; };
} }
pub fn srcToken(decl: Decl, mod: *Module) Ast.TokenIndex { pub fn srcToken(decl: Decl, zcu: *Zcu) Ast.TokenIndex {
const tree = &decl.getFileScope(mod).tree; const tree = &decl.getFileScope(zcu).tree;
return tree.firstToken(decl.src_node); return tree.firstToken(decl.src_node);
} }
pub fn srcByteOffset(decl: Decl, mod: *Module) u32 { pub fn srcByteOffset(decl: Decl, zcu: *Zcu) u32 {
const tree = &decl.getFileScope(mod).tree; const tree = &decl.getFileScope(zcu).tree;
return tree.tokens.items(.start)[decl.srcToken()]; 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) { if (decl.name_fully_qualified) {
try writer.print("{}", .{decl.name.fmt(&mod.intern_pool)}); try writer.print("{}", .{decl.name.fmt(&zcu.intern_pool)});
} else { } 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 { pub fn renderFullyQualifiedDebugName(decl: Decl, zcu: *Zcu, writer: anytype) !void {
return mod.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(mod, decl.name, writer); return zcu.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(zcu, decl.name, writer);
} }
pub fn getFullyQualifiedName(decl: Decl, mod: *Module) !InternPool.NullTerminatedString { pub fn fullyQualifiedName(decl: Decl, zcu: *Zcu) !InternPool.NullTerminatedString {
if (decl.name_fully_qualified) return decl.name; return if (decl.name_fully_qualified)
decl.name
const ip = &mod.intern_pool; else
const count = count: { zcu.namespacePtr(decl.src_namespace).fullyQualifiedName(zcu, decl.name);
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 typedValue(decl: Decl) error{AnalysisFail}!TypedValue { pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue {
@ -572,38 +540,38 @@ pub const Decl = struct {
return TypedValue{ .ty = decl.ty, .val = decl.val }; 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); 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); decl.val = Value.fromInterned(ip_index);
return 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(); 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, /// If the Decl owns its value and it is a struct, return it,
/// otherwise null. /// 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.owns_tv) return null;
if (decl.val.ip_index == .none) 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, /// If the Decl owns its value and it is a union, return it,
/// otherwise null. /// 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.owns_tv) return null;
if (decl.val.ip_index == .none) 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(); const i = decl.getOwnedFunctionIndex();
if (i == .none) return null; if (i == .none) return null;
return switch (mod.intern_pool.indexToKey(i)) { return switch (zcu.intern_pool.indexToKey(i)) {
.func => |func| func, .func => |func| func,
else => null, else => null,
}; };
@ -616,24 +584,24 @@ pub const Decl = struct {
/// If the Decl owns its value and it is an extern function, returns it, /// If the Decl owns its value and it is an extern function, returns it,
/// otherwise null. /// otherwise null.
pub fn getOwnedExternFunc(decl: Decl, mod: *Module) ?InternPool.Key.ExternFunc { pub fn getOwnedExternFunc(decl: Decl, zcu: *Zcu) ?InternPool.Key.ExternFunc {
return if (decl.owns_tv) decl.val.getExternFunc(mod) else null; return if (decl.owns_tv) decl.val.getExternFunc(zcu) else null;
} }
/// If the Decl owns its value and it is a variable, returns it, /// If the Decl owns its value and it is a variable, returns it,
/// otherwise null. /// otherwise null.
pub fn getOwnedVariable(decl: Decl, mod: *Module) ?InternPool.Key.Variable { pub fn getOwnedVariable(decl: Decl, zcu: *Zcu) ?InternPool.Key.Variable {
return if (decl.owns_tv) decl.val.getVariable(mod) else null; return if (decl.owns_tv) decl.val.getVariable(zcu) else null;
} }
/// Gets the namespace that this Decl creates by being a struct, union, /// Gets the namespace that this Decl creates by being a struct, union,
/// enum, or opaque. /// 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; if (!decl.has_tv) return .none;
return switch (decl.val.ip_index) { return switch (decl.val.ip_index) {
.empty_struct_type => .none, .empty_struct_type => .none,
.none => .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(), .opaque_type => |opaque_type| opaque_type.namespace.toOptional(),
.struct_type => |struct_type| struct_type.namespace, .struct_type => |struct_type| struct_type.namespace,
.union_type => |union_type| union_type.namespace.toOptional(), .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. /// 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; if (!decl.owns_tv) return .none;
return decl.getInnerNamespaceIndex(mod); return decl.getInnerNamespaceIndex(zcu);
} }
/// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer. /// Same as `getOwnedInnerNamespaceIndex` but additionally obtains the pointer.
pub fn getOwnedInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { pub fn getOwnedInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
return mod.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(mod)); return zcu.namespacePtrUnwrap(decl.getOwnedInnerNamespaceIndex(zcu));
} }
/// Same as `getInnerNamespaceIndex` but additionally obtains the pointer. /// Same as `getInnerNamespaceIndex` but additionally obtains the pointer.
pub fn getInnerNamespace(decl: Decl, mod: *Module) ?*Namespace { pub fn getInnerNamespace(decl: Decl, zcu: *Zcu) ?*Namespace {
return mod.namespacePtrUnwrap(decl.getInnerNamespaceIndex(mod)); return zcu.namespacePtrUnwrap(decl.getInnerNamespaceIndex(zcu));
} }
pub fn dump(decl: *Decl) void { pub fn dump(decl: *Decl) void {
@ -674,27 +642,27 @@ pub const Decl = struct {
std.debug.print("\n", .{}); std.debug.print("\n", .{});
} }
pub fn getFileScope(decl: Decl, mod: *Module) *File { pub fn getFileScope(decl: Decl, zcu: *Zcu) *File {
return mod.namespacePtr(decl.src_namespace).file_scope; 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); 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, .variable => |variable| if (variable.is_extern) variable.decl.toOptional() else .none,
.extern_func => |extern_func| extern_func.decl.toOptional(), .extern_func => |extern_func| extern_func.decl.toOptional(),
else => .none, else => .none,
}; };
} }
pub fn isExtern(decl: Decl, mod: *Module) bool { pub fn isExtern(decl: Decl, zcu: *Zcu) bool {
return decl.getExternDecl(mod) != .none; 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); assert(decl.has_tv);
if (decl.alignment != .none) return decl.alignment; 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 { pub const DeclAdapter = struct {
mod: *Module, zcu: *Zcu,
pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 { pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 {
_ = self; _ = 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 { pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool {
_ = b_index; _ = b_index;
const b_decl = self.mod.declPtr(b_decl_index); return a == self.zcu.declPtr(b_decl_index).name;
return a == b_decl.name;
} }
}; };
@ -723,7 +690,7 @@ pub const Namespace = struct {
parent: OptionalIndex, parent: OptionalIndex,
file_scope: *File, file_scope: *File,
/// Will be a struct, enum, union, or opaque. /// Will be a struct, enum, union, or opaque.
ty: Type, decl_index: Decl.Index,
/// Direct children of the namespace. /// Direct children of the namespace.
/// Declaration order is preserved via entry order. /// Declaration order is preserved via entry order.
/// These are only declarations named directly by the AST; anonymous /// These are only declarations named directly by the AST; anonymous
@ -739,7 +706,7 @@ pub const Namespace = struct {
const OptionalIndex = InternPool.OptionalNamespaceIndex; const OptionalIndex = InternPool.OptionalNamespaceIndex;
const DeclContext = struct { const DeclContext = struct {
module: *Module, zcu: *Zcu,
pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 {
const decl = ctx.module.declPtr(decl_index); const decl = ctx.module.declPtr(decl_index);
@ -757,39 +724,87 @@ pub const Namespace = struct {
// This renders e.g. "std.fs.Dir.OpenOptions" // This renders e.g. "std.fs.Dir.OpenOptions"
pub fn renderFullyQualifiedName( pub fn renderFullyQualifiedName(
ns: Namespace, ns: Namespace,
mod: *Module, zcu: *Zcu,
name: InternPool.NullTerminatedString, name: InternPool.NullTerminatedString,
writer: anytype, writer: anytype,
) @TypeOf(writer).Error!void { ) @TypeOf(writer).Error!void {
if (ns.parent.unwrap()) |parent| { if (ns.parent.unwrap()) |parent| {
const decl = mod.declPtr(ns.getDeclIndex(mod)); try zcu.namespacePtr(parent).renderFullyQualifiedName(
try mod.namespacePtr(parent).renderFullyQualifiedName(mod, decl.name, writer); zcu,
zcu.declPtr(ns.decl_index).name,
writer,
);
} else { } else {
try ns.file_scope.renderFullyQualifiedName(writer); 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" /// This renders e.g. "std/fs.zig:Dir.OpenOptions"
pub fn renderFullyQualifiedDebugName( pub fn renderFullyQualifiedDebugName(
ns: Namespace, ns: Namespace,
mod: *Module, zcu: *Zcu,
name: InternPool.NullTerminatedString, name: InternPool.NullTerminatedString,
writer: anytype, writer: anytype,
) @TypeOf(writer).Error!void { ) @TypeOf(writer).Error!void {
const separator_char: u8 = if (ns.parent.unwrap()) |parent| sep: { const sep: u8 = if (ns.parent.unwrap()) |parent| sep: {
const decl = mod.declPtr(ns.getDeclIndex(mod)); try zcu.namespacePtr(parent).renderFullyQualifiedDebugName(
try mod.namespacePtr(parent).renderFullyQualifiedDebugName(mod, decl.name, writer); zcu,
zcu.declPtr(ns.decl_index).name,
writer,
);
break :sep '.'; break :sep '.';
} else sep: { } else sep: {
try ns.file_scope.renderFullyQualifiedDebugName(writer); try ns.file_scope.renderFullyQualifiedDebugName(writer);
break :sep ':'; 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 { pub fn fullyQualifiedName(
return ns.ty.getOwnerDecl(mod); 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 { pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
const decl = mod.declPtr(decl_index); const decl = mod.declPtr(decl_index);
const namespace = mod.namespacePtr(decl.src_namespace); const namespace = mod.namespacePtr(decl.src_namespace);
if (namespace.parent != .none) if (namespace.parent != .none) return false;
return false; return decl_index == namespace.decl_index;
return decl_index == namespace.getDeclIndex(mod);
} }
fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { 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); defer liveness.deinit(gpa);
if (dump_air) { 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)}); std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)});
@import("print_air.zig").dump(zcu, air, liveness); @import("print_air.zig").dump(zcu, air, liveness);
std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)}); 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. // InternPool index.
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = .none, .parent = .none,
.ty = undefined, .decl_index = undefined,
.file_scope = file, .file_scope = file,
}); });
const new_namespace = mod.namespacePtr(new_namespace_index); 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"); errdefer @panic("TODO error handling");
file.root_decl = new_decl_index.toOptional(); file.root_decl = new_decl_index.toOptional();
new_namespace.decl_index = new_decl_index;
new_decl.name = try file.fullyQualifiedName(mod); new_decl.name = try file.fullyQualifiedName(mod);
new_decl.name_fully_qualified = true; new_decl.name_fully_qualified = true;
@ -3808,7 +3823,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
_ = try decl.internValue(mod); _ = try decl.internValue(mod);
} }
new_namespace.ty = Type.fromInterned(struct_ty);
new_decl.val = Value.fromInterned(struct_ty); new_decl.val = Value.fromInterned(struct_ty);
new_decl.has_tv = true; new_decl.has_tv = true;
new_decl.owns_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_decl = mod.declPtr(std_file.root_decl.unwrap().?);
const std_namespace = std_decl.getInnerNamespace(mod).?; const std_namespace = std_decl.getInnerNamespace(mod).?;
const builtin_str = try ip.getOrPutString(gpa, "builtin"); 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; const builtin_namespace = builtin_decl.getInnerNamespaceIndex(mod).unwrap() orelse break :blk .none;
if (decl.src_namespace != builtin_namespace) 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. // 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( const gop = try namespace.decls.getOrPutContextAdapted(
gpa, gpa,
decl_name, decl_name,
DeclAdapter{ .mod = zcu }, DeclAdapter{ .zcu = zcu },
Namespace.DeclContext{ .module = zcu }, Namespace.DeclContext{ .zcu = zcu },
); );
const comp = zcu.comp; const comp = zcu.comp;
if (!gop.found_existing) { if (!gop.found_existing) {
@ -4600,12 +4614,11 @@ fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void
.@"test" => a: { .@"test" => a: {
if (!comp.config.is_test) break :a false; if (!comp.config.is_test) break :a false;
if (decl_mod != zcu.main_mod) break :a false; if (decl_mod != zcu.main_mod) break :a false;
if (is_named_test) { if (is_named_test and comp.test_filters.len > 0) {
if (comp.test_filter) |test_filter| { const decl_fqn = ip.stringToSlice(try namespace.fullyQualifiedName(zcu, decl_name));
if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) { for (comp.test_filters) |test_filter| {
break :a false; if (mem.indexOf(u8, decl_fqn, test_filter)) |_| break;
} } else break :a false;
}
} }
try zcu.test_functions.put(gpa, new_decl_index, {}); try zcu.test_functions.put(gpa, new_decl_index, {});
break :a true; break :a true;
@ -5622,7 +5635,7 @@ pub fn populateTestFunctions(
const test_functions_str = try ip.getOrPutString(gpa, "test_functions"); const test_functions_str = try ip.getOrPutString(gpa, "test_functions");
const decl_index = builtin_namespace.decls.getKeyAdapted( const decl_index = builtin_namespace.decls.getKeyAdapted(
test_functions_str, test_functions_str,
DeclAdapter{ .mod = mod }, DeclAdapter{ .zcu = mod },
).?; ).?;
{ {
// We have to call `ensureDeclAnalyzed` here in case `builtin.test_functions` // 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| { for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| {
const test_decl = mod.declPtr(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(try test_decl.fullyQualifiedName(mod)));
const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(test_decl.name));
defer gpa.free(test_decl_name); defer gpa.free(test_decl_name);
const test_name_decl_index = n: { const test_name_decl_index = n: {
const test_name_decl_ty = try mod.arrayType(.{ 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 { 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 { pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
return mod.declPtr(decl_index).getFileScope(mod); 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: /// Returns null in the following cases:
/// * `@TypeOf(.{})` /// * `@TypeOf(.{})`
/// * A struct which has no fields (`struct {}`). /// * A struct which has no fields (`struct {}`).

View file

@ -2801,10 +2801,9 @@ fn zirStructDecl(
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = block.namespace.toOptional(), .parent = block.namespace.toOptional(),
.ty = undefined, .decl_index = new_decl_index,
.file_scope = block.getFileScope(mod), .file_scope = block.getFileScope(mod),
}); });
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer mod.destroyNamespace(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index);
const struct_ty = ty: { const struct_ty = ty: {
@ -2821,7 +2820,6 @@ fn zirStructDecl(
new_decl.ty = Type.type; new_decl.ty = Type.type;
new_decl.val = Value.fromInterned(struct_ty); new_decl.val = Value.fromInterned(struct_ty);
new_namespace.ty = Type.fromInterned(struct_ty);
const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index); try mod.finalizeAnonDecl(new_decl_index);
@ -2990,10 +2988,9 @@ fn zirEnumDecl(
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = block.namespace.toOptional(), .parent = block.namespace.toOptional(),
.ty = undefined, .decl_index = new_decl_index,
.file_scope = block.getFileScope(mod), .file_scope = block.getFileScope(mod),
}); });
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer if (!done) mod.destroyNamespace(new_namespace_index); errdefer if (!done) mod.destroyNamespace(new_namespace_index);
const decls = sema.code.bodySlice(extra_index, decls_len); const decls = sema.code.bodySlice(extra_index, decls_len);
@ -3036,7 +3033,6 @@ fn zirEnumDecl(
new_decl.ty = Type.type; new_decl.ty = Type.type;
new_decl.val = Value.fromInterned(incomplete_enum.index); 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); const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index); try mod.finalizeAnonDecl(new_decl_index);
@ -3248,10 +3244,9 @@ fn zirUnionDecl(
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = block.namespace.toOptional(), .parent = block.namespace.toOptional(),
.ty = undefined, .decl_index = new_decl_index,
.file_scope = block.getFileScope(mod), .file_scope = block.getFileScope(mod),
}); });
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer mod.destroyNamespace(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index);
const union_ty = ty: { const union_ty = ty: {
@ -3292,7 +3287,6 @@ fn zirUnionDecl(
new_decl.ty = Type.type; new_decl.ty = Type.type;
new_decl.val = Value.fromInterned(union_ty); new_decl.val = Value.fromInterned(union_ty);
new_namespace.ty = Type.fromInterned(union_ty);
const decls = sema.code.bodySlice(extra_index, decls_len); const decls = sema.code.bodySlice(extra_index, decls_len);
try mod.scanNamespace(new_namespace_index, decls, new_decl); try mod.scanNamespace(new_namespace_index, decls, new_decl);
@ -3346,10 +3340,9 @@ fn zirOpaqueDecl(
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = block.namespace.toOptional(), .parent = block.namespace.toOptional(),
.ty = undefined, .decl_index = new_decl_index,
.file_scope = block.getFileScope(mod), .file_scope = block.getFileScope(mod),
}); });
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer mod.destroyNamespace(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index);
const opaque_ty = try mod.intern(.{ .opaque_type = .{ const opaque_ty = try mod.intern(.{ .opaque_type = .{
@ -3362,7 +3355,6 @@ fn zirOpaqueDecl(
new_decl.ty = Type.type; new_decl.ty = Type.type;
new_decl.val = Value.fromInterned(opaque_ty); new_decl.val = Value.fromInterned(opaque_ty);
new_namespace.ty = Type.fromInterned(opaque_ty);
const decls = sema.code.bodySlice(extra_index, decls_len); const decls = sema.code.bodySlice(extra_index, decls_len);
try mod.scanNamespace(new_namespace_index, decls, new_decl); try mod.scanNamespace(new_namespace_index, decls, new_decl);
@ -4834,7 +4826,7 @@ fn validateStructInit(
if (root_msg) |msg| { if (root_msg) |msg| {
if (mod.typeToStruct(struct_ty)) |struct_type| { if (mod.typeToStruct(struct_ty)) |struct_type| {
const decl = mod.declPtr(struct_type.decl.unwrap().?); const decl = mod.declPtr(struct_type.decl.unwrap().?);
const fqn = try decl.getFullyQualifiedName(mod); const fqn = try decl.fullyQualifiedName(mod);
try mod.errNoteNonLazy( try mod.errNoteNonLazy(
decl.srcLoc(mod), decl.srcLoc(mod),
msg, msg,
@ -4961,7 +4953,7 @@ fn validateStructInit(
if (root_msg) |msg| { if (root_msg) |msg| {
if (mod.typeToStruct(struct_ty)) |struct_type| { if (mod.typeToStruct(struct_ty)) |struct_type| {
const decl = mod.declPtr(struct_type.decl.unwrap().?); const decl = mod.declPtr(struct_type.decl.unwrap().?);
const fqn = try decl.getFullyQualifiedName(mod); const fqn = try decl.fullyQualifiedName(mod);
try mod.errNoteNonLazy( try mod.errNoteNonLazy(
decl.srcLoc(mod), decl.srcLoc(mod),
msg, msg,
@ -5355,7 +5347,7 @@ fn failWithBadStructFieldAccess(
const mod = sema.mod; const mod = sema.mod;
const gpa = sema.gpa; const gpa = sema.gpa;
const decl = mod.declPtr(struct_type.decl.unwrap().?); 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 = msg: {
const msg = try sema.errMsg( const msg = try sema.errMsg(
@ -5382,7 +5374,7 @@ fn failWithBadUnionFieldAccess(
const gpa = sema.gpa; const gpa = sema.gpa;
const decl = mod.declPtr(union_obj.decl); const decl = mod.declPtr(union_obj.decl);
const fqn = try decl.getFullyQualifiedName(mod); const fqn = try decl.fullyQualifiedName(mod);
const msg = msg: { const msg = msg: {
const msg = try sema.errMsg( const msg = try sema.errMsg(
@ -6504,8 +6496,7 @@ fn lookupInNamespace(
const mod = sema.mod; const mod = sema.mod;
const namespace = mod.namespacePtr(namespace_index); 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) { if (namespace_decl.analysis == .file_failure) {
return error.AnalysisFail; return error.AnalysisFail;
} }
@ -6526,7 +6517,7 @@ fn lookupInNamespace(
while (check_i < checked_namespaces.count()) : (check_i += 1) { while (check_i < checked_namespaces.count()) : (check_i += 1) {
const check_ns = checked_namespaces.keys()[check_i]; 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 // Skip decls which are not marked pub, which are in a different
// file than the `a.b`/`@hasDecl` syntax. // file than the `a.b`/`@hasDecl` syntax.
const decl = mod.declPtr(decl_index); const decl = mod.declPtr(decl_index);
@ -6584,7 +6575,7 @@ fn lookupInNamespace(
return sema.failWithOwnedErrorMsg(block, msg); 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; return decl_index;
} }
@ -17210,7 +17201,7 @@ fn zirThis(
extended: Zir.Inst.Extended.InstData, extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref { ) CompileError!Air.Inst.Ref {
const mod = sema.mod; 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)); const src = LazySrcLoc.nodeOffset(@bitCast(extended.operand));
return sema.analyzeDeclVal(block, src, this_decl_index); return sema.analyzeDeclVal(block, src, this_decl_index);
} }
@ -20075,7 +20066,7 @@ fn finishStructInit(
if (root_msg) |msg| { if (root_msg) |msg| {
if (mod.typeToStruct(struct_ty)) |struct_type| { if (mod.typeToStruct(struct_ty)) |struct_type| {
const decl = mod.declPtr(struct_type.decl.unwrap().?); const decl = mod.declPtr(struct_type.decl.unwrap().?);
const fqn = try decl.getFullyQualifiedName(mod); const fqn = try decl.fullyQualifiedName(mod);
try mod.errNoteNonLazy( try mod.errNoteNonLazy(
decl.srcLoc(mod), decl.srcLoc(mod),
msg, msg,
@ -21404,10 +21395,9 @@ fn zirReify(
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = block.namespace.toOptional(), .parent = block.namespace.toOptional(),
.ty = undefined, .decl_index = new_decl_index,
.file_scope = block.getFileScope(mod), .file_scope = block.getFileScope(mod),
}); });
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer mod.destroyNamespace(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index);
const opaque_ty = try mod.intern(.{ .opaque_type = .{ const opaque_ty = try mod.intern(.{ .opaque_type = .{
@ -21420,7 +21410,6 @@ fn zirReify(
new_decl.ty = Type.type; new_decl.ty = Type.type;
new_decl.val = Value.fromInterned(opaque_ty); new_decl.val = Value.fromInterned(opaque_ty);
new_namespace.ty = Type.fromInterned(opaque_ty);
const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index); try mod.finalizeAnonDecl(new_decl_index);
@ -21614,10 +21603,9 @@ fn zirReify(
const new_namespace_index = try mod.createNamespace(.{ const new_namespace_index = try mod.createNamespace(.{
.parent = block.namespace.toOptional(), .parent = block.namespace.toOptional(),
.ty = undefined, .decl_index = new_decl_index,
.file_scope = block.getFileScope(mod), .file_scope = block.getFileScope(mod),
}); });
const new_namespace = mod.namespacePtr(new_namespace_index);
errdefer mod.destroyNamespace(new_namespace_index); errdefer mod.destroyNamespace(new_namespace_index);
const union_ty = try ip.getUnionType(gpa, .{ const union_ty = try ip.getUnionType(gpa, .{
@ -21649,7 +21637,6 @@ fn zirReify(
new_decl.ty = Type.type; new_decl.ty = Type.type;
new_decl.val = Value.fromInterned(union_ty); new_decl.val = Value.fromInterned(union_ty);
new_namespace.ty = Type.fromInterned(union_ty);
const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index); try mod.finalizeAnonDecl(new_decl_index);
@ -37260,7 +37247,7 @@ fn generateUnionTagTypeNumbered(
const src_decl = mod.declPtr(block.src_decl); 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); const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
errdefer mod.destroyDecl(new_decl_index); 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)}); const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{ try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
.ty = Type.noreturn, .ty = Type.noreturn,
@ -37269,7 +37256,6 @@ fn generateUnionTagTypeNumbered(
errdefer mod.abortAnonDecl(new_decl_index); errdefer mod.abortAnonDecl(new_decl_index);
const new_decl = mod.declPtr(new_decl_index); const new_decl = mod.declPtr(new_decl_index);
new_decl.name_fully_qualified = true;
new_decl.owns_tv = true; new_decl.owns_tv = true;
new_decl.name_fully_qualified = true; new_decl.name_fully_qualified = true;
@ -37310,7 +37296,7 @@ fn generateUnionTagTypeSimple(
.val = Value.@"unreachable", .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 src_decl = mod.declPtr(block.src_decl);
const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
errdefer mod.destroyDecl(new_decl_index); errdefer mod.destroyDecl(new_decl_index);

View file

@ -7223,7 +7223,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 {
defer arena_allocator.deinit(); defer arena_allocator.deinit();
const arena = arena_allocator.allocator(); 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}); const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn});
// check if we already generated code for this. // check if we already generated code for this.

View file

@ -1163,7 +1163,7 @@ pub const Object = struct {
const fwd_ref = self.debug_unresolved_namespace_scopes.values()[i]; const fwd_ref = self.debug_unresolved_namespace_scopes.values()[i];
const namespace = self.module.namespacePtr(namespace_index); 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); self.builder.debugForwardReferenceSetType(fwd_ref, debug_type);
} }
@ -1797,7 +1797,7 @@ pub const Object = struct {
return updateExportedGlobal(self, mod, global_index, exports); return updateExportedGlobal(self, mod, global_index, exports);
} else { } else {
const fqn = try self.builder.string( 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); try global_index.rename(fqn, &self.builder);
global_index.setLinkage(.internal, &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 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 std_namespace = mod.namespacePtr(mod.declPtr(std_file.root_decl.unwrap().?).src_namespace);
const builtin_decl = std_namespace.decls const builtin_decl = std_namespace.decls.getKeyAdapted(builtin_str, Module.DeclAdapter{ .zcu = mod }).?;
.getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?;
const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace"); const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace");
// buffer is only used for int_type, `builtin` is a struct. // buffer is only used for int_type, `builtin` is a struct.
const builtin_ty = mod.declPtr(builtin_decl).val.toType(); const builtin_ty = mod.declPtr(builtin_decl).val.toType();
const builtin_namespace = builtin_ty.getNamespace(mod).?; const builtin_namespace = builtin_ty.getNamespace(mod).?;
const stack_trace_decl_index = builtin_namespace.decls const stack_trace_decl_index = builtin_namespace.decls.getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .zcu = mod }).?;
.getKeyAdapted(stack_trace_str, Module.DeclAdapter{ .mod = mod }).?;
const stack_trace_decl = mod.declPtr(stack_trace_decl_index); const stack_trace_decl = mod.declPtr(stack_trace_decl_index);
// Sema should have ensured that StackTrace was analyzed. // 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) try o.builder.string(ip.stringToSlice(if (is_extern)
decl.name decl.name
else else
try decl.getFullyQualifiedName(zcu))), try decl.fullyQualifiedName(zcu))),
toLlvmAddressSpace(decl.@"addrspace", target), toLlvmAddressSpace(decl.@"addrspace", target),
); );
gop.value_ptr.* = function_index.ptrConst(&o.builder).global; gop.value_ptr.* = function_index.ptrConst(&o.builder).global;
@ -3100,7 +3098,7 @@ pub const Object = struct {
const variable_index = try o.builder.addVariable( const variable_index = try o.builder.addVariable(
try o.builder.string(mod.intern_pool.stringToSlice( 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), try o.lowerType(decl.ty),
toLlvmGlobalAddressSpace(decl.@"addrspace", mod.getTarget()), toLlvmGlobalAddressSpace(decl.@"addrspace", mod.getTarget()),
@ -3325,7 +3323,7 @@ pub const Object = struct {
} }
const name = try o.builder.string(ip.stringToSlice( 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){}; var llvm_field_types = std.ArrayListUnmanaged(Builder.Type){};
@ -3481,7 +3479,7 @@ pub const Object = struct {
} }
const name = try o.builder.string(ip.stringToSlice( 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]); 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 usize_ty = try o.lowerType(Type.usize);
const ret_ty = try o.lowerType(Type.slice_const_u8_sentinel_0); 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 target = zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction( const function_index = try o.builder.addFunction(
try o.builder.fnType(ret_ty, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), 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, .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 is_internal_linkage = !zcu.decl_exports.contains(decl_index);
const fn_ty = try zcu.funcType(.{ const fn_ty = try zcu.funcType(.{
@ -9643,7 +9641,7 @@ pub const FuncGen = struct {
if (gop.found_existing) return gop.value_ptr.*; if (gop.found_existing) return gop.value_ptr.*;
errdefer assert(o.named_enum_map.remove(enum_type.decl)); 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 target = zcu.root_mod.resolved_target.result;
const function_index = try o.builder.addFunction( const function_index = try o.builder.addFunction(
try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal), try o.builder.fnType(.i1, &.{try o.lowerType(Type.fromInterned(enum_type.tag_ty))}, .normal),

View file

@ -2019,7 +2019,7 @@ const DeclGen = struct {
// Append the actual code into the functions section. // Append the actual code into the functions section.
try self.spv.addFunction(spv_decl_index, self.func); 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); try self.spv.debugName(decl_id, fqn);
// Temporarily generate a test kernel declaration if this is a test function. // Temporarily generate a test kernel declaration if this is a test function.
@ -2055,7 +2055,7 @@ const DeclGen = struct {
.id_result = decl_id, .id_result = decl_id,
.storage_class = actual_storage_class, .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); try self.spv.debugName(decl_id, fqn);
if (opt_init_val) |init_val| { if (opt_init_val) |init_val| {

View file

@ -1176,7 +1176,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: InternPool.Dec
gop.value_ptr.* = .{}; gop.value_ptr.* = .{};
} }
const unnamed_consts = 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 index = unnamed_consts.items.len;
const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
defer gpa.free(sym_name); 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 mod = self.base.comp.module.?;
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0)); const required_alignment: u32 = @intCast(decl.getAlignment(mod).toByteUnits(0));

View file

@ -1082,7 +1082,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: InternPool.DeclInde
defer tracy.end(); defer tracy.end();
const decl = mod.declPtr(decl_index); 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 }); log.debug("initDeclState {}{*}", .{ decl_linkage_name.fmt(&mod.intern_pool), decl });

View file

@ -903,7 +903,7 @@ fn updateDeclCode(
const gpa = elf_file.base.comp.gpa; const gpa = elf_file.base.comp.gpa;
const mod = elf_file.base.comp.module.?; const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
@ -1001,7 +1001,7 @@ fn updateTlv(
const gpa = elf_file.base.comp.gpa; const gpa = elf_file.base.comp.gpa;
const mod = elf_file.base.comp.module.?; const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateTlv {s} ({*})", .{ decl_name, decl });
@ -1300,7 +1300,7 @@ pub fn lowerUnnamedConst(
} }
const unnamed_consts = gop.value_ptr; const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index); 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 index = unnamed_consts.items.len;
const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
defer gpa.free(name); defer gpa.free(name);
@ -1482,7 +1482,7 @@ pub fn updateDeclLineNumber(
defer tracy.end(); defer tracy.end();
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });

View file

@ -792,7 +792,7 @@ fn updateDeclCode(
const gpa = macho_file.base.comp.gpa; const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?; const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
@ -876,7 +876,7 @@ fn updateTlv(
) !void { ) !void {
const mod = macho_file.base.comp.module.?; const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateTlv {s} ({*})", .{ decl_name, decl });
@ -1079,7 +1079,7 @@ pub fn lowerUnnamedConst(
} }
const unnamed_consts = gop.value_ptr; const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index); 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 index = unnamed_consts.items.len;
const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
defer gpa.free(name); defer gpa.free(name);

View file

@ -478,7 +478,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: InternPool.De
} }
const unnamed_consts = 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 index = unnamed_consts.items.len;
// name is freed when the unnamed const is freed // name is freed when the unnamed const is freed

View file

@ -662,7 +662,7 @@ pub fn getOrCreateAtomForDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) !At
const symbol = atom.symbolLoc().getSymbol(wasm); const symbol = atom.symbolLoc().getSymbol(wasm);
const mod = wasm.base.comp.module.?; const mod = wasm.base.comp.module.?;
const decl = mod.declPtr(decl_index); 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); symbol.name = try wasm.string_table.put(gpa, full_name);
} }
return gop.value_ptr.*; return gop.value_ptr.*;
@ -1598,7 +1598,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: InternPool.De
defer tracy.end(); defer tracy.end();
const decl = mod.declPtr(decl_index); 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 }); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
try dw.updateDeclLineNumber(mod, decl_index); 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_index = wasm.decls.get(decl_index).?;
const atom = wasm.getAtomPtr(atom_index); const atom = wasm.getAtomPtr(atom_index);
const symbol = &wasm.symbols.items[atom.sym_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.name = try wasm.string_table.put(gpa, full_name);
symbol.tag = symbol_tag; symbol.tag = symbol_tag;
try atom.code.appendSlice(gpa, code); 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_index = try wasm.getOrCreateAtomForDecl(decl_index);
const parent_atom = wasm.getAtom(parent_atom_index); const parent_atom = wasm.getAtom(parent_atom_index);
const local_index = parent_atom.locals.items.len; 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}", .{ const name = try std.fmt.allocPrintZ(gpa, "__unnamed_{s}_{d}", .{
fqn, local_index, fqn, local_index,
}); });

View file

@ -596,7 +596,7 @@ const usage_build_generic =
\\ --export=[value] (WebAssembly) Force a symbol to be exported \\ --export=[value] (WebAssembly) Force a symbol to be exported
\\ \\
\\Test Options: \\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-name-prefix [text] Add prefix to all tests
\\ --test-cmd [arg] Specify test execution command one arg at a time \\ --test-cmd [arg] Specify test execution command one arg at a time
\\ --test-cmd-bin Appends test binary path to test cmd args \\ --test-cmd-bin Appends test binary path to test cmd args
@ -869,7 +869,7 @@ fn buildOutputType(
var link_emit_relocs = false; var link_emit_relocs = false;
var build_id: ?std.zig.BuildId = null; var build_id: ?std.zig.BuildId = null;
var runtime_args_start: ?usize = 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_name_prefix: ?[]const u8 = null;
var test_runner_path: ?[]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); 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; var rc_source_files_owner_index: usize = 0;
// null means replace with the test executable binary // 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 // These get set by CLI flags and then snapshotted when a `--mod` flag is
// encountered. // encountered.
@ -1278,13 +1278,13 @@ fn buildOutputType(
} else if (mem.eql(u8, arg, "--libc")) { } else if (mem.eql(u8, arg, "--libc")) {
create_module.libc_paths_file = args_iter.nextOrFatal(); create_module.libc_paths_file = args_iter.nextOrFatal();
} else if (mem.eql(u8, arg, "--test-filter")) { } 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")) { } else if (mem.eql(u8, arg, "--test-name-prefix")) {
test_name_prefix = args_iter.nextOrFatal(); test_name_prefix = args_iter.nextOrFatal();
} else if (mem.eql(u8, arg, "--test-runner")) { } else if (mem.eql(u8, arg, "--test-runner")) {
test_runner_path = args_iter.nextOrFatal(); test_runner_path = args_iter.nextOrFatal();
} else if (mem.eql(u8, arg, "--test-cmd")) { } 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")) { } else if (mem.eql(u8, arg, "--cache-dir")) {
override_local_cache_dir = args_iter.nextOrFatal(); override_local_cache_dir = args_iter.nextOrFatal();
} else if (mem.eql(u8, arg, "--global-cache-dir")) { } 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")) { } else if (mem.eql(u8, arg, "-fno-each-lib-rpath")) {
create_module.each_lib_rpath = false; create_module.each_lib_rpath = false;
} else if (mem.eql(u8, arg, "--test-cmd-bin")) { } 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")) { } else if (mem.eql(u8, arg, "--test-no-exec")) {
test_no_exec = true; test_no_exec = true;
} else if (mem.eql(u8, arg, "-ftime-report")) { } else if (mem.eql(u8, arg, "-ftime-report")) {
@ -3246,7 +3246,7 @@ fn buildOutputType(
.time_report = time_report, .time_report = time_report,
.stack_report = stack_report, .stack_report = stack_report,
.build_id = build_id, .build_id = build_id,
.test_filter = test_filter, .test_filters = test_filters.items,
.test_name_prefix = test_name_prefix, .test_name_prefix = test_name_prefix,
.test_runner_path = test_runner_path, .test_runner_path = test_runner_path,
.disable_lld_caching = disable_lld_caching, .disable_lld_caching = disable_lld_caching,
@ -3369,16 +3369,15 @@ fn buildOutputType(
const c_code_path = try fs.path.join(arena, &[_][]const u8{ const c_code_path = try fs.path.join(arena, &[_][]const u8{
c_code_directory.path orelse ".", c_code_loc.basename, c_code_directory.path orelse ".", c_code_loc.basename,
}); });
try test_exec_args.append(self_exe_path); try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" });
try test_exec_args.append("run");
if (zig_lib_directory.path) |p| { 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) { 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) { } else if (target.os.tag == .windows) {
try test_exec_args.appendSlice(&.{ try test_exec_args.appendSlice(arena, &.{
"--subsystem", "console", "--subsystem", "console",
"-lkernel32", "-lntdll", "-lkernel32", "-lntdll",
}); });
@ -3386,17 +3385,15 @@ fn buildOutputType(
const first_cli_mod = create_module.modules.values()[0]; const first_cli_mod = create_module.modules.values()[0];
if (first_cli_mod.target_arch_os_abi) |triple| { if (first_cli_mod.target_arch_os_abi) |triple| {
try test_exec_args.append("-target"); try test_exec_args.appendSlice(arena, &.{ "-target", triple });
try test_exec_args.append(triple);
} }
if (first_cli_mod.target_mcpu) |mcpu| { 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| { if (create_module.dynamic_linker) |dl| {
try test_exec_args.append("--dynamic-linker"); try test_exec_args.appendSlice(arena, &.{ "--dynamic-linker", dl });
try test_exec_args.append(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) { const run_or_test = switch (arg_mode) {

View file

@ -537,7 +537,7 @@ pub fn lowerToBuildSteps(
self: *Cases, self: *Cases,
b: *std.Build, b: *std.Build,
parent_step: *std.Build.Step, parent_step: *std.Build.Step,
opt_test_filter: ?[]const u8, test_filters: []const []const u8,
cases_dir_path: []const u8, cases_dir_path: []const u8,
incremental_exe: *std.Build.Step.Compile, incremental_exe: *std.Build.Step.Compile,
) void { ) void {
@ -552,9 +552,9 @@ pub fn lowerToBuildSteps(
// compilation is in a happier state. // compilation is in a happier state.
continue; continue;
} }
if (opt_test_filter) |test_filter| { for (test_filters) |test_filter| {
if (std.mem.indexOf(u8, incr_case.base_path, test_filter) == null) continue; 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, &.{ const case_base_path_with_dir = std.fs.path.join(b.allocator, &.{
cases_dir_path, incr_case.base_path, cases_dir_path, incr_case.base_path,
}) catch @panic("OOM"); }) catch @panic("OOM");
@ -573,9 +573,9 @@ pub fn lowerToBuildSteps(
assert(case.updates.items.len == 1); assert(case.updates.items.len == 1);
const update = case.updates.items[0]; const update = case.updates.items[0];
if (opt_test_filter) |test_filter| { for (test_filters) |test_filter| {
if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; if (std.mem.indexOf(u8, case.name, test_filter)) |_| break;
} } else if (test_filters.len > 0) continue;
const writefiles = b.addWriteFiles(); const writefiles = b.addWriteFiles();
var file_sources = std.StringHashMap(std.Build.LazyPath).init(b.allocator); 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) { for (self.translate.items) |case| switch (case.kind) {
.run => |output| { .run => |output| {
const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name}); const annotated_case_name = b.fmt("run-translated-c {s}", .{case.name});
if (opt_test_filter) |filter| { for (test_filters) |test_filter| {
if (std.mem.indexOf(u8, annotated_case_name, filter) == null) continue; if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
} } else if (test_filters.len > 0) continue;
if (!std.process.can_spawn) { if (!std.process.can_spawn) {
std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)}); std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)});
continue; // Pass test. continue; // Pass test.
@ -721,9 +721,9 @@ pub fn lowerToBuildSteps(
}, },
.translate => |output| { .translate => |output| {
const annotated_case_name = b.fmt("zig translate-c {s}", .{case.name}); const annotated_case_name = b.fmt("zig translate-c {s}", .{case.name});
if (opt_test_filter) |filter| { for (test_filters) |test_filter| {
if (std.mem.indexOf(u8, annotated_case_name, filter) == null) continue; if (std.mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
} } else if (test_filters.len > 0) continue;
const write_src = b.addWriteFiles(); const write_src = b.addWriteFiles();
const file_source = write_src.add("tmp.c", case.input); 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); assert(case.backend != .stage1);
if (build_options.test_filter) |test_filter| { for (build_options.test_filters) |test_filter| {
if (std.mem.indexOf(u8, case.name, test_filter) == null) continue; 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); var prg_node = root_node.start(case.name, case.updates.items.len);
prg_node.activate(); prg_node.activate();

View file

@ -4,7 +4,7 @@
b: *std.Build, b: *std.Build,
step: *std.Build.Step, step: *std.Build.Step,
test_index: usize, test_index: usize,
test_filter: ?[]const u8, test_filters: []const []const u8,
optimize_modes: []const OptimizeMode, optimize_modes: []const OptimizeMode,
const Special = enum { 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}", .{ const annotated_case_name = fmt.allocPrint(self.b.allocator, "run assemble-and-link {s}", .{
case.name, case.name,
}) catch @panic("OOM"); }) catch @panic("OOM");
if (self.test_filter) |filter| { for (self.test_filters) |test_filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return; if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
} } else if (self.test_filters.len > 0) return;
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "test", .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})", .{ const annotated_case_name = fmt.allocPrint(self.b.allocator, "run compare-output {s} ({s})", .{
case.name, @tagName(optimize), case.name, @tagName(optimize),
}) catch @panic("OOM"); }) catch @panic("OOM");
if (self.test_filter) |filter| { for (self.test_filters) |test_filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
} } else if (self.test_filters.len > 0) return;
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "test", .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 // TODO iterate over self.optimize_modes and test this in both
// debug and release safe mode // debug and release safe mode
const annotated_case_name = fmt.allocPrint(self.b.allocator, "run safety {s}", .{case.name}) catch @panic("OOM"); const annotated_case_name = fmt.allocPrint(self.b.allocator, "run safety {s}", .{case.name}) catch @panic("OOM");
if (self.test_filter) |filter| { for (self.test_filters) |test_filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return; if (mem.indexOf(u8, annotated_case_name, test_filter)) |_| break;
} } else if (self.test_filters.len > 0) return;
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{
.name = "test", .name = "test",

103
test/src/RunTranslatedC.zig Normal file
View file

@ -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;

View file

@ -1,7 +1,7 @@
b: *std.Build, b: *std.Build,
step: *Step, step: *Step,
test_index: usize, test_index: usize,
test_filter: ?[]const u8, test_filters: []const []const u8,
optimize_modes: []const OptimizeMode, optimize_modes: []const OptimizeMode,
check_exe: *std.Build.Step.Compile, check_exe: *std.Build.Step.Compile,
@ -47,9 +47,9 @@ fn addExpect(
const annotated_case_name = fmt.allocPrint(b.allocator, "check {s} ({s})", .{ const annotated_case_name = fmt.allocPrint(b.allocator, "check {s} ({s})", .{
name, @tagName(optimize_mode), name, @tagName(optimize_mode),
}) catch @panic("OOM"); }) catch @panic("OOM");
if (self.test_filter) |filter| { for (self.test_filters) |test_filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null) return; 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 write_src = b.addWriteFile("source.zig", source);
const exe = b.addExecutable(.{ const exe = b.addExecutable(.{

118
test/src/TranslateC.zig Normal file
View file

@ -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;

View file

@ -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);
}
};

View file

@ -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);
}
};

View file

@ -15,8 +15,8 @@ const run_translated_c = @import("run_translated_c.zig");
const link = @import("link.zig"); const link = @import("link.zig");
// Implementations // Implementations
pub const TranslateCContext = @import("src/translate_c.zig").TranslateCContext; pub const TranslateCContext = @import("src/TranslateC.zig");
pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext; pub const RunTranslatedCContext = @import("src/RunTranslatedC.zig");
pub const CompareOutputContext = @import("src/CompareOutput.zig"); pub const CompareOutputContext = @import("src/CompareOutput.zig");
pub const StackTracesContext = @import("src/StackTrace.zig"); pub const StackTracesContext = @import("src/StackTrace.zig");
@ -619,7 +619,7 @@ const c_abi_targets = [_]CAbiTarget{
pub fn addCompareOutputTests( pub fn addCompareOutputTests(
b: *std.Build, b: *std.Build,
test_filter: ?[]const u8, test_filters: []const []const u8,
optimize_modes: []const OptimizeMode, optimize_modes: []const OptimizeMode,
) *Step { ) *Step {
const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM"); const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM");
@ -627,7 +627,7 @@ pub fn addCompareOutputTests(
.b = b, .b = b,
.step = b.step("test-compare-output", "Run the compare output tests"), .step = b.step("test-compare-output", "Run the compare output tests"),
.test_index = 0, .test_index = 0,
.test_filter = test_filter, .test_filters = test_filters,
.optimize_modes = optimize_modes, .optimize_modes = optimize_modes,
}; };
@ -638,7 +638,7 @@ pub fn addCompareOutputTests(
pub fn addStackTraceTests( pub fn addStackTraceTests(
b: *std.Build, b: *std.Build,
test_filter: ?[]const u8, test_filters: []const []const u8,
optimize_modes: []const OptimizeMode, optimize_modes: []const OptimizeMode,
) *Step { ) *Step {
const check_exe = b.addExecutable(.{ const check_exe = b.addExecutable(.{
@ -653,7 +653,7 @@ pub fn addStackTraceTests(
.b = b, .b = b,
.step = b.step("test-stack-traces", "Run the stack trace tests"), .step = b.step("test-stack-traces", "Run the stack trace tests"),
.test_index = 0, .test_index = 0,
.test_filter = test_filter, .test_filters = test_filters,
.optimize_modes = optimize_modes, .optimize_modes = optimize_modes,
.check_exe = check_exe, .check_exe = check_exe,
}; };
@ -983,13 +983,13 @@ pub fn addCliTests(b: *std.Build) *Step {
return 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"); const cases = b.allocator.create(CompareOutputContext) catch @panic("OOM");
cases.* = CompareOutputContext{ cases.* = CompareOutputContext{
.b = b, .b = b,
.step = b.step("test-asm-link", "Run the assemble and link tests"), .step = b.step("test-asm-link", "Run the assemble and link tests"),
.test_index = 0, .test_index = 0,
.test_filter = test_filter, .test_filters = test_filters,
.optimize_modes = optimize_modes, .optimize_modes = optimize_modes,
}; };
@ -998,13 +998,13 @@ pub fn addAssembleAndLinkTests(b: *std.Build, test_filter: ?[]const u8, optimize
return cases.step; 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"); const cases = b.allocator.create(TranslateCContext) catch @panic("OOM");
cases.* = TranslateCContext{ cases.* = TranslateCContext{
.b = b, .b = b,
.step = b.step("test-translate-c", "Run the C translation tests"), .step = b.step("test-translate-c", "Run the C translation tests"),
.test_index = 0, .test_index = 0,
.test_filter = test_filter, .test_filters = test_filters,
}; };
translate_c.addCases(cases); translate_c.addCases(cases);
@ -1014,7 +1014,7 @@ pub fn addTranslateCTests(b: *std.Build, test_filter: ?[]const u8) *Step {
pub fn addRunTranslatedCTests( pub fn addRunTranslatedCTests(
b: *std.Build, b: *std.Build,
test_filter: ?[]const u8, test_filters: []const []const u8,
target: std.Build.ResolvedTarget, target: std.Build.ResolvedTarget,
) *Step { ) *Step {
const cases = b.allocator.create(RunTranslatedCContext) catch @panic("OOM"); const cases = b.allocator.create(RunTranslatedCContext) catch @panic("OOM");
@ -1022,7 +1022,7 @@ pub fn addRunTranslatedCTests(
.b = b, .b = b,
.step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"), .step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"),
.test_index = 0, .test_index = 0,
.test_filter = test_filter, .test_filters = test_filters,
.target = target, .target = target,
}; };
@ -1032,7 +1032,7 @@ pub fn addRunTranslatedCTests(
} }
const ModuleTestOptions = struct { const ModuleTestOptions = struct {
test_filter: ?[]const u8, test_filters: []const []const u8,
root_src: []const u8, root_src: []const u8,
name: []const u8, name: []const u8,
desc: []const u8, desc: []const u8,
@ -1115,7 +1115,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
.optimize = test_target.optimize_mode, .optimize = test_target.optimize_mode,
.target = resolved_target, .target = resolved_target,
.max_rss = max_rss, .max_rss = max_rss,
.filter = options.test_filter, .filters = options.test_filters,
.link_libc = test_target.link_libc, .link_libc = test_target.link_libc,
.single_threaded = test_target.single_threaded, .single_threaded = test_target.single_threaded,
.use_llvm = test_target.use_llvm, .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( pub fn addCases(
b: *std.Build, b: *std.Build,
parent_step: *Step, parent_step: *Step,
opt_test_filter: ?[]const u8, test_filters: []const []const u8,
check_case_exe: *std.Build.Step.Compile, check_case_exe: *std.Build.Step.Compile,
build_options: @import("cases.zig").BuildOptions, build_options: @import("cases.zig").BuildOptions,
) !void { ) !void {
@ -1310,7 +1310,7 @@ pub fn addCases(
cases.lowerToBuildSteps( cases.lowerToBuildSteps(
b, b,
parent_step, parent_step,
opt_test_filter, test_filters,
cases_dir_path, cases_dir_path,
check_case_exe, check_case_exe,
); );