Remove dead code from libuv_sys, cares_sys, simdutf FFI, test_runner, and C++ bindings

Merged
RO
3mo ago
+263-1751

Scheduled dead-code sweep. Areas this run: src/libuv_sys, src/cares_sys, src/brotli_sys, src/simdutf_sys (both sides of the FFI), src/runtime/test_runner, a few bun_runtime leftovers, and C++ bindings outside the files the other open dead-code PRs touch. Net: 43 files, +218 (the new lint) / -1723.

Removed

bun_libuv_sys (Windows-only crate, -619)

  • 169 extern "C" declarations that no Rust code references: the tcp/udp/tty/poll/prepare/check/fs_poll/threading/dl/os-info/metrics surface of uv.h (uv_tcp_*, uv_udp_*, uv_tty_get_winsize, uv_prepare_*, uv_check_*, uv_fs_poll_*, uv_thread_*, uv_key_*, uv_once, uv_os_get_passwd, uv_os_environ, uv_queue_work, uv_getnameinfo, uv_random, uv_async_init, uv_dlopen, ...). The C symbols themselves stay exported for napi addons via symbols.def/symbols.dyn/linker*.lds and the force-link list in napi_body.rs; only bun's own unused Rust declarations go.
  • Structs and callback aliases only those declarations used: uv_getnameinfo_t, uv_random_t, uv_timespec64_t, uv_timeval64_t, uv_dir_t, uv_dirent_t, uv_env_item_t, uv_passwd_t, uv_group_t, uv_metrics_t, uv_key_t, uv_once_t, uv_thread_options_t, uv_lib_t, uv_getnameinfo_cb, uv_random_cb, uv_fs_poll_cb, uv_thread_cb, plus the uv_sem_t/uv_errno_t/uv_handle_s/uv_loop_s/uv_run_mode/uv_pipe_t/uv_fs_s/struct_uv_req_s/struct_uv_stream_s/uv_dirent_type_t/FILE/uv_thread_t/uv_loop_option/uv_membership/uv_tty_vtermstate_t/uv_clock_id aliases.
  • Wrappers nobody called: the UvReq marker trait and its 10 impls, Loop::dump_active_handles, Pipe::set_pending_instances_count, Pipe::as_stream_ptr, uv_async_t::init, uv_stat_t::birthtime.
  • Alias tables nothing read: StdioFlags (the three StdioFlags::INHERIT_FD uses in bun_spawn now spell UV_INHERIT_FD like the rest of that function), UV_FS_O_* (duplicates of the O module), UV_PRIORITY_*, UV_CLOCK_*, UV_LOOP_BLOCK_SIGNAL/UV_METRICS_IDLE_TIME, the udp/tty-mode/membership/copyfile flag groups, UV_MAXHOSTNAMESIZE, UV_IF_NAMESIZE, MAX_PIPENAME_LEN.

bun_cares_sys (-118): ares_library_init, ares_version, ares_init, ares_set_socket_functions, ares_send, ares_search, ares_gethostbyname, ares_getsock, ares_timeout, ares_create_query, ares_expand_name, ares_expand_string, ares_parse_uri_reply, ares_free_string, the ares_socket_functions and struct_ares_uri_reply structs, the ares_ssize_t/struct_timeval aliases, two commented-out ares_fds/ares_process declarations, and the Windows timeval/iovec definitions in lib.rs that existed only for them.

bun_brotli_sys: BrotliDecoder::{is_finished, get_error_code, version} and the BrotliDecoderIsFinished/BrotliDecoderVersion declarations (callers use BrotliDecoderGetErrorCode directly).

simdutf FFI (-230): 22 unused declarations in simdutf.rs and 30 wrappers in bun-simdutf.cpp (the 22 plus 8 that had already lost their Rust declaration), and their stubs in the parser bench shim. The lint asserts the two files now declare exactly the same set of simdutf__* names.

bun_runtime

  • test_runner::expect::JSValueTestExt: 17 forwarder methods (to_fmt, jest_deep_equals, values, keys, to_u32, ...) that bun_jsc::JSValue inherent methods of the same name shadow, so no call site ever resolved to them; rustc reports them unused once the trait is scoped to the crate. The four methods that do add behavior stay.
  • Never-read fields: CustomMatcherParamsFormatter::global_this (and its now-unused lifetime), SuccessfulReturnsFormatter::global_this, FetchOptions::global_this.
  • S3ErrorJsc::to_js (every caller uses the s3_error_to_js free fn).

C++ bindings (roughly -590)

  • Events_functionGetEventListeners / ListenerCount / Once / On in JSEventEmitter.cpp (declared in the header, never installed anywhere) and jsEventEmitterCast + JSEventEmitterWrapper, whose only callers they were. jsEventEmitterCastFast is untouched.
  • jsFunctionDebugNoop, jsFunctionSyncBuiltinExports (NodeModuleModule.cpp; the live export is jsFunctionSyncBuiltinESMExports).
  • jsCookieStaticFunctionSerialize (never attached to the constructor; only parse/from are) plus its helpers toCookieWrapped and Cookie::serialize(VM&, span<Ref<Cookie>>). The prototype serialize() is untouched.
  • Nine JSC_DECLARE_CUSTOM_GETTER(jsBakeResponsePrototypeGet*) declarations with no definition.
  • UTF8Encoding(), createMockResultStructure (the LazyProperty initializer inlines the same code), ActiveDOMObject::queueTaskToDispatchEvent and the queueTaskToDispatchEventInternal / isAllowedToRunScript / PendingActivity::object helpers that became unreferenced with it, StreamQueue::setTotalSize, WorkerMessagingProxy::{askedToTerminate, loaderContextIdentifier, workerThread} getters, 19 m_subspaceFor* / m_clientSubspaceFor* slots no class allocates from, the commonStringInitializer typedef, the BUN_FOREACH_CJS_NATIVE_MODULE macro, a DocumentLoadTiming forward declaration.
  • The five cross-realm (transferable stream) stubs in CrossRealmTransform.cpp / WebStreamsInternals.h, which only threw "not implemented" and had no callers, plus CrossRealmMessageType. WebStreamsInternals.h described these signatures as frozen placeholders from the streams port; nothing reaches them, so they are deleted here, but this is the one group in the PR that is a judgment call rather than a leftover, so it is easy to drop if you would rather keep the placeholders.
  • EventInterfaces.h / EventTargetInterfaces.h: checked-in copies of WebCore's generated enums listing every event and event-target interface in WebKit. Trimmed to the 5 + 9 entries bun's Event / EventTarget subclasses report; survivors keep their numeric values (Event::m_eventInterface is a 7-bit field, and EventFactory.cpp / EventTargetFactory.cpp both have default: arms).

Verification

  • Each symbol: rg across src/, scripts/, test/, packages/ and the regenerated build/debug/codegen/ output (plus substring searches for token-pasted names and vendor/WebKit/Source for anything extern "C").
  • Rust candidates came from scoping same-crate-only pub items to pub(crate) and intersecting rustc's dead_code output across all 8 target families, so platform-specific items (e.g. EmptyCopyFileState on darwin, Listener::NamedPipe on Windows) were excluded automatically; bun_libuv_sys was evaluated on the Windows targets since the module is cfg(windows).
  • cargo check --workspace on all 10 CI triples, cargo check --workspace --tests, cargo fmt --check, clippy on the touched crates, full bun bd, and bun bd test over events, cookies, node:module, TextEncoder/TextDecoder, expect.extend, toHaveReturnedWith, streams, fetch, zlib/brotli, mock, and test/internal/source-lints/ (the dns file's 30 network-dependent tests fail in the sandbox with ENOTFOUND both before and after; its 92 offline tests pass).
  • test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts pins 67 of the removed symbols (every entry was checked to match on main and not on this branch).

Notes for whoever merges

  • #32268 adds RETURN_IF_EXCEPTION lines inside the Events_function* bodies deleted here (its actual fix is in jsEventEmitterCastFast, which this PR does not touch); whichever lands second needs a trivial rebase that drops those hunks.
  • Found dead but deliberately left alone: VM::has_termination_request, JSPromise::settle_task, job.rs on_js_thread / off_thread (all added two days ago in #37075, presumably for follow-ups); JSC__VM__hasTerminationRequest goes with them. Single unconstructed variants / unread payloads inside otherwise-live ABI or ported enums (SSRKind::Regular, DeclarationContext::Keyframes, StmtListWhich::AllStmts, OptionsData::Saved(usize), AsyncState::Done(ExitCode)) and the remaining partially-used libuv constant tables were also left as-is. rustc's "field is never read" hits on multi_array_columns! schema structs (JSMeta, BuilderEntry, LineOffsetTable, ServerComponentBoundary, the isolated-install Entry, BundledAst::tla_check) and on the type-punned SerializedSourceMapLoaded are live data, not dead code.

[review] gate passed · iteration 0 · 43 files touched

fails on main (without fix)
ASAN without fix: 6 FAILED
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts
bun test v1.4.0 (3f65303a0)

test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts:
59 |       ["src/libuv_sys/libuv.rs", /\bUV_FS_O_APPEND\b/],
60 |       ["src/libuv_sys/libuv.rs", /\bUV_PRIORITY_LOW\b/],
61 |       ["src/libuv_sys/libuv.rs", /\bUV_CLOCK_MONOTONIC\b/],
62 |       ["src/spawn/process.rs", /\bStdioFlags\b/],
63 |     ]),
64 |   ).toEqual([]);
         ^
error: expect(received).toEqual(expected)

- []
+ [
+   "src/libuv_sys/libuv.rs: \bfn uv_tcp_connect\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_udp_recv_start\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_tty_get_winsize\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_prepare_init\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_fs_poll_start\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_thread_create\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_os_get_passwd\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_queue_work\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_async_init\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_dlopen\b",
... (truncated)

release without fix: 6 FAILED
bun test v1.4.0-canary.1 (8db13c363)

test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts:
59 |       ["src/libuv_sys/libuv.rs", /\bUV_FS_O_APPEND\b/],
60 |       ["src/libuv_sys/libuv.rs", /\bUV_PRIORITY_LOW\b/],
61 |       ["src/libuv_sys/libuv.rs", /\bUV_CLOCK_MONOTONIC\b/],
62 |       ["src/spawn/process.rs", /\bStdioFlags\b/],
63 |     ]),
64 |   ).toEqual([]);
         ^
error: expect(received).toEqual(expected)

- []
+ [
+   "src/libuv_sys/libuv.rs: \bfn uv_tcp_connect\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_udp_recv_start\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_tty_get_winsize\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_prepare_init\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_fs_poll_start\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_thread_create\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_os_get_passwd\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_queue_work\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_async_init\b",
+   "src/libuv_sys/libuv.rs: \bfn uv_dlopen\b",
+   "src/libuv_sys/libuv.rs: \bstruct uv_passwd_t\b",
+   "src/libuv_sys/libuv.rs: \bstruct uv_getnameinfo_t\b",
+   "src/libuv_sys/libuv.rs: \bstruct uv_thread_options_t\b",
+   "src/libuv_sys/l
... (truncated)
passes on PR (with fix)
ASAN with fix: all passed
$ BUN_DEBUG_QUIET_LOGS=1 bun scripts/build.ts --profile=debug --quiet test "--reporter=junit" "--reporter-outfile=/tmp/mechgate.xml" test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts
bun test v1.4.0 (3f65303a0)

test/internal/source-lints/dead-symbols-ffi-sys-test-runner-cpp.test.ts:
(pass) dead libuv FFI declarations (windows-only crate) do not reappear [64.93ms]
(pass) dead c-ares and brotli FFI declarations do not reappear [19.79ms]
(pass) dead simdutf wrappers stay removed on both sides of the FFI [35.67ms]
(pass) dead bun_runtime helpers do not reappear [14.26ms]
(pass) dead C++ bindings do not reappear [28.17ms]
(pass) WebCore event interface enums stay trimmed to the interfaces bun implements [9.48ms]

 6 pass
 0 fail
 11 expect() calls
Ran 6 tests across 1 file. [2.71s]
__F:0:S:0

release with fix: all passed
$ bun scripts/build.ts --profile=release
[configured] bun-profile → bun (stripped) in 883ms (unchanged)
ninja: Entering directory `/workspace/bun/build/release'
[1/126] gen NodeModuleModule.lut.h
Generating /workspace/bun/build/release/codegen/NodeModuleModule.lut.h from /workspace/bun/src/jsc/modules/NodeModuleModule.cpp
[2/126] gen generated_host_exports.rs
generated_host_exports.rs: 93 exports (host=3, lazy=10, generic=80, rust=0); 239 extern-C blocks audited
[3/126] gen cpp.rs (cppbind)
[3/126] cargo bun_bin → libbun_rust.a (--target x86_64-unknown-linux-gnu)

  nightly-2026-07-20-x86_64-unknown-linux-gnu unchanged - rustc 1.99.0-nightly (9f36de775 2026-07-19)

   Compiling bun_core v0.0.0 (/workspace/bun/src/bun_core)
   Compiling bun_simdutf_sys v0.0.0 (/workspace/bun/src/simdutf_sys)
   Compiling bun_libuv_sys v0.0.0 (/workspace/bun/src/libuv_sys)
   Compiling bun_brotli_sys v0.0.0 (/workspace/bun/src/brotli_sys)
   Compiling bun_errno v0.0.0 (/workspace/bun/src/errno)
   Compiling bun_ptr v0.0.0 (/workspace/bun/src/ptr)
   Compiling bun_boringssl_sys v0.0.0 (/works
... (truncated)
diff hotspot
src/brotli_sys/brotli_c.rs                         |  14 -
 src/cares_sys/c_ares.rs                            | 110 +---
 src/cares_sys/lib.rs                               |  16 +-
 src/jsc/bindings/BunHttp2CommonStrings.h           |   2 -
 src/jsc/bindings/Cookie.cpp                        |  19 -
 src/jsc/bindings/Cookie.h                          |   2 -
 src/jsc/bindings/DOMFormData.h                     |   1 -
 src/jsc/bindings/JSBakeResponse.cpp                |  10 -
 src/jsc/bindings/JSMockFunction.cpp                |  23 -
 src/jsc/bindings/TextEncoding.cpp                  |   8 -
 src/jsc/bindings/TextEncoding.h                    |   2 -
 src/jsc/bindings/webcore/ActiveDOMObject.cpp       |  21 -
 src/jsc/bindings/webcore/ActiveDOMObject.h         |  13 -
 src/jsc/bindings/webcore/DOMClientIsoSubspaces.h   |  10 -
 src/jsc/bindings/webcore/DOMIsoSubspaces.h         |  11 -
 src/jsc/bindings/webcore/EventInterfaces.h         | 127 ----
 src/jsc/bindings/webcore/EventTargetInterfaces.h   | 104 ----
 src/jsc/bindings/webcore/JSCookie.cpp              |  36 --
 src/jsc/bindings/webcore/JSEventEmitter.cpp        |  91 ---
 src/jsc/bindings/webcore/JSEventEmitter.h          |   5 -
 src/jsc/bindings/webcore/JSEventEmitterCustom.cpp  |   9 -
 src/jsc/bindings/webcore/JSEventEmitterCustom.h    |  21 -
 src/jsc/bindings/webcore/Performance.h             |   1 -
 src/jsc/bindings/webcore/WorkerMessagingProxy.h    |   3 -
 .../webcore/streams/CrossRealmTransform.cpp        |  48 +-
 .../streams/JSWritableStreamDefaultController.cpp  |   2 +-
 src/jsc/bindings/webcore/streams/StreamQueue.h     |   1 -
 src/jsc/bindings/webcore/streams/StreamsForward.h  |   7 -
 .../bindings/webcore/streams/WebStreamsInternals.h |  15 -
 src/jsc/modules/NativeModuleList.h                 |   3 -
 src/jsc/modules/NodeModuleModule.cpp               |  16 -
 src/libuv_sys/libuv.rs                             | 641 +--------------------
 src/parsers/benches/support/s
... (truncated)

gate history · 4 passed · 0 rejected · iteration 0

evidence per changed file
file                                              reads  edits  tests
src/brotli_sys/brotli_c.rs                            1      2      0
src/cares_sys/c_ares.rs                               5     10      0
src/cares_sys/lib.rs                                  1      2      0
src/jsc/bindings/BunHttp2CommonStrings.h              0      0      0
src/jsc/bindings/Cookie.cpp                           0      0      0
src/jsc/bindings/Cookie.h                             0      0      0
src/jsc/bindings/DOMFormData.h                        0      0      0
src/jsc/bindings/JSBakeResponse.cpp                   0      0      0
src/jsc/bindings/JSMockFunction.cpp                   0      0      0
src/jsc/bindings/TextEncoding.cpp                     0      0      0
src/jsc/bindings/TextEncoding.h                       0      0      0
src/jsc/bindings/webcore/ActiveDOMObject.cpp          0      0      0
src/jsc/bindings/webcore/ActiveDOMObject.h            0      0      0
src/jsc/bindings/webcore/DOMClientIsoSubspaces.h      0      0      0
src/jsc/bindings/webcore/DOMIsoSubspaces.h            0      0      0
src/jsc/bindings/webcore/EventInterfaces.h            1      0      0
(+ 27 more files)