Say the platform once: real #[cfg] in place of stubs, placeholders, let _ = x and allow(...)

Merged
DY
1mo ago
+1237-2349

What does this PR do?

Cleans up how the Rust code says "this only exists on one platform". No behaviour change is intended and no exported symbol changes.

Since #43650 made bun_runtime a private crate, rustc's dead_code lint sees everything in it, and a lot of what it saw was code standing in for another platform: stub functions, placeholder types, let _ = x; and allow(...). This says the platform once, with a real #[cfg], and deletes what only existed to keep the other platforms compiling.

in src/**/*.rsmainthis PR
item-level allow(dead_code) escapes770
#[cfg(...)] attributes5,2175,063
single-name let _ = x;385302

The changes, by theme (later review commits are folded into the theme they belong to)

  1. spawn: a memfd stdio exists where memfd does. Stdio::Memfd and the Memfd variants of the subprocess and shell Readable / Writable are Linux/Android-only, with can_use_memfd, use_memfd and take_memfd. Gone: #[cfg(windows)] Self::Memfd(_) => panic!("This should never happen"), panic!("memfd is only supported on Linux"), the return false stub bodies. Bun.spawn's memfd cleanup guard goes too: stdio is an owned [Stdio; 3] that is never moved, and Stdio's Drop closes a memfd, so the guard repeated that.
  2. napi, collections. NapiStatus was listed in full under allow(dead_code) because two extern declarations typed a C++-produced status as the Rust enum. They take napi_status (the integer), and the enum keeps the values Rust produces, with the rest listed as comments. multi_array_columns! accessors name their field in an offset_of!, a use the lint can see.
  3. dead_code escapes: say where the item exists, or delete it. Stale attributes in the macOS-only CoreGraphics backend, a real #[cfg] on nine items, FileCloner gated as a module, the shell PipeReader.stdio_result as a POSIX field. Deleted: a single-use alias, a hand-declared setenv, a debug_assert! on the constant true.
  4. Attributes that repeat an enclosing gate, and code under a contradictory one. Inside something that already exists only under a predicate, repeating the predicate does nothing, and an item under the opposite predicate is never compiled. WindowsNamedPipe.rs alone had 36 repeats and 7 not(windows) stand-ins inside a Windows-only module. A #[cfg(p)] { … } block is unwrapped where it was the last thing in its enclosing block, so scopes and drop order are the same; the two exceptions, in WindowsNamedPipe.rs, hold only raw pointers and a temporary.
  5. Stubs for platforms whose callers never reach them. bun_sys::{writev, readv, preadv, statfs} are unix functions (Windows reaches these through sys_uv). Deleted: the non-macOS clonefileat, the non-Linux can_use_memfd, the Windows us_socket_t::write_fd (unreachable!). snapshot_children and kill_subreaper_adoptees are Linux functions like their callers, without stub arms.
  6. let _ = x; statements that silence nothing. Every single-name one (363, outside proc-macro crates) was removed and the compiler asked which it needs; 75 stay removed. Five more looked unneeded only because they sit in arms no checked target builds (wasm32, neither unix nor Windows); those are back. A single name under a _ pattern is not moved, so removing one cannot change when anything is dropped.
  7. Placeholders for another platform's types. windows: () / pseudoconsole: () in the POSIX spawn options, PidFdType = () off Linux, Windows struct WaitPidResult {} and enum WaiterThread {}, the event loop's signal_handler: (), ExceptionValidationScope._scope: (), MemoryAccessor._mem: (). The POSIX signal ring is a unix type.
  8. A rename flag nobody sets and a Windows dup2 nobody calls. Without nofollow, Renameat2Flags wrapped one field, so renameat2 takes the RenameMode.
  9. allow attributes that allow nothing. Every single-line allow outside proc-macro crates and macro bodies was rewritten as expect, and rustc and clippy asked on five targets which expectations are unfulfilled. 334 lints never fire where they are written (214 attributes go entirely): naming lints on names that already follow the convention, and clippy::not_unsafe_ptr_arg_deref, which only checks exported functions: these are pub(crate) since #43650. The comments that justified a removed allowance go with it. Two of the 334 were needed after all, by test code, which the experiment did not compile: clippy::disallowed_types in bun_ptr and bun_sys is back as #![cfg_attr(test, allow(...))]. Nothing is left as expect.
  10. dead_code escapes inside macros do nothing. rustc does not report dead_code for an item another crate's macro generated, only for one from a macro in the same crate, and every use of opaque_ffi!, multi_array_columns!, comptime_string_map!, the css derives and jsc_macros' Gc enum is from another crate. With all 18 removed nothing fires on any target or profile, test targets included. A nineteenth was on a test's struct, which the test now also reads directly.
  11. The last platform-only items behind escapes. posix_spawn.rs is a unix module and says so where it is mounted (31 repeats of #[cfg(unix)] go with Attr's four escapes; bun_spawn's re-export of it had no users). With Windows out of the file, a forwarding helper and two aliases go, and spawn_bun borrows its request. patch::ApplyState is #[cfg(windows)], down to apply_patch's parameter. WindowsNamedPipe writes its two Windows writer-parent impls by hand, as Terminal does, in place of a macro that also stamps a POSIX impl; the field that existed only to be named there goes. InternalSocket::Pipe no longer exists on POSIX: its only constructor was one of the stand-ins removed in 4.
  12. Style::JavascriptDefined does not keep a function nothing calls. A style function is still accepted and the route scan still panics with TODO: customizable Style. The Strong the variant held is gone, so Style is a plain Copy enum and the hand-written Clone, with its own copy of the panic, goes. The dev server and production build reached that copy first; they now reach the scan's.
  13. The escape inventory is a ban. dead-code-escape-limits.json is deleted and the test asserts there are no item-level escapes.

Left alone on purpose

  • Whole-module #![allow(dead_code)], which the test does not count. generated_classes.rs needs its one: the generator emits the full accessor set for every class and each class uses a subset. The five h2/*.rs files hide the unused outbound half of a rewrite in progress.
  • allow attributes inside macro_rules! bodies, other than the dead_code in 10: an expectation there is judged per expansion.
  • File-level #![cfg(windows)] that repeat the mod declaration's gate: they tell a reader of the file what it is.
  • Arms for a target that is neither unix nor Windows.
  • let _ = x; statements the compiler does need somewhere. Those silence a value that really is unused on some platform, and the fix is a #[cfg] on the parameter or binding.

How did you verify your code works?

All with warnings as errors, on the branch merged with main:

  • cargo check --workspace on x86_64 Linux, x86_64 Windows, arm64 macOS, x86_64 FreeBSD and x86_64 Android, in the dev and release profiles. Release matters here: code under debug_assertions is not compiled there, so something used only by it is unused.

  • cargo check --workspace --all-targets on the same five targets, and cargo clippy --workspace --no-deps on Linux. cargo clippy --workspace --all-targets reports the same set of findings as on main.

  • For commits 6 and 9, before the merge: the same check with the build's own cfgs on (bun_debug, bun_asan, socket_fault_injection; bun_codegen_embed in release).

  • test/internal/source-lints/dead-code-escapes.test.ts passes, and fails naming the file when an escape is added.

  • A Linux x64 debug build: the binary checks pass with 0 duplicate strong symbols. Bun.spawn with a Blob stdin (the memfd path), Bun.spawnSync with a buffer stdin, a shell pipeline and repeated SIGUSR1 handling work. A function as style panics with the same message as before and an invalid style throws the same error. spawn-stdin-readable-stream.test.ts (37), spawn-maxbuf.test.ts (16), process-signal-listener-count.test.ts (3), framework-router.test.ts (35), patch.test.ts (27), socket.test.ts (104) and no-orphans.test.ts (18) pass.

  • CI's binaries for this branch against main's build of its base commit, function by function (sizes from the symbol table or linker map, then instructions with padding and addresses ignored):

    functionsdiffer
    linux-x6476,856115
    darwin-aarch6466,159186
    windows-x6490,61685

    The differences are in spawn (Memfd and pidfd gone where they cannot exist, the cleanup guard), bake (Style and what contains it, mostly drop glue), everything on POSIX that matches on InternalSocket (about 100 networking functions recompiled for four variants instead of five; the removed arms were unreachable), field offsets on Windows shifted by the removed fields, and two Windows startup functions without the waiter-thread env lookup. On macOS about 30 more differ only in nop padding or in the addresses of constants. A function that changed while keeping its exact size would not show.

  • Not run locally: a build or tests on macOS or Windows (only cargo check for those), and the mordant job. No benchmark was run.