Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/workflows/source-lints.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ on:
branches: [main]
paths:
- "src/**/*.rs"
- "src/**/Cargo.toml"
- "Cargo.toml"
- "src/**/*.h"
- "src/**/*.cpp"
- "src/**/*.bind.ts"
Expand Down Expand Up @@ -42,6 +44,8 @@ on:
pull_request:
paths:
- "src/**/*.rs"
- "src/**/Cargo.toml"
- "Cargo.toml"
- "src/**/*.h"
- "src/**/*.cpp"
- "src/**/*.bind.ts"
Expand Down
135 changes: 123 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# For `rustflags` in `[profile.dev]` and `[profile.release]`.
cargo-features = ["profile-rustflags"]

[workspace]
resolver = "2"
members = [
Expand All @@ -5,7 +8,7 @@
"src/pod",
"src/analytics",
"src/base64",
"src/bundler",

Check warning on line 11 in Cargo.toml

View workflow job for this annotation

GitHub Actions / lol-html cargo test

explicit `package.readme` can be inferred
"src/collections",
"src/css",
"src/errno",
Expand Down Expand Up @@ -146,6 +149,7 @@
[workspace.package]
version = "0.0.0"
edition = "2024"
publish = false

# ─── Release optimization ───────────────────────────────────────────────────
# Zig's release build is one compilation unit with whole-program optimization.
Expand All @@ -168,9 +172,57 @@
debug = "line-tables-only"
strip = "none"
panic = "abort"
# The nightly features the workspace's own crates may enable, as the Linux kernel lists its own. A `#![feature(..)]`
# that is not here is error E0725. A nightly feature can change or go away with any toolchain bump, so taking on a new
# one is a decision, made by adding it to this list and to the one in `[profile.dev]`.
rustflags = ["""-Zallow-features=\
Comment thread
dylan-conway marked this conversation as resolved.
Resolved
adt_const_params,\
alloc_error_hook,\
allocator_api,\
arbitrary_self_types_pointers,\
const_cmp,\
const_trait_impl,\
core_intrinsics,\
freeze,\
hasher_prefixfree_extras,\
inherent_associated_types,\
linkage,\
optimize_attribute,\
rust_cold_cc,\
rustc_attrs,\
thread_local,\
transmutability,\
type_info,\
unsized_const_params,\
vec_fallible_shrink"""]

# Dependencies, and std under `-Zbuild-std`, enable features of their own.
[profile.release.package."*"]
rustflags = []

[profile.dev]
panic = "abort"
# See `[profile.release]`.
rustflags = ["""-Zallow-features=\
adt_const_params,\
alloc_error_hook,\
allocator_api,\
arbitrary_self_types_pointers,\
const_cmp,\
const_trait_impl,\
core_intrinsics,\
freeze,\
hasher_prefixfree_extras,\
inherent_associated_types,\
linkage,\
optimize_attribute,\
rust_cold_cc,\
rustc_attrs,\
thread_local,\
transmutability,\
type_info,\
unsized_const_params,\
vec_fallible_shrink"""]
# Split DWARF: debuginfo goes into `.dwo` files alongside each `.o` instead of
# being packed into the rlibs. Per-crate codegen writes less to disk, and `gdb`/`lldb` still resolve full debuginfo via
# the skeleton CUs (`DW_AT_dwo_name`) pointing into `<target>/deps/*.dwo`.
Expand All @@ -179,6 +231,9 @@
# `dsymutil` already expects.
split-debuginfo = "unpacked"

[profile.dev.package."*"]
rustflags = []

# Release with debuginfo retained for `perf record` / flamegraphs. Same opt
# level as release; binary is large but profilable.
[profile.release-profiling]
Expand Down Expand Up @@ -239,8 +294,17 @@
unused_mut = "deny"
unused_assignments = "deny"
unused_macros = "deny"
unused_must_use = "deny"
unreachable_code = "deny"
unreachable_patterns = "deny"
unused_import_braces = "deny"
unused_lifetimes = "deny"
redundant_lifetimes = "deny"
macro_use_extern_crate = "deny"
meta_variable_misuse = "deny"
ambiguous_negative_literals = "deny"
non_ascii_idents = "deny"
ffi_unwind_calls = "deny"

[workspace.lints.clippy]
# == provenance-safe pointer casts ==
Expand All @@ -262,6 +326,18 @@
as_ptr_cast_mut = "deny"
drop_non_drop = "deny"
uninit_vec = "deny"
transmute_undefined_repr = "deny"
uninhabited_references = "deny"
trailing_empty_array = "deny"
read_zero_byte_vec = "deny"
coerce_container_to_any = "deny"
fallible_impl_from = "deny"
unchecked_time_subtraction = "deny"
invalid_upcast_comparisons = "deny"
same_functions_in_if_condition = "deny"
suspicious_xor_used_as_pow = "deny"
float_cmp_const = "deny"
path_buf_push_overwrite = "deny"

# == performance ==
redundant_clone = "deny"
Expand All @@ -280,6 +356,15 @@
format_collect = "deny"
manual_memcpy = "deny"
needless_pass_by_value = "deny"
inefficient_to_string = "deny"
unnecessary_join = "deny"
string_add_assign = "deny"
clear_with_drain = "deny"
set_contains_or_insert = "deny"
iter_on_empty_collections = "deny"
with_capacity_zero = "deny"
trivial_regex = "deny"
linkedlist = "deny"

# == clarity / api hygiene ==
unnecessary_unwrap = "deny"
Expand All @@ -305,6 +390,44 @@
precedence = "deny"
implicit_saturating_sub = "deny"
ptr_eq = "deny"
ptr_offset_by_literal = "deny"
explicit_deref_methods = "deny"
get_unwrap = "deny"
try_err = "deny"
filter_map_next = "deny"
flat_map_option = "deny"
iter_filter_is_ok = "deny"
iter_filter_is_some = "deny"
search_is_some = "deny"
manual_is_variant_and = "deny"
manual_bit_width = "deny"
manual_instant_elapsed = "deny"
duration_suboptimal_units = "deny"
ip_constant = "deny"
range_minus_one = "deny"
index_refutable_slice = "deny"
single_char_pattern = "deny"
string_lit_chars_any = "deny"
non_zero_suggestions = "deny"
large_digit_groups = "deny"
unicode_not_nfc = "deny"
unnecessary_debug_formatting = "deny"
unnecessary_literal_bound = "deny"
unused_peekable = "deny"
unused_rounding = "deny"
self_only_used_in_recursion = "deny"
ref_option_ref = "deny"
into_iter_without_iter = "deny"
mismatching_type_param_order = "deny"
trait_duplication_in_bounds = "deny"
macro_use_imports = "deny"
inline_asm_x86_att_syntax = "deny"
unnecessary_safety_doc = "deny"
doc_broken_link = "deny"
doc_comment_double_space_linebreaks = "deny"
doc_include_without_cfg = "deny"
# Reads the manifests, not the code.
negative_feature_names = "deny"
Comment thread
dylan-conway marked this conversation as resolved.
Resolved

# == disallowed-* (configured in clippy.toml) ==
disallowed_methods = "deny"
Expand All @@ -320,7 +443,6 @@
len_zero = "allow"
len_without_is_empty = "allow"
needless_return = "allow"
module_inception = "allow"
missing_safety_doc = "allow"
let_unit_value = "allow"
needless_update = "allow"
Expand All @@ -332,27 +454,16 @@
wrong_self_convention = "allow"
should_implement_trait = "allow"
new_without_default = "allow"
self_named_constructors = "allow" # Zig-port `Type::init()` constructor convention
single_match = "allow"
manual_range_contains = "allow"
needless_lifetimes = "allow"
needless_range_loop = "allow"
while_let_loop = "allow"
while_let_on_iterator = "allow"
blocks_in_conditions = "allow"
diverging_sub_expression = "allow"
declare_interior_mutable_const = "allow"
empty_line_after_doc_comments = "allow"
empty_docs = "allow"
excessive_precision = "allow"
unreadable_literal = "allow"
approx_constant = "allow"
result_unit_err = "allow"
only_used_in_recursion = "allow"
# `as u32` etc. is identity on some libc targets, required widen on others
unnecessary_cast = "allow"
new_ret_no_self = "allow"
map_identity = "allow"

[workspace.dependencies]
rust-argon2 = { path = "vendor/rust-argon2" }
Expand Down
31 changes: 30 additions & 1 deletion clippy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,35 @@ disallowed-methods = [
{ path = "std::fs::read_dir", reason = "use bun_sys::dir" },
{ path = "std::fs::read_link", reason = "use bun_sys::file" },
{ path = "std::fs::symlink_metadata", reason = "use bun_sys::file" },
{ path = "std::os::unix::fs::symlink", reason = "use bun_sys::file" },
{ path = "std::fs::copy", reason = "use bun_sys::copy_file" },
{ path = "std::fs::exists", reason = "use bun_sys::exists" },
{ path = "std::fs::hard_link", reason = "use bun_sys::linkat (POSIX) or bun_sys::link_w (Windows)" },
{ path = "std::fs::remove_dir", reason = "use bun_sys::rmdir" },
{ path = "std::fs::set_permissions", reason = "use bun_sys::fchmod, or bun_sys::chmod (POSIX) / bun_sys::sys_uv::chmod (Windows)" },
{ path = "std::fs::soft_link", reason = "use bun_sys::symlink" },
# A path that only one platform's std has needs `allow-invalid`, or clippy warns about it when it lints for another.
{ path = "std::os::unix::fs::symlink", reason = "use bun_sys::symlink", allow-invalid = true },
{ path = "std::os::windows::fs::symlink_file", reason = "use bun_sys::symlink_w", allow-invalid = true },
{ path = "std::os::windows::fs::symlink_dir", reason = "use bun_sys::symlink_or_junction", allow-invalid = true },
# `Path`'s own spelling of the functions above.
{ path = "std::path::Path::exists", reason = "use bun_sys::exists" },
{ path = "std::path::Path::try_exists", reason = "use bun_sys::exists" },
{ path = "std::path::Path::is_file", reason = "use bun_sys::stat" },
{ path = "std::path::Path::is_dir", reason = "use bun_sys::directory_exists_at" },
{ path = "std::path::Path::is_symlink", reason = "use bun_sys::lstat" },
{ path = "std::path::Path::metadata", reason = "use bun_sys::stat" },
{ path = "std::path::Path::symlink_metadata", reason = "use bun_sys::lstat" },
{ path = "std::path::Path::canonicalize", reason = "use bun_paths" },
{ path = "std::path::Path::read_link", reason = "use bun_sys::readlink" },
{ path = "std::path::Path::read_dir", reason = "use bun_sys::iterate_dir" },
{ path = "std::env::var", reason = "use bun_core::env_var" },
{ path = "std::env::var_os", reason = "use bun_core::env_var" },
{ path = "std::env::vars", reason = "use bun_sys::environ, or bun_dotenv::Loader::load_process for a map" },
{ path = "std::env::vars_os", reason = "use bun_sys::environ, or bun_dotenv::Loader::load_process for a map" },
{ path = "std::env::home_dir", reason = "use bun_core::env_var::HOME" },
{ path = "std::env::set_current_dir", reason = "use bun_sys::chdir" },
{ path = "std::env::set_var", reason = "std's lock does not cover the C and C++ code that reads environ; for a child process, put it in the bun_dotenv::Map the child is spawned with" },
{ path = "std::env::remove_var", reason = "std's lock does not cover the C and C++ code that reads environ; for a child process, remove it from the bun_dotenv::Map the child is spawned with" },
{ path = "std::thread::spawn", reason = "use std::thread::Builder with a stack size, and name the thread (Output::Source::configure_named_thread), or use bun_threading::ThreadPool" },
{ path = "std::mem::zeroed", reason = "use MaybeUninit; zeroed is UB for most Bun types" },
{ path = "bun_core::output::pretty_fmt_rt", reason = "const format strings must use pretty_fmt!/write_pretty! (compile-time rewrite); the runtime walk is only for templates built at runtime — allow with justification" },
Expand Down Expand Up @@ -98,6 +124,9 @@ disallowed-types = [
{ path = "std::collections::HashMap", reason = "use bun_collections (wyhash)" },
{ path = "std::collections::HashSet", reason = "use bun_collections (wyhash)" },
{ path = "std::fs::File", reason = "use bun_sys::File" },
{ path = "std::fs::OpenOptions", reason = "use bun_sys::File::open / File::openat with bun_sys::O flags" },
{ path = "std::fs::ReadDir", reason = "use bun_sys::iterate_dir" },
{ path = "std::fs::DirBuilder", reason = "use bun_sys::mkdir / bun_sys::mkdir_recursive" },
{ path = "core::simd::Simd", reason = "use bun_highway / bun_core::strings (highway): one SIMD system, with runtime dispatch" },
{ path = "core::simd::Mask", reason = "use bun_highway / bun_core::strings (highway): one SIMD system, with runtime dispatch" },
{ path = "std::process::Command", reason = "use bun_core::util::spawn_sync_inherit (CLI helpers) or bun_spawn_sys (full control)" },
Expand Down
13 changes: 8 additions & 5 deletions scripts/build/rust/units.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,8 @@ export function buildRustGraph(plan: RustPlan, dir: string): RustGraph {

// Hashes, computed topologically over the DAG. `symbolHash` (→ `-C metadata`) must differ wherever two builds
// of one crate name can meet in a link — host vs target, sysroot std vs build-std std, feature sets — and must
// *not* differ between builds meant to have identical symbols (PGO generate/use), so it excludes the rustflags.
// *not* differ between builds meant to have identical symbols (PGO generate/use), so it excludes the rustflags,
// the plan's and the profile's: a release link orders its symbols by the names an earlier build had (`linker.order`).
// `hash` (→ file names) additionally covers the rustflags. cargo: compute_metadata's c_metadata vs unit_id.
// A package from a registry is named by its id (source URL + name + version), also when it is one of std's
// dependencies: those live under $CARGO_HOME, and a path to them would put the machine's directory layout into
Expand All @@ -196,8 +197,10 @@ export function buildRustGraph(plan: RustPlan, dir: string): RustGraph {
: relative(plan.workspaceRoot, unit.pkg.manifest_path);
const digest = (parts: unknown[]): string =>
createHash("sha256").update(JSON.stringify(parts)).digest("hex").slice(0, 16);
const identity = (unit: RustUnit): unknown[] => {
const identity = (unit: RustUnit, of: "symbols" | "files"): unknown[] => {
const u = g.units[unit.index]!;
// cargo leaves the key out of a profile that has none.
const { rustflags: _, ...profileWithoutRustflags } = u.profile;
return [
3, // bump to invalidate every artifact
packageKey(unit),
Expand All @@ -207,7 +210,7 @@ export function buildRustGraph(plan: RustPlan, dir: string): RustGraph {
unit.platform,
u.mode,
[...unit.features].sort(),
u.profile,
of === "symbols" ? profileWithoutRustflags : u.profile,
unit.isStd,
plan.rustc.version,
plan.rustc.commitHash,
Expand All @@ -219,12 +222,12 @@ export function buildRustGraph(plan: RustPlan, dir: string): RustGraph {
for (const d of unit.deps) hashesOf(d.unit);
if (unit.buildScript !== undefined) hashesOf(unit.buildScript);
unit.symbolHash = digest([
...identity(unit),
...identity(unit, "symbols"),
unit.deps.map(d => [d.externName, d.unit.symbolHash]),
unit.buildScript?.symbolHash ?? null,
]);
unit.hash = digest([
...identity(unit),
...identity(unit, "files"),
unit.platform === "host" ? [] : targetRustflags.filter(f => !f.startsWith("--remap-path-prefix")),
unit.deps.map(d => [d.externName, d.unit.hash]),
unit.buildScript?.hash ?? null,
Expand Down
1 change: 1 addition & 0 deletions src/analytics/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_analytics"
version.workspace = true
edition.workspace = true
publish.workspace = true

[lib]
path = "lib.rs"
Expand Down
1 change: 1 addition & 0 deletions src/aot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_aot"
version.workspace = true
edition.workspace = true
publish.workspace = true
build = "build.rs"

[lib]
Expand Down
1 change: 1 addition & 0 deletions src/aot/absent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_aot_absent"
version.workspace = true
edition.workspace = true
publish.workspace = true

[lib]
path = "lib.rs"
Expand Down
1 change: 1 addition & 0 deletions src/aot/builtins/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_aot_builtins"
version.workspace = true
edition.workspace = true
publish.workspace = true
build = "build.rs"

[lib]
Expand Down
1 change: 1 addition & 0 deletions src/aot/interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_aot_interface"
version.workspace = true
edition.workspace = true
publish.workspace = true

[lib]
path = "lib.rs"
Expand Down
2 changes: 1 addition & 1 deletion src/aot/ir/packed_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const FLAGS_AT: u32 = POSITION_AT + width(PositionFlags::ALL.0);
const _: () = assert!(FLAGS_AT + width(FieldFlags::ALL.0) <= u32::BITS);

const fn width(all: u32) -> u32 {
u32::BITS - all.leading_zeros()
all.bit_width()
}

#[derive(Default)]
Expand Down
1 change: 1 addition & 0 deletions src/archive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_archive"
version.workspace = true
edition.workspace = true
publish.workspace = true

[lib]
path = "lib.rs"
Expand Down
1 change: 0 additions & 1 deletion src/archive/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//! Extracts tar archives to disk. The format itself is `bun_tar`'s.
#![warn(unused_must_use)]

use bun_alloc::AllocError;
use bun_collections::StringArrayHashMap;
Expand Down
1 change: 1 addition & 0 deletions src/ast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "bun_ast"
version.workspace = true
edition.workspace = true
publish.workspace = true

[lib]
path = "lib.rs"
Expand Down
Loading
Loading