Say the platform once: real #[cfg] in place of stubs, placeholders, let _ = x and allow(...)
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/**/*.rs | main | this PR |
|---|---|---|
item-level allow(dead_code) escapes | 77 | 0 |
#[cfg(...)] attributes | 5,217 | 5,063 |
single-name let _ = x; | 385 | 302 |
The changes, by theme (later review commits are folded into the theme they belong to)
- spawn: a memfd stdio exists where memfd does.
Stdio::Memfdand theMemfdvariants of the subprocess and shellReadable/Writableare Linux/Android-only, withcan_use_memfd,use_memfdandtake_memfd. Gone:#[cfg(windows)] Self::Memfd(_) => panic!("This should never happen"),panic!("memfd is only supported on Linux"), thereturn falsestub bodies.Bun.spawn's memfd cleanup guard goes too:stdiois an owned[Stdio; 3]that is never moved, andStdio'sDropcloses a memfd, so the guard repeated that. - napi, collections.
NapiStatuswas listed in full underallow(dead_code)because two extern declarations typed a C++-produced status as the Rust enum. They takenapi_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 anoffset_of!, a use the lint can see. - 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,FileClonergated as a module, the shellPipeReader.stdio_resultas a POSIX field. Deleted: a single-use alias, a hand-declaredsetenv, adebug_assert!on the constanttrue. - 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.rsalone had 36 repeats and 7not(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, inWindowsNamedPipe.rs, hold only raw pointers and a temporary. - Stubs for platforms whose callers never reach them.
bun_sys::{writev, readv, preadv, statfs}are unix functions (Windows reaches these throughsys_uv). Deleted: the non-macOSclonefileat, the non-Linuxcan_use_memfd, the Windowsus_socket_t::write_fd(unreachable!).snapshot_childrenandkill_subreaper_adopteesare Linux functions like their callers, without stub arms. 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.- Placeholders for another platform's types.
windows: ()/pseudoconsole: ()in the POSIX spawn options,PidFdType = ()off Linux, Windowsstruct WaitPidResult {}andenum WaiterThread {}, the event loop'ssignal_handler: (),ExceptionValidationScope._scope: (),MemoryAccessor._mem: (). The POSIX signal ring is a unix type. - A rename flag nobody sets and a Windows
dup2nobody calls. Withoutnofollow,Renameat2Flagswrapped one field, sorenameat2takes theRenameMode. allowattributes that allow nothing. Every single-lineallowoutside proc-macro crates and macro bodies was rewritten asexpect, 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, andclippy::not_unsafe_ptr_arg_deref, which only checks exported functions: these arepub(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_typesinbun_ptrandbun_sysis back as#![cfg_attr(test, allow(...))]. Nothing is left asexpect.dead_codeescapes inside macros do nothing. rustc does not reportdead_codefor an item another crate's macro generated, only for one from a macro in the same crate, and every use ofopaque_ffi!,multi_array_columns!,comptime_string_map!, the css derives andjsc_macros'Gcenum 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.- The last platform-only items behind escapes.
posix_spawn.rsis a unix module and says so where it is mounted (31 repeats of#[cfg(unix)]go withAttr'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, andspawn_bunborrows its request.patch::ApplyStateis#[cfg(windows)], down toapply_patch's parameter.WindowsNamedPipewrites its two Windows writer-parent impls by hand, asTerminaldoes, in place of a macro that also stamps a POSIX impl; the field that existed only to be named there goes.InternalSocket::Pipeno longer exists on POSIX: its only constructor was one of the stand-ins removed in 4. Style::JavascriptDefineddoes not keep a function nothing calls. A style function is still accepted and the route scan still panics withTODO: customizable Style. TheStrongthe variant held is gone, soStyleis a plainCopyenum and the hand-writtenClone, with its own copy of the panic, goes. The dev server and production build reached that copy first; they now reach the scan's.- The escape inventory is a ban.
dead-code-escape-limits.jsonis 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.rsneeds its one: the generator emits the full accessor set for every class and each class uses a subset. The fiveh2/*.rsfiles hide the unused outbound half of a rewrite in progress. allowattributes insidemacro_rules!bodies, other than thedead_codein 10: an expectation there is judged per expansion.- File-level
#![cfg(windows)]that repeat themoddeclaration'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 --workspaceon 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 underdebug_assertionsis not compiled there, so something used only by it is unused. -
cargo check --workspace --all-targetson the same five targets, andcargo clippy --workspace --no-depson Linux.cargo clippy --workspace --all-targetsreports 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_embedin release). -
test/internal/source-lints/dead-code-escapes.test.tspasses, 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.spawnwith aBlobstdin (the memfd path),Bun.spawnSyncwith a buffer stdin, a shell pipeline and repeatedSIGUSR1handling work. A function asstylepanics with the same message as before and an invalidstylethrows 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) andno-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):
functions differ linux-x64 76,856 115 darwin-aarch64 66,159 186 windows-x64 90,616 85 The differences are in spawn (
Memfdandpidfdgone where they cannot exist, the cleanup guard), bake (Styleand what contains it, mostly drop glue), everything on POSIX that matches onInternalSocket(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 innoppadding 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 checkfor those), and themordantjob. No benchmark was run.