Skip to content
Closed
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ env:
# Pin the toolchain explicitly so rustup ignores rust-toolchain.toml's
# `targets` list (11 cross triples ≈ 450 MB of prebuilt std we don't need
# to lint the host). Keep in sync with `channel` in rust-toolchain.toml.
RUSTUP_TOOLCHAIN: nightly-2026-05-06
RUSTUP_TOOLCHAIN: nightly-2026-07-20

jobs:
clippy:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
# Pin the toolchain explicitly so rustup ignores rust-toolchain.toml's
# `targets` list (11 cross triples ≈ 450 MB of prebuilt std we don't
# need just to run rustfmt). Keep this in sync with `channel` there.
RUSTUP_TOOLCHAIN: nightly-2026-05-06
RUSTUP_TOOLCHAIN: nightly-2026-07-20
run: |
# Without pipefail, `cmd | sed` always reports sed's exit status, so a
# failing formatter is invisible to the `wait $PID` checks below.
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/miri.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ env:
LLVM_VERSION_MAJOR: "21"
# Pin so rustup ignores rust-toolchain.toml's `targets` list (11 cross
# triples ≈ 450 MB we don't need). Keep in sync with `channel` there.
RUSTUP_TOOLCHAIN: nightly-2026-05-06
RUSTUP_TOOLCHAIN: nightly-2026-07-20

jobs:
miri:
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[toolchain]
channel = "nightly-2026-05-06"
channel = "nightly-2026-07-20"
# rust-src is needed for -Zbuild-std (Tier 3 targets like
# aarch64-unknown-freebsd have no prebuilt std). miri is for
# `bun run rust:miri`. targets ensures the
Expand Down
4 changes: 3 additions & 1 deletion scripts/build/rust.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,8 +297,10 @@ export function registerRustRules(n: Ninja, cfg: Config): void {

const rustup = findRustup(cfg);
if (rustup !== undefined && cfg.rustToolchain !== undefined) {
// `-q` + `--no-self-update` silence the five `info:` lines rustup prints
// on every no-op reinstall; warnings/errors still show.
const chain =
`${stream} --console $env ${q(rustup)} toolchain install ${cfg.rustToolchain} --force --component rust-src $rust_target_arg && ` +
`${stream} --console $env ${q(rustup)} -q toolchain install ${cfg.rustToolchain} --force --no-self-update --component rust-src $rust_target_arg && ` +
`${stream} --console --cwd=$cwd $env ${q(cfg.cargo)} build $args`;
n.rule("rust_build_cross", {
command: hostWin ? `cmd /c "${chain}"` : chain,
Expand Down
4 changes: 2 additions & 2 deletions scripts/build/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -601,8 +601,8 @@ export function registerDepRules(n: Ninja, cfg: Config): void {
const rustup = q(join(dirname(cfg.cargo), `rustup${cfg.host.exeSuffix}`));
const cargoCrossEnsure =
cfg.rustToolchain !== undefined
? `${stream} $env ${rustup} toolchain install ${cfg.rustToolchain} --force --component rust-src --target $rust_target`
: `${stream} $env ${rustup} target add $rust_target`;
? `${stream} $env ${rustup} -q toolchain install ${cfg.rustToolchain} --force --no-self-update --component rust-src --target $rust_target`
: `${stream} $env ${rustup} -q target add $rust_target`;
// Windows: ninja runs commands via CreateProcess (no shell) — wrap in
// `cmd /c "..."` so `&&` is interpreted as a chain operator instead of
// being passed as a literal arg. See rust.ts `rust_build_cross`.
Expand Down
25 changes: 20 additions & 5 deletions scripts/build/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -664,11 +664,26 @@ export function findRustLld(os: OS): {
const rustup = findTool({ names: ["rustup"], paths: [join(cargoHome, "bin")], required: false })?.path;
const channel = readRustToolchainChannel();
if (rustup !== undefined && channel !== undefined) {
spawnSync(rustup, ["toolchain", "install", channel, "--force", "--profile", "minimal", "--component", "rust-src"], {
encoding: "utf8",
timeout: 300_000,
stdio: ["ignore", "ignore", "inherit"], // surface download/error output
});
spawnSync(
rustup,
[
"-q",
"toolchain",
"install",
channel,
"--force",
"--no-self-update",
"--profile",
"minimal",
"--component",
"rust-src",
],
{
encoding: "utf8",
timeout: 300_000,
stdio: ["ignore", "ignore", "inherit"], // surface download/error output; `-q` hides `info:` noise
},
);
}

// One spawn for both sysroot and host triple / LLVM version. `-vV` prints
Expand Down
2 changes: 1 addition & 1 deletion src/ast/char_freq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ fn scan_big(out: &mut Buffer, text: &[u8], delta: i32) {
let unrolled = text.len() - (text.len() % SCAN_BIG_CHUNK_SIZE);
let (chunks, remain) = text.split_at(unrolled);

for chunk in chunks.chunks_exact(SCAN_BIG_CHUNK_SIZE) {
for chunk in chunks.as_chunks::<SCAN_BIG_CHUNK_SIZE>().0 {
// PERF: candidate for unrolling — profile
for i in 0..SCAN_BIG_CHUNK_SIZE {
deltas[chunk[i] as usize] += delta;
Expand Down
4 changes: 2 additions & 2 deletions src/boringssl/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,8 @@ impl core::fmt::Display for AltNameIp<'_> {
match self.0 {
[a, b, c, d] => write!(f, "{a}.{b}.{c}.{d}"),
octets if octets.len() == 16 => {
for (i, pair) in octets.chunks_exact(2).enumerate() {
let group = u16::from_be_bytes([pair[0], pair[1]]);
for (i, pair) in octets.as_chunks::<2>().0.iter().enumerate() {
let group = u16::from_be_bytes(*pair);
if i > 0 {
f.write_str(":")?;
}
Expand Down
12 changes: 5 additions & 7 deletions src/bun_alloc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3375,12 +3375,10 @@ impl<
) -> core::result::Result<(), AllocError> {
let _guard = self.map().mutex.lock();

let slice: &'static [u8];

// Is this actually a slice into the map? Don't free it.
if self.is_key_statically_allocated(key) {
let slice: &'static [u8] = if self.is_key_statically_allocated(key) {
// SAFETY: key points into self.key_list_buffer which lives for the singleton's life.
slice = unsafe { core::slice::from_raw_parts(key.as_ptr(), key.len()) };
unsafe { core::slice::from_raw_parts(key.as_ptr(), key.len()) }
} else if self.key_list_buffer_used + key.len() < self.key_list_buffer.len() {
let start = self.key_list_buffer_used;
self.key_list_buffer_used += key.len();
Expand All @@ -3396,7 +3394,7 @@ impl<
};
dst.copy_from_slice(key);
// SAFETY: points into self.key_list_buffer (singleton-static lifetime).
slice = unsafe { core::slice::from_raw_parts(dst.as_ptr(), dst.len()) };
unsafe { core::slice::from_raw_parts(dst.as_ptr(), dst.len()) }
} else {
// Propagate OOM. Route
// through mimalloc directly (PORTING.md forbids `Box::leak`) so the
Expand All @@ -3410,8 +3408,8 @@ impl<
unsafe { core::ptr::copy_nonoverlapping(key.as_ptr(), ptr, key.len()) };
// SAFETY: allocation is owned by this singleton for process lifetime (or until
// freed below on overwrite).
slice = unsafe { core::slice::from_raw_parts(ptr, key.len()) };
}
unsafe { core::slice::from_raw_parts(ptr, key.len()) }
};

let slice = if REMOVE_TRAILING_SLASHES {
trim_right(slice, b"/")
Expand Down
2 changes: 2 additions & 0 deletions src/bun_core/Global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,8 @@ pub(crate) fn is_exiting() -> bool {
// args and are `noreturn`/kernel-validated — no memory-safety preconditions,
// so `safe fn` discharges the link-time proof and the call sites are plain
// calls. `#[link_name]` avoids colliding with this module's own `pub fn exit`.
// The lint fires on the `safe` annotation only; the ABI matches std's.
#[allow(suspicious_runtime_symbol_definitions)]
unsafe extern "C" {
#[link_name = "abort"]
safe fn libc_abort() -> !;
Expand Down
8 changes: 5 additions & 3 deletions src/bun_core/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1846,15 +1846,17 @@ pub(crate) mod strings_impl {

const HIGH_BITS: u64 = 0x8080_8080_8080_8080;
let mut copied = 0usize;
for (d, s) in dst.chunks_exact_mut(8).zip(src.chunks_exact(8)) {
let word = u64::from_ne_bytes(s.try_into().expect("infallible: size matches"));
let (dst_chunks, _) = dst.as_chunks_mut::<8>();
let (src_chunks, _) = src.as_chunks::<8>();
for (d, s) in dst_chunks.iter_mut().zip(src_chunks) {
let word = u64::from_ne_bytes(*s);
let mask = word & HIGH_BITS;
if mask != 0 {
let ascii = (mask.trailing_zeros() / 8) as usize;
d[..ascii].copy_from_slice(&s[..ascii]);
return copied + ascii;
}
d.copy_from_slice(&word.to_ne_bytes());
*d = word.to_ne_bytes();
copied += 8;
}
for (d, &s) in dst[copied..].iter_mut().zip(&src[copied..]) {
Expand Down
9 changes: 4 additions & 5 deletions src/collections/bit_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,14 @@ fn set_range_value_masks(masks: &mut [usize], range: Range, value: bool) {
mask2 = bool_mask_usize(value) >> ((MASK_LEN - 1) - (end_bit - 1));
masks[start_mask_index] |= mask1 & mask2;
} else {
let bulk_mask_index: usize;
if start_bit > 0 {
let bulk_mask_index: usize = if start_bit > 0 {
masks[start_mask_index] = (masks[start_mask_index]
& !(bool_mask_usize(true) << start_bit))
| (bool_mask_usize(value) << start_bit);
bulk_mask_index = start_mask_index + 1;
start_mask_index + 1
} else {
bulk_mask_index = start_mask_index;
}
start_mask_index
};

for mask in &mut masks[bulk_mask_index..end_mask_index] {
*mask = bool_mask_usize(value);
Expand Down
6 changes: 3 additions & 3 deletions src/collections/multi_array_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ use crate::const_str_eq;
/// callers routinely use lifetime-carrying field types (`&'a [u8]`, `Ref<'a>`).
#[inline(always)]
const fn type_id_of<F: ?Sized>() -> TypeId {
core::intrinsics::type_id::<F>()
const { core::intrinsics::type_id::<F>() }
}

/// Reflected fields of `T` (struct only). Panics at const-eval for non-structs.
Expand Down Expand Up @@ -295,7 +295,7 @@ const fn align_sort_key(size: usize, struct_align: usize) -> usize {
return 1;
}
// Largest power of two dividing `size`.
let pow2 = size & size.wrapping_neg();
let pow2 = size.isolate_lowest_one();
if pow2 < struct_align {
pow2
} else {
Expand Down Expand Up @@ -344,7 +344,7 @@ impl<T> Reflected<T> {
let mut i = 0;
while i < n {
let f = &fields[i];
let size = match f.ty.info().size {
let size = match f.ty.size() {
Some(s) => s,
None => panic!("MultiArrayList: field type must be Sized"),
};
Expand Down
2 changes: 1 addition & 1 deletion src/css/values/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ bitflags::bitflags! {

impl ColorFallbackKind {
pub fn lowest(self) -> ColorFallbackKind {
ColorFallbackKind::from_bits_truncate(self.bits() & self.bits().wrapping_neg())
ColorFallbackKind::from_bits_truncate(self.bits().isolate_lowest_one())
}

pub fn highest(self) -> ColorFallbackKind {
Expand Down
4 changes: 3 additions & 1 deletion src/http_jsc/websocket_client/WebSocketUpgradeClient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1843,7 +1843,9 @@ impl<'a> Headers8Bit<'a> {

fn iter(&self) -> impl Iterator<Item = (&[u8], &[u8])> + '_ {
self.slices
.chunks_exact(2)
.as_chunks::<2>()
.0
.iter()
.map(|pair| (pair[0].slice(), pair[1].slice()))
}

Expand Down
10 changes: 5 additions & 5 deletions src/install/PackageManager/CommandLineArguments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1320,8 +1320,8 @@ Full documentation is available at <magenta>https://bun.com/docs/cli/pm#scan<r>.
if let Some(cwd_) = args.option(b"--cwd") {
let mut buf = PathBuffer::uninit();
let mut buf2 = PathBuffer::uninit();
let final_path: &mut bun_core::ZStr;
if !cwd_.is_empty() && cwd_[0] == b'.' {

let final_path: &mut bun_core::ZStr = if !cwd_.is_empty() && cwd_[0] == b'.' {
let cwd_len = bun_sys::getcwd(&mut buf[..])?;
let cwd = &buf[..cwd_len];
let parts: [&[u8]; 1] = [cwd_];
Expand All @@ -1332,12 +1332,12 @@ Full documentation is available at <magenta>https://bun.com/docs/cli/pm#scan<r>.
)
.len();
buf2[len] = 0;
final_path = bun_core::ZStr::from_buf_mut(&mut buf2[..], len);
bun_core::ZStr::from_buf_mut(&mut buf2[..], len)
} else {
buf[..cwd_.len()].copy_from_slice(cwd_);
buf[cwd_.len()] = 0;
final_path = bun_core::ZStr::from_buf_mut(&mut buf[..], cwd_.len());
}
bun_core::ZStr::from_buf_mut(&mut buf[..], cwd_.len())
};
if let Err(err) = bun_sys::chdir(final_path) {
Output::err_generic(
"failed to change directory to \"{}\": {}\n",
Expand Down
14 changes: 7 additions & 7 deletions src/install/resolvers/folder_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ fn normalize_package_json_path<'a>(
non_normalized_path: &[u8],
) -> Paths<'a> {
let abs: &[u8];
let rel: &[u8];

// We consider it valid if there is a package.json in the folder
let normalized: &[u8] = if non_normalized_path.len() == 1 && non_normalized_path[0] == b'.' {
non_normalized_path
Expand All @@ -198,7 +198,7 @@ fn normalize_package_json_path<'a>(

const PACKAGE_JSON_LEN: usize = "/package.json".len();

if strings::starts_with_char(normalized, b'.') {
let rel: &[u8] = if strings::starts_with_char(normalized, b'.') {
let mut tempcat = PathBuffer::uninit();

tempcat[..normalized.len()].copy_from_slice(normalized);
Expand All @@ -210,10 +210,10 @@ fn normalize_package_json_path<'a>(
&tempcat[0..normalized.len() + PACKAGE_JSON_LEN],
];
abs = FileSystem::instance().abs_buf(&parts, joined);
rel = FileSystem::instance().relative(
FileSystem::instance().relative(
FileSystem::instance().top_level_dir(),
&abs[0..abs.len() - PACKAGE_JSON_LEN],
);
)
} else {
let joined_len = joined.len();
let mut remain: &mut [u8] = &mut joined[..];
Expand Down Expand Up @@ -246,11 +246,11 @@ fn normalize_package_json_path<'a>(
let abs_len = joined_len - remain_after;
abs = &joined[0..abs_len];
// We store the folder name without package.json
rel = FileSystem::instance().relative(
FileSystem::instance().relative(
FileSystem::instance().top_level_dir(),
&abs[0..abs.len() - PACKAGE_JSON_LEN],
);
}
)
};
let abs_len = abs.len();
joined[abs_len] = 0;

Expand Down
11 changes: 4 additions & 7 deletions src/js_parser/parse/parse_typescript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,25 +632,22 @@ impl<'a, const TYPESCRIPT: bool, const SCAN_ONLY: bool> P<'a, TYPESCRIPT, SCAN_O
name: js_ast::StoreStr::new(b"" as &[u8]),
value: None,
};
// Assigned in both live arms below; the third arm returns.
let needs_symbol: bool;

// Parse the name
if p.lexer.token == T::TStringLiteral {
let needs_symbol: bool = if p.lexer.token == T::TStringLiteral {
// `slice8()` is currently duplicated in E.rs (two impl blocks);
// read `.data` directly — `to_utf8_e_string` guarantees `is_utf16 == false`.
let estr = p.lexer.to_utf8_e_string()?;
debug_assert!(!estr.is_utf16);
value.name = estr.data;
needs_symbol = js_lexer::is_identifier(value.name.slice());
js_lexer::is_identifier(value.name.slice())
} else if p.lexer.is_identifier_or_keyword() {
value.name = js_ast::StoreStr::new(p.lexer.identifier);
needs_symbol = true;
true
} else {
p.lexer.expect(T::TIdentifier)?;
// error early, name is still `undefined`
return Err(crate::Error::SyntaxError);
}
};
p.lexer.next()?;

// Identifiers can be referenced by other values
Expand Down
9 changes: 4 additions & 5 deletions src/js_printer/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7923,14 +7923,13 @@ pub fn print_ast<'a, W: WriterTrait, const ASCII_ONLY: bool, const GENERATE_SOUR
// hoisted out of the `minify_identifiers` arm so the
// `&'r mut MinifyRenamer` borrow stored in `renamer` outlives the branch.
let mut minify_renamer;
let renamer: rename::Renamer<'_, '_>;
// `Scope` isn't `Copy` here and the only
// consumer (`compute_reserved_names_for_scope`) walks `members`/`generated`/
// `children` — never `parent` — so we re-point at the in-place
// `tree.module_scope` instead (lives for `'a`).
let module_scope = &tree.module_scope;
let stable_source_indices = [source.index.0];
if opts.minify_identifiers {
let renamer: rename::Renamer<'_, '_> = if opts.minify_identifiers {
let mut reserved_names = rename::compute_initial_reserved_names(opts.module_type)?;
for child in module_scope.children.slice() {
// `StoreRef<Scope>` has safe `DerefMut`; copy the handle to a mut
Expand Down Expand Up @@ -8008,11 +8007,11 @@ pub fn print_ast<'a, W: WriterTrait, const ASCII_ONLY: bool, const GENERATE_SOUR
let minifier = tree.char_freq.as_ref().unwrap().compile();
minify_renamer.assign_names_by_frequency(&minifier)?;

renamer = rename::Renamer::MinifyRenamer(&mut *minify_renamer);
rename::Renamer::MinifyRenamer(&mut *minify_renamer)
} else {
no_op_renamer = rename::NoOpRenamer::init(symbols, source);
renamer = no_op_renamer.to_renamer();
}
no_op_renamer.to_renamer()
};

// defer: if minify_identifiers { renamer.deinit() } — Drop handles.

Expand Down
12 changes: 6 additions & 6 deletions src/react_compiler/ssa/enter_ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,12 +240,12 @@ impl SSABuilder {
}

fn fix_incomplete_phis(&mut self, block_id: BlockId, env: &mut Environment) {
let incomplete_phis: Vec<IncompletePhi> = self.states[block_id.0 as usize]
.as_mut()
.unwrap()
.incomplete_phis
.drain(..)
.collect();
let incomplete_phis: Vec<IncompletePhi> = core::mem::take(
&mut self.states[block_id.0 as usize]
.as_mut()
.unwrap()
.incomplete_phis,
);
for phi in &incomplete_phis {
self.add_phi(block_id, &phi.old_place, &phi.new_place, env);
}
Expand Down
Loading
Loading