Skip to content

Make Rc<T>::deref zero-cost - #141348

Open
EFanZh wants to merge 2 commits into
rust-lang:mainfrom
EFanZh:zero-cost-rc-deref
Open

EFanZh wants to merge 2 commits into
rust-lang:mainfrom
EFanZh:zero-cost-rc-deref

Conversation

@EFanZh

@EFanZh EFanZh commented May 21, 2025 •

Copy link
Copy Markdown
Contributor

View all comments

This PR makes Rc::deref zero-cost by changing the internal pointer to point directly to the value instead of to the allocation.

This PR is split from #132553, which will also make Arc::deref zero-cost.

Review status:

  • 8d8878a Add RefCounts and RcLayout types
  • abe9c27 Add allocation functions
  • cfa6ea8 Add RefCounter trait
  • 77755f0 Add RawWeak type
  • 7fce1c4 Add RawWeak methods for sized values
  • adddf22 Add RawWeak methods for slice values
  • 99522fc Implement necessary traits for RawWeak
  • 393e377 Add RawRc type
  • 6cb537c Add RawRc methods for sized values
  • 6b47771 Add RawRc methods for MaybeUninit<T> values
  • 9184466 Add RawRc methods for slice values
  • 33881a5 Add RawRc methods for dyn Any type
  • 17e84c6 Implement necessary traits for RawRc
  • 20e0aba Add RawUniqueRc type
  • 82525d0 Add RawUniqueRc methods for sized values
  • 8bc9dea Implement necessary traits for RawUniqueRc
  • cee99e8 Implement alloc::rc::{Rc,Weak,UniqueRc} with alloc::raw_rc types
  • 2676c63 (HEAD -> zero-cost-rc-deref) Add LLVM codegen tests for new Rc implementation

@rustbot rustbot added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels May 21, 2025
@rust-log-analyzer

This comment has been minimized.

@EFanZh
EFanZh force-pushed the zero-cost-rc-deref branch from df34f84 to d3a7429 Compare May 24, 2025 05:01
@rust-log-analyzer

This comment has been minimized.

@EFanZh
EFanZh force-pushed the zero-cost-rc-deref branch 2 times, most recently from bc84ec6 to 19fb34b Compare May 24, 2025 09:00
@EFanZh
EFanZh marked this pull request as ready for review May 24, 2025 10:22
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 24, 2025
@rustbot

rustbot commented May 24, 2025

Copy link
Copy Markdown
Collaborator

The Miri subtree was changed

cc @rust-lang/miri

Comment thread library/alloc/src/raw_rc/mod.rs Outdated
@EFanZh
EFanZh force-pushed the zero-cost-rc-deref branch from 19fb34b to f5245ba Compare May 26, 2025 15:02
@oli-obk

This comment was marked as outdated.

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label May 26, 2025
@bors

This comment was marked as outdated.

bors added a commit that referenced this pull request May 26, 2025
Make `Rc<T>::deref` zero-cost

This PR makes `Rc::deref` zero-cost by changing the internal pointer so that it points to the value directly instead of the allocation.

This is split out from #132553, which will also make `Arc::deref` zero-cost.
@bors

This comment was marked as outdated.

@rust-timer

This comment has been minimized.

@rust-timer

This comment was marked as outdated.

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels May 26, 2025
@apiraino

This comment was marked as outdated.

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 31, 2025
@rustbot

This comment was marked as outdated.

Comment thread library/alloc/src/raw_rc/mod.rs Outdated
@EFanZh

EFanZh commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

I have done an initial refactoring, notable points:

  • Certain inner names are kept to reduce the diff size to make it easier to review at the cost of semantic mismatch.
  • RcLayout and specialization are kept as justified in Make Rc<T>::deref zero-cost #141348 (comment).
  • The change is provided as a single commit at the current stage because I would like to finalize the design before splitting based on the design.

I'll update the PR based on the future review feedback.

cc @clarfonthey, @joboet, @tgross35

@rustbot

This comment has been minimized.

Comment on lines 307 to 314
pub struct Rc<
T: ?Sized,
#[unstable(feature = "allocator_ext", issue = "163177", implied_by = "allocator_api")] A: Allocator = Global,
> {
ptr: NonNull<RcInner<T>>,
phantom: PhantomData<RcInner<T>>,
ptr: RcValuePointer<Header, T>,
phantom: PhantomData<T>,
alloc: A,
}

@tgross35 tgross35 Oct 6, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid needing to specify Header everywhere, could you put these types/aliases in common/mod.rs?

// common/mod.rs

#[repr(align(...))]
#[repr(C)]
pub(crate) struct Header<C> {
    pub(crate) weak: C,
    pub(crate) strong: C,
}

pub(crate) type RcHeader = Header<Cell<usize>>;
// pub(crate) type ArcHeader = Header<Atomic<usize>>;

View changes since the review

Comment on lines +30 to +31
/// A `Layout` that describes a reference-counted allocation containing a header of type `H`.
pub(in crate::rcs) struct RcLayout<H>(Layout, PhantomData<H>);

@tgross35 tgross35 Oct 6, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think we can eliminate RcLayout, it pretty much exists only for use within rc_alloc.rs. With the design at #141348 (comment), the free functions in rc_alloc are instead implemented on RefCounts (renamed to Header here / after https://github.com/rust-lang/rust/pull/141348/changes#r4190716209), which can use Self to get the layout. You'll still need the layout computation functions but they can just be free functions in rc_alloc that are mostly private, similar to what exists on main.

UniqueRc is the only snag but rc_layout is only used for deallocation. It should be fine if that one case calls A::deallocate on its own without using the bits in common.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike RcValuePointer, RcLayout is indeed used as a safety contract. For allocation, we usually calculate the allocation layout from the value layout; then we only need a type-erased function that allocates from the allocation layout:

fn allocate<H, A>(alloc: &A, layout: RcLayout<H>) -> ErasedRcValuePointer<H> { ... }

We choose to return a pointer to the value instead of the allocation because this is usually what the caller wants. The caller usually won't need the allocation pointer until deallocation. Here RcLayout<H> is guaranteed to support the header H, so we can safely perform pointer arithmetic to get a pointer to the value.

If we drop the RcLayout type, we have to either mark the function unsafe or return a pointer to the allocation and let the caller calculate the pointer to the value. The first approach will introduce a lot of unsafe code and corresponding justifications at each call site; the second approach can cause code duplication at call sites for pointer calculations; and both require the caller to keep track of what kind of layout they are passing.

I also considered passing a value layout instead of the allocation layout, but that does not work very well because the underlying allocator API requires allocation layouts, so we have to obtain an allocation layout at some point; so functions that take allocation layouts arise naturally. Also, decoupling layout calculations from memory operations makes the code more flexible; an example is the cached layout in UniqueRcUninit. Although I am not sure whether the cache here has a performance benefit, at least we have a choice when we do need it.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also considered passing a value layout instead of the allocation layout, but that does not work very well because the underlying allocator API requires allocation layouts, so we have to obtain an allocation layout at some point; so functions that take allocation layouts arise naturally.

This is the preferred solution: nothing in rc.rs/arc.rs should care about the actual allocated layout, that can all be internal to the common module. Currently RcLayout is pretty viral.

Taking the API from the linked comment (with some fixes):

impl<C> Header<C> {x
    // The `_type` functions can be `#[inline]` and implemented in terms of `*_layout`.
    pub(crate) fn allocate_for_type<T, A: Allocator>(alloc: A) -> RcValuePointer<T> {}
    pub(crate) fn allocate_for_layout<A: Allocator>(value_layout: Layout, alloc: A) -> ErasedRcValuePointer {}
    pub(crate) fn try_allocate_for_type<T, A: Allocator>(alloc: A) -> Result<RcValuePointer<T>, AllocError> {}
    pub(crate) fn try_allocate_for_layout<A: Allocator>(value_layout: Layout, alloc: A) -> Result<ErasedRcValuePointer, AllocError> {}
    // ...
    // I updated these here
    pub(crate) unsafe fn deallocate_for_type<T, A: Allocator>(ptr: RcValuePointer<T>, alloc: A) {}
    pub(crate) unsafe fn deallocate_for_layout<A: Allocator>(ptr: ErasedRcValuePointer, value_layout: Layout, alloc: A) {}
    // Maybe this can actually return `&Header` since `RcValuePointer` has a validity invariant?
    pub(crate) fn get(ptr: RcValuePointer) -> NonNull<Header<C>> {}
}

All the Layouts there are for T: only try_allocate_for_layout, deallocate_for_layout, and get actually need to know about the true allocated Layout and they can do it internally. The first two can call a shared fn allocated_layout(value_layout: Layout).

value_layout is the layout of the entire data other than the header, e.g. for [T] it should be the layout for [T; N] that actually needs to get allocated. This is the layout that UniqueRcUninit can store.

Comment on lines 4278 to 4282
struct UniqueRcUninit<T: ?Sized, A: Allocator> {
ptr: NonNull<RcInner<T>>,
layout_for_value: Layout,
alloc: Option<A>,
ptr: RcValuePointer<Header, T>,
rc_layout: RcLayout<Header>,
alloc: A,
}

@tgross35 tgross35 Oct 6, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does UniqueRcUninit hold a layout at all? It's only used in drop, and I think that can be recomputed from T same as we do on UniqueRc. Perhaps it's related to allowing shared drop to reduce code size, but it doesn't seem worth optimizing this struct in this way but not the rest of the Arc/Rc types.

If you are interested, I think you could submit a separate PR changing this to match what is done in UniqueRc, which may make things a bit more simple for this PR.

Cc @kpreid as the author of 88c3db5.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not necessary. I kept it to match the existing implementation. Changing it would have an unknown performance impact, so I prefer to leave it out of the scope of the current PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed you dropped the layout as part of this PR now—I don't think it will make all that much of a difference but your consideration about perf was reasonable. if you're interested, feel free to create a separate PR changing the existing implementation, which we can perf and merge separately.

@EFanZh EFanZh Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the cached layout because:

  • To my understanding, you prefer to not expose the allocation layout to Rc and Arc implementations.
  • Caching the value layout is not very useful because we have to compute the allocation layout again when dellocation happens.

So to my understanding, either we remove the cached layout, or we expose the allocation layout and cache this one instead.

I kept RcLayout because I found out that the "passing value layout" approach has another defect of not being able to compute the allocation layout at compile time. We could rely on compiler optimization, but it is not guaranteed. I also added a value_offset field to RcLayout because it is a by-product from computing allocation layout and is used whenever an RcLayout is used.

@rustbot

rustbot commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@tgross35 tgross35 Oct 7, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many of the functions in this module are now called a single time in common/mod.rs. Can you inline any like this? The few remaining functions that are called >1 time can also just move into common/mod.rs.

View changes since the review

@EFanZh EFanZh Oct 7, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked each function in rc_alloc, only allocate_from_bytes and try_allocate_with are called a single time. allocate_from_bytes is introduced to erase the concrete value types, try_allocate_with is introduced to exist as a fallible counterpart of allocate_with.

Comment on lines +21 to +29
let allocation_result = alloc.allocate(rc_layout.layout());

allocation_result.map(|allocation_ptr| {
// SAFETY: `allocation_ptr` is allocated with `rc_layout`, so we can safely acquire an
// pointer to the value.
ErasedRcValuePointer::new(unsafe {
allocation_ptr.cast().byte_add(rc_layout.value_offset())
})
})

@tgross35 tgross35 Oct 7, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let allocation_result = alloc.allocate(rc_layout.layout());
allocation_result.map(|allocation_ptr| {
// SAFETY: `allocation_ptr` is allocated with `rc_layout`, so we can safely acquire an
// pointer to the value.
ErasedRcValuePointer::new(unsafe {
allocation_ptr.cast().byte_add(rc_layout.value_offset())
})
})
let ptr = alloc.allocate(rc_layout.layout())?;
// SAFETY: `allocation_ptr` is allocated with `rc_layout`, so we can safely acquire an
// pointer to the value.
ErasedRcValuePointer::new(unsafe {
ptr.cast().byte_add(rc_layout.value_offset())
})

? avoids some messier map calls. Applies a handful of places.

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@tgross35

tgross35 commented Oct 7, 2026

Copy link
Copy Markdown
Member

I'll have more feedback but let's see where this is on perf

@bors try
@rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

@rust-bors

rust-bors Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 2e6b3c1 (2e6b3c19247c4ef0d2338a39f5a893e3380ff26b)
Base parent: 8d1a764 (8d1a76430406c877b35d0b627e7f796dcf0dfeca)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (2e6b3c1): comparison URL.

Overall result: ❌✅ regressions and improvements - please read:

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

Next, please: If you can, justify the regressions found in this try perf run in writing along with @rustbot label: +perf-regression-triaged. If not, fix the regressions and do another perf run. Neutral or positive results will clear the label automatically.

@bors rollup=never rustc-perf
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.1% [0.1%, 0.2%] 8
Regressions ❌
(secondary)
4.3% [0.1%, 10.9%] 12
Improvements ✅
(primary)
-0.4% [-0.8%, -0.1%] 3
Improvements ✅
(secondary)
-0.1% [-0.1%, -0.1%] 1
All ❌✅ (primary) -0.0% [-0.8%, 0.2%] 11

Max RSS (memory usage)

Results (primary -0.2%, secondary 3.6%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
3.0% [3.0%, 3.0%] 1
Regressions ❌
(secondary)
3.6% [3.6%, 3.7%] 2
Improvements ✅
(primary)
-1.8% [-2.2%, -1.5%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.2% [-2.2%, 3.0%] 3

Cycles

Results (primary -0.0%, secondary 5.8%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.0% [2.0%, 2.0%] 1
Regressions ❌
(secondary)
5.8% [2.0%, 11.2%] 9
Improvements ✅
(primary)
-2.0% [-2.0%, -2.0%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.0% [-2.0%, 2.0%] 2

Binary size

Results (primary -0.1%, secondary 7.7%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.1% [0.1%, 0.2%] 9
Regressions ❌
(secondary)
7.7% [0.1%, 12.3%] 9
Improvements ✅
(primary)
-0.3% [-0.9%, -0.1%] 9
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) -0.1% [-0.9%, 0.2%] 18

Bootstrap: 489.893s -> 489.388s (-0.10%)
Artifact size: 408.60 MiB -> 408.61 MiB (0.00%)

@rust-log-analyzer

This comment has been minimized.

@EFanZh

EFanZh commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

@tgross35: I added some #[inline] attributes based on the previous perf result, can I have another run to check the effects?

@tgross35

tgross35 commented Oct 7, 2026

Copy link
Copy Markdown
Member

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rust-bors

This comment has been minimized.

@rust-bors

rust-bors Bot commented Oct 7, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: baeaed6 (baeaed6b4b0829a8f731b6d2a31277126d397d36)
Base parent: 8d1a764 (8d1a76430406c877b35d0b627e7f796dcf0dfeca)

@rust-timer

This comment has been minimized.

@rust-timer

Copy link
Copy Markdown
Collaborator

Finished benchmarking commit (baeaed6): comparison URL.

Overall result: ❌✅ regressions and improvements - please read:

Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf.

Next, please: If you can, justify the regressions found in this try perf run in writing along with @rustbot label: +perf-regression-triaged. If not, fix the regressions and do another perf run. Neutral or positive results will clear the label automatically.

@bors rollup=never rustc-perf
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

Our most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.

mean range count
Regressions ❌
(primary)
0.2% [0.1%, 0.2%] 9
Regressions ❌
(secondary)
3.7% [0.1%, 11.7%] 12
Improvements ✅
(primary)
-0.4% [-0.8%, -0.1%] 5
Improvements ✅
(secondary)
-0.3% [-0.5%, -0.1%] 3
All ❌✅ (primary) -0.1% [-0.8%, 0.2%] 14

Max RSS (memory usage)

Results (primary 1.0%, secondary 2.3%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
2.6% [2.5%, 2.8%] 2
Regressions ❌
(secondary)
3.9% [2.1%, 9.3%] 6
Improvements ✅
(primary)
-2.4% [-2.4%, -2.4%] 1
Improvements ✅
(secondary)
-2.7% [-2.9%, -2.4%] 2
All ❌✅ (primary) 1.0% [-2.4%, 2.8%] 3

Cycles

Results (secondary 5.9%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
- - 0
Regressions ❌
(secondary)
6.5% [0.7%, 16.4%] 14
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
-2.0% [-2.0%, -2.0%] 1
All ❌✅ (primary) - - 0

Binary size

Results (primary -0.1%, secondary 6.6%)

A less reliable metric. May be of interest, but not used to determine the overall result above.

mean range count
Regressions ❌
(primary)
0.2% [0.1%, 0.2%] 13
Regressions ❌
(secondary)
8.1% [0.1%, 12.9%] 6
Improvements ✅
(primary)
-0.4% [-1.6%, -0.1%] 9
Improvements ✅
(secondary)
-2.4% [-2.4%, -2.4%] 1
All ❌✅ (primary) -0.1% [-1.6%, 0.2%] 22

Bootstrap: 489.893s -> 488.069s (-0.37%)
Artifact size: 408.60 MiB -> 409.41 MiB (0.20%)

@tgross35

Copy link
Copy Markdown
Member

Hopefully rust-lang/rustc-perf#2615 will give some better hints about exactly where things are slowing down.

@tgross35 tgross35 left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you can run perf yourself and experiment,

@bors delegate=try

I know the patterns in the current code have been optimized about as much as possible, any kind of perturbation may easily have negative effects on performance. The best thing to do is probably to slowly walk back changes to make the code's shape look more like what's currently there. If that means moving more out of common.rs and back into rc.rs then that's fine, more refactoring can happen after the two big PRs merge.

View changes since this review

Comment on lines 488 to 490
pub fn new_uninit() -> Rc<mem::MaybeUninit<T>> {
// ignore-tidy-undocumented-unsafe
unsafe {
Rc::from_ptr(Rc::allocate_for_layout(
Layout::new::<T>(),
|layout| Global.allocate(layout),
<*mut u8>::cast,
))
}
Self::new_uninit_in(Global)
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you try adding this pattern back with allocate_for_layout and try_allocate_for_layout? With API in common:

fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout;

impl RcHeader {
    unsafe fn allocate_for_layout(
        value_layout: Layout,
        allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
        mem_to_rc_inner: impl FnOnce(ErasedRcValuePointer) -> RcValuePointer<T>,
    ) -> RcValuePointer<T>;
}

I think we may be spending more time/complexity doing layout calculation and allocation while the existing pattern works quite well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I inspected the generated assembly locally, I think the majority difference is caused by different inlining strategy and extra pointer offset operations. Most of the test cases use sized types, I ensured the layouts are computed at compile time, so the layout calculation are not likely the main cause.

I am now trying different optimization strategies to see if they improve the perf result.

@rust-bors

rust-bors Bot commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

✌️ @EFanZh, you can now perform try builds on this pull request!

Warning

You used the legacy format of the delegate command.
The new format is @bors delegate[=<username>] [<try|review>].

You can now post @bors try to start a try build.

@EFanZh

EFanZh commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

@bors try @rust-timer queue

@rust-timer

Copy link
Copy Markdown
Collaborator

Insufficient permissions to issue commands to rust-timer.

@rust-bors

This comment has been minimized.

@rust-bors

rust-bors Bot commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: 6692763 (6692763b8b363b590d95624cbb6273d067eb73b2)
Base parent: 0617e57 (0617e57afe33d3afb1d5d5489030cae802f6c17e)

@rust-bors

rust-bors Bot commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

☔ The latest upstream changes (presumably #164230) made this pull request unmergeable. Please resolve the merge conflicts by rebasing.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

perf-regression Performance regression. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.