wcc/ww: don't interface-check the sep-build root unit (BUG-1, #69)

The --sep producer compiled the ROOT build-target with the .wwi-producer
-I flag, so check_exported_type ran on the root and rejected a real-tool
root's legitimate `export fn f(a: *t)` over an unexported local type t
(the root is terminal — its interface is never imported, and its .wwi is
never consumed). The combined build never passes -I, so it built fine.
For pi==root, invoke w6c with -c -o only, no -I. Both stages (the wwstage
twin builds the shorter root argv). Gates that asserted __root.wwi exists
encoded the buggy behavior; updated to assert __root.s (the consumed
product) while deps' .wwi byte-id is retained.

M3-tail commit-6 prerequisite. Gate 989_seproot_export_run reproduces the
export-fn-over-unexported-type root + proves it sep-builds, with a
non-vacuity leg that the forced -I path still rejects.
This commit is contained in:
2026-06-16 17:16:37 +09:00
parent 747475174a
commit 2ff54c8bd4
7 changed files with 362 additions and 26 deletions

View File

@@ -4510,16 +4510,28 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
return 1;
};
{
let argv: []*u8 = alloc([], 8u64)!;
argv.len = 8;
// BUG-1 (#69): -I <wwi> is purely the root's UNUSED
// `.wwi` output path, but it triggers wwiemit ->
// checkexportedtype on the root. A terminal binary's
// root legitimately has `export fn` over an unexported
// LOCAL type (the root is never imported), which the
// export-check rejects. Build a shorter root argv
// without the -I/wwi pair; root's `.wwi` is unconsumed.
let alen: u64 = 8u64;
if (pi == root) { alen = 6u64; };
let argv: []*u8 = alloc([], alen)!;
argv.len = (alen: i32);
argv[0] = "w6c\0".ptr;
argv[1] = "-c\0".ptr;
argv[2] = "-I\0".ptr;
argv[3] = wwi;
argv[4] = "-o\0".ptr;
argv[5] = asmf;
argv[6] = unitf;
argv[7] = nil;
let k: u64 = 2u64;
if (pi != root) {
argv[k] = "-I\0".ptr; k += 1u64;
argv[k] = wwi; k += 1u64;
};
argv[k] = "-o\0".ptr; k += 1u64;
argv[k] = asmf; k += 1u64;
argv[k] = unitf; k += 1u64;
argv[k] = nil;
if (procrun(c6, argv.ptr) != 0) {
cerr("ww --sep: w6c failed\n");
return 1;

View File

@@ -1636,16 +1636,28 @@ fn buildonesep(selfdir: *u8, src: *u8, entryisdir: i32, out: *u8,
return 1;
};
{
let argv: []*u8 = alloc([], 8u64)!;
argv.len = 8;
// BUG-1 (#69): -I <wwi> is purely the root's UNUSED
// `.wwi` output path, but it triggers wwiemit ->
// checkexportedtype on the root. A terminal binary's
// root legitimately has `export fn` over an unexported
// LOCAL type (the root is never imported), which the
// export-check rejects. Build a shorter root argv
// without the -I/wwi pair; root's `.wwi` is unconsumed.
let alen: u64 = 8u64;
if (pi == root) { alen = 6u64; };
let argv: []*u8 = alloc([], alen)!;
argv.len = (alen: i32);
argv[0] = "w6c\0".ptr;
argv[1] = "-c\0".ptr;
argv[2] = "-I\0".ptr;
argv[3] = wwi;
argv[4] = "-o\0".ptr;
argv[5] = asmf;
argv[6] = unitf;
argv[7] = nil;
let k: u64 = 2u64;
if (pi != root) {
argv[k] = "-I\0".ptr; k += 1u64;
argv[k] = wwi; k += 1u64;
};
argv[k] = "-o\0".ptr; k += 1u64;
argv[k] = asmf; k += 1u64;
argv[k] = unitf; k += 1u64;
argv[k] = nil;
if (procrun(c6, argv.ptr) != 0) {
cerr("ww --sep: w6c failed\n");
return 1;