| Age | Commit message (Collapse) | Author | Lines |
|
Optimize `Box::default` and `Arc::default` to construct more types in place
Both the `Arc` and `Box` `Default` impls currently call `T::default()` before allocating, and then moving the resulting `T` into the allocation.
Most `Default` impls are trivial, which should in theory allow
LLVM to construct `T: Default` directly in the `Box` allocation when calling
`<Box<T>>::default()`.
However, the allocation may fail, which necessitates calling `T`'s destructor if it has one.
If the destructor is non-trivial, then LLVM has a hard time proving that it's
sound to elide, which makes it construct `T` on the stack first, and then copy it into the allocation.
Change both of these impls to allocate first, and then call `T::default` into the uninitialized allocation, so that LLVM doesn't have to prove that it's sound to elide the destructor/initial stack copy.
For example, given the following Rust code:
```rust
#[derive(Default, Clone)]
struct Foo {
x: Vec<u8>,
z: String,
y: Vec<u8>,
}
#[no_mangle]
pub fn src() -> Box<Foo> {
Box::default()
}
```
<details open>
<summary>Before this PR:</summary>
```llvm
`@__rust_no_alloc_shim_is_unstable` = external global i8
; drop_in_place() generated in case the allocation fails
; core::ptr::drop_in_place<playground::Foo>
; Function Attrs: nounwind nonlazybind uwtable
define internal fastcc void `@"_ZN4core3ptr36drop_in_place$LT$playground..Foo$GT$17hff376aece491233bE"(ptr` noalias nocapture noundef readonly align 8 dereferenceable(72) %_1) unnamed_addr #0 personality ptr `@rust_eh_personality` {
start:
%_1.val = load i64, ptr %_1, align 8
%0 = icmp eq i64 %_1.val, 0
br i1 %0, label %bb6, label %"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i"
"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i": ; preds = %start
%1 = getelementptr inbounds i8, ptr %_1, i64 8
%_1.val6 = load ptr, ptr %1, align 8, !nonnull !3, !noundef !3
tail call void `@__rust_dealloc(ptr` noundef nonnull %_1.val6, i64 noundef %_1.val, i64 noundef 1) #8
br label %bb6
bb6: ; preds = %"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i", %start
%2 = getelementptr inbounds i8, ptr %_1, i64 24
%.val9 = load i64, ptr %2, align 8
%3 = icmp eq i64 %.val9, 0
br i1 %3, label %bb5, label %"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i.i11"
"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i.i11": ; preds = %bb6
%4 = getelementptr inbounds i8, ptr %_1, i64 32
%.val10 = load ptr, ptr %4, align 8, !nonnull !3, !noundef !3
tail call void `@__rust_dealloc(ptr` noundef nonnull %.val10, i64 noundef %.val9, i64 noundef 1) #8
br label %bb5
bb5: ; preds = %"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i.i11", %bb6
%5 = getelementptr inbounds i8, ptr %_1, i64 48
%.val4 = load i64, ptr %5, align 8
%6 = icmp eq i64 %.val4, 0
br i1 %6, label %"_ZN4core3ptr46drop_in_place$LT$alloc..vec..Vec$LT$u8$GT$$GT$17hb5ca95423e113cf7E.exit16", label %"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i15"
"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i15": ; preds = %bb5
%7 = getelementptr inbounds i8, ptr %_1, i64 56
%.val5 = load ptr, ptr %7, align 8, !nonnull !3, !noundef !3
tail call void `@__rust_dealloc(ptr` noundef nonnull %.val5, i64 noundef %.val4, i64 noundef 1) #8
br label %"_ZN4core3ptr46drop_in_place$LT$alloc..vec..Vec$LT$u8$GT$$GT$17hb5ca95423e113cf7E.exit16"
"_ZN4core3ptr46drop_in_place$LT$alloc..vec..Vec$LT$u8$GT$$GT$17hb5ca95423e113cf7E.exit16": ; preds = %bb5, %"_ZN63_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$10deallocate17heaa87468709346b1E.exit.i.i.i4.i15"
ret void
}
; Function Attrs: nonlazybind uwtable
define noalias noundef nonnull align 8 ptr `@src()` unnamed_addr #1 personality ptr `@rust_eh_personality` {
start:
; alloca to place `Foo` in.
%_1 = alloca [72 x i8], align 8
call void `@llvm.lifetime.start.p0(i64` 72, ptr nonnull %_1)
store i64 0, ptr %_1, align 8
%_2.sroa.4.0._1.sroa_idx = getelementptr inbounds i8, ptr %_1, i64 8
store ptr inttoptr (i64 1 to ptr), ptr %_2.sroa.4.0._1.sroa_idx, align 8
%_2.sroa.5.0._1.sroa_idx = getelementptr inbounds i8, ptr %_1, i64 16
%_3.sroa.4.0..sroa_idx = getelementptr inbounds i8, ptr %_1, i64 32
call void `@llvm.memset.p0.i64(ptr` noundef nonnull align 8 dereferenceable(16) %_2.sroa.5.0._1.sroa_idx, i8 0, i64 16, i1 false)
store ptr inttoptr (i64 1 to ptr), ptr %_3.sroa.4.0..sroa_idx, align 8
%_3.sroa.5.0..sroa_idx = getelementptr inbounds i8, ptr %_1, i64 40
%_4.sroa.4.0..sroa_idx = getelementptr inbounds i8, ptr %_1, i64 56
call void `@llvm.memset.p0.i64(ptr` noundef nonnull align 8 dereferenceable(16) %_3.sroa.5.0..sroa_idx, i8 0, i64 16, i1 false)
store ptr inttoptr (i64 1 to ptr), ptr %_4.sroa.4.0..sroa_idx, align 8
%_4.sroa.5.0..sroa_idx = getelementptr inbounds i8, ptr %_1, i64 64
store i64 0, ptr %_4.sroa.5.0..sroa_idx, align 8
%0 = load volatile i8, ptr `@__rust_no_alloc_shim_is_unstable,` align 1, !noalias !4
%_0.i.i.i = tail call noalias noundef align 8 dereferenceable_or_null(72) ptr `@__rust_alloc(i64` noundef 72, i64 noundef 8) #8, !noalias !4
%1 = icmp eq ptr %_0.i.i.i, null
br i1 %1, label %bb2.i, label %"_ZN5alloc5boxed12Box$LT$T$GT$3new17h0864de14f863a27aE.exit"
bb2.i: ; preds = %start
; invoke alloc::alloc::handle_alloc_error
invoke void `@_ZN5alloc5alloc18handle_alloc_error17h98142d0d8d74161bE(i64` noundef 8, i64 noundef 72) #9
to label %.noexc unwind label %cleanup.i
.noexc: ; preds = %bb2.i
unreachable
cleanup.i: ; preds = %bb2.i
%2 = landingpad { ptr, i32 }
cleanup
; call core::ptr::drop_in_place<playground::Foo>
call fastcc void `@"_ZN4core3ptr36drop_in_place$LT$playground..Foo$GT$17hff376aece491233bE"(ptr` noalias noundef nonnull align 8 dereferenceable(72) %_1) #10
resume { ptr, i32 } %2
"_ZN5alloc5boxed12Box$LT$T$GT$3new17h0864de14f863a27aE.exit": ; preds = %start
; Copy from stack to heap if allocation is successful
call void `@llvm.memcpy.p0.p0.i64(ptr` noundef nonnull align 8 dereferenceable(72) %_0.i.i.i, ptr noundef nonnull align 8 dereferenceable(72) %_1, i64 72, i1 false)
call void `@llvm.lifetime.end.p0(i64` 72, ptr nonnull %_1)
ret ptr %_0.i.i.i
}
```
</details>
<details>
<summary>After this PR</summary>
```llvm
; Notice how there's no `drop_in_place()` generated as well
define noalias noundef nonnull align 8 ptr `@src()` unnamed_addr #0 personality ptr `@rust_eh_personality` {
start:
; no stack allocation
%0 = load volatile i8, ptr `@__rust_no_alloc_shim_is_unstable,` align 1
%_0.i.i.i.i.i = tail call noalias noundef align 8 dereferenceable_or_null(72) ptr `@__rust_alloc(i64` noundef 72, i64 noundef 8) #5
%1 = icmp eq ptr %_0.i.i.i.i.i, null
br i1 %1, label %bb3.i, label %"_ZN5alloc5boxed16Box$LT$T$C$A$GT$13new_uninit_in17h80d6355ef4b73ea3E.exit"
bb3.i: ; preds = %start
; call alloc::alloc::handle_alloc_error
tail call void `@_ZN5alloc5alloc18handle_alloc_error17h98142d0d8d74161bE(i64` noundef 8, i64 noundef 72) #6
unreachable
"_ZN5alloc5boxed16Box$LT$T$C$A$GT$13new_uninit_in17h80d6355ef4b73ea3E.exit": ; preds = %start
; construct `Foo` directly into the allocation if successful
store i64 0, ptr %_0.i.i.i.i.i, align 8
%_8.sroa.4.0._1.sroa_idx = getelementptr inbounds i8, ptr %_0.i.i.i.i.i, i64 8
store ptr inttoptr (i64 1 to ptr), ptr %_8.sroa.4.0._1.sroa_idx, align 8
%_8.sroa.5.0._1.sroa_idx = getelementptr inbounds i8, ptr %_0.i.i.i.i.i, i64 16
%_8.sroa.7.0._1.sroa_idx = getelementptr inbounds i8, ptr %_0.i.i.i.i.i, i64 32
tail call void `@llvm.memset.p0.i64(ptr` noundef nonnull align 8 dereferenceable(16) %_8.sroa.5.0._1.sroa_idx, i8 0, i64 16, i1 false)
store ptr inttoptr (i64 1 to ptr), ptr %_8.sroa.7.0._1.sroa_idx, align 8
%_8.sroa.8.0._1.sroa_idx = getelementptr inbounds i8, ptr %_0.i.i.i.i.i, i64 40
%_8.sroa.10.0._1.sroa_idx = getelementptr inbounds i8, ptr %_0.i.i.i.i.i, i64 56
tail call void `@llvm.memset.p0.i64(ptr` noundef nonnull align 8 dereferenceable(16) %_8.sroa.8.0._1.sroa_idx, i8 0, i64 16, i1 false)
store ptr inttoptr (i64 1 to ptr), ptr %_8.sroa.10.0._1.sroa_idx, align 8
%_8.sroa.11.0._1.sroa_idx = getelementptr inbounds i8, ptr %_0.i.i.i.i.i, i64 64
store i64 0, ptr %_8.sroa.11.0._1.sroa_idx, align 8
ret ptr %_0.i.i.i.i.i
}
```
</details>
|
|
|
|
Stabilize `const_option`
This makes the following API stable in const contexts:
```rust
impl<T> Option<T> {
pub const fn as_mut(&mut self) -> Option<&mut T>;
pub const fn expect(self, msg: &str) -> T;
pub const fn unwrap(self) -> T;
pub const unsafe fn unwrap_unchecked(self) -> T;
pub const fn take(&mut self) -> Option<T>;
pub const fn replace(&mut self, value: T) -> Option<T>;
}
impl<T> Option<&T> {
pub const fn copied(self) -> Option<T>
where T: Copy;
}
impl<T> Option<&mut T> {
pub const fn copied(self) -> Option<T>
where T: Copy;
}
impl<T, E> Option<Result<T, E>> {
pub const fn transpose(self) -> Result<Option<T>, E>
}
impl<T> Option<Option<T>> {
pub const fn flatten(self) -> Option<T>;
}
```
The following functions make use of the unstable `const_precise_live_drops` feature:
- `expect`
- `unwrap`
- `unwrap_unchecked`
- `transpose`
- `flatten`
Fixes: <https://github.com/rust-lang/rust/issues/67441>
|
|
This makes the following API stable in const contexts:
impl<T> Option<T> {
pub const fn as_mut(&mut self) -> Option<&mut T>;
pub const fn expect(self, msg: &str) -> T;
pub const fn unwrap(self) -> T;
pub const unsafe fn unwrap_unchecked(self) -> T;
pub const fn take(&mut self) -> Option<T>;
pub const fn replace(&mut self, value: T) -> Option<T>;
}
impl<T> Option<&T> {
pub const fn copied(self) -> Option<T>
where T: Copy;
}
impl<T> Option<&mut T> {
pub const fn copied(self) -> Option<T>
where T: Copy;
}
impl<T, E> Option<Result<T, E>> {
pub const fn transpose(self) -> Result<Option<T>, E>
}
impl<T> Option<Option<T>> {
pub const fn flatten(self) -> Option<T>;
}
The following functions make use of the unstable
`const_precise_live_drops` feature:
- `expect`
- `unwrap`
- `unwrap_unchecked`
- `transpose`
- `flatten`
Fixes: <https://github.com/rust-lang/rust/issues/67441>
|
|
remove const_cow_is_borrowed feature gate
The two functions guarded by this are still unstable, and there's no reason to require a separate feature gate for their const-ness -- we can just have `cow_is_borrowed` cover both kinds of stability.
Cc #65143
|
|
|
|
Const-stabilizes:
- `write`
- `write_bytes`
- `write_unaligned`
In the following paths:
- `core::ptr`
- `core::ptr::NonNull`
- pointer `<*mut T>`
Const-stabilizes the internal `core::intrinsics`:
- `write_bytes`
- `write_via_move`
|
|
Same rationale as in the previous commit.
|
|
liballoc: introduce String, Vec const-slicing
This change `const`-qualifies many methods on `Vec` and `String`, notably `as_slice`, `as_str`, `len`. These changes are made behind the unstable feature flag `const_vec_string_slice`.
## Motivation
This is to support simultaneous variance over ownership and constness. I have an enum type that may contain either `String` or `&str`, and I want to produce a `&str` from it in a possibly-`const` context.
```rust
enum StrOrString<'s> {
Str(&'s str),
String(String),
}
impl<'s> StrOrString<'s> {
const fn as_str(&self) -> &str {
match self {
// In a const-context, I really only expect to see this variant, but I can't switch the implementation
// in some mode like #[cfg(const)] -- there has to be a single body
Self::Str(s) => s,
// so this is a problem, since it's not `const`
Self::String(s) => s.as_str(),
}
}
}
```
Currently `String` and `Vec` don't support this, but can without functional changes. Similar logic applies for `len`, `capacity`, `is_empty`.
## Changes
The essential thing enabling this change is that `Unique::as_ptr` is `const`. This lets us convert `RawVec::ptr` -> `Vec::as_ptr` -> `Vec::as_slice` -> `String::as_str`.
I had to move the `Deref` implementations into `as_{str,slice}` because `Deref` isn't `#[const_trait]`, but I would expect this change to be invisible up to inlining. I moved the `DerefMut` implementations as well for uniformity.
|
|
This change `const`-qualifies many methods on Vec and String, notably
`as_slice`, `as_str`, `len`. These changes are made behind the unstable
feature flag `const_vec_string_slice` with the following tracking issue:
https://github.com/rust-lang/rust/issues/129041
|
|
|
|
|
|
|
|
|
|
Apply size optimizations to panic machinery and some cold functions
* std dependencies gimli and addr2line are now built with opt-level=s
* various panic-related methods and `#[cold]` methods are now marked `#[optimize(size)]`
Panics should be cold enough that it doesn't make sense to optimize them for speed. The only tradeoff here is if someone does a lot of backtrace captures (without panics) and printing then the opt-level change might impact their perf.
Seems to be the first use of the optimize attribute. Tracking issue #54882
|
|
A partial stabilization that only affects:
- AllocType<T>::new_uninit
- AllocType<T>::assume_init
- AllocType<[T]>::new_uninit_slice
- AllocType<[T]>::assume_init
where "AllocType" is Box, Rc, or Arc
|
|
|
|
|
|
|
|
Bump bootstrap compiler to new beta
https://forge.rust-lang.org/release/process.html#master-bootstrap-update-t-2-day-tuesday
|
|
They are all clean now, so enable the lint to keep them clean going forward.
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
|
|
|
|
Stabilize `const_waker`
Closes: https://github.com/rust-lang/rust/issues/102012.
For `local_waker` and `context_ext` related things, I just ~~moved them to dedicated feature gates and reused their own tracking issue (maybe it's better to open a new one later, but at least they should not be tracked under https://github.com/rust-lang/rust/issues/102012 from the beginning IMO.)~~ reused their own feature gates as suggested by ``@tgross35.``
``@rustbot`` label: +T-libs-api
r? libs-api
|
|
|
|
|
|
|
|
Mark format! with must_use hint
Uses unstable feature https://github.com/rust-lang/rust/issues/94745
Part of #126475
First contribution to rust, please let me know if the blessing of tests is correct
Thanks `@bjorn3` for the help
|
|
Don't check the capacity every time (and also for `Extend` for tuples, as this is how `unzip()` is implemented).
I did this with an unsafe method on `Extend` that doesn't check for growth (`extend_one_unchecked()`). I've marked it as perma-unstable currently, although we may want to expose it in the future so collections outside of std can benefit from it. Then specialize `Extend for (A, B)` for `TrustedLen` to call it.
It may seem that an alternative way of implementing this is to have a semi-public trait (`#[doc(hidden)]` public, so collections outside of core can implement it) for `extend()` inside tuples, and specialize it from collections. However, it is impossible due to limitations of `min_specialization`.
A concern that may arise with the current approach is that implementing `extend_one_unchecked()` correctly must also incur implementing `extend_reserve()`, otherwise you can have UB. This is a somewhat non-local safety invariant. However, I believe this is fine, since to have actual UB you must have unsafe code inside your `extend_one_unchecked()` that makes incorrect assumption, *and* not implement `extend_reserve()`. I've also documented this requirement.
|
|
|
|
Stabilize `hint::assert_unchecked`
Make the following API stable, including const:
```rust
// core::hint, std::hint
pub const unsafe fn assert_unchecked(p: bool);
```
This PR also reworks some of the documentation and adds an example.
Tracking issue: https://github.com/rust-lang/rust/issues/119131
FCP: https://github.com/rust-lang/rust/issues/119131#issuecomment-1906394087. The docs update should resolve the remaining concern.
|
|
This is possible now that inline const blocks are stable; the idea was
even mentioned as an alternative when `uninit_array()` was added:
<https://github.com/rust-lang/rust/pull/65580#issuecomment-544200681>
> if it’s stabilized soon enough maybe it’s not worth having a
> standard library method that will be replaceable with
> `let buffer = [MaybeUninit::<T>::uninit(); $N];`
Const array repetition and inline const blocks are now stable (in the
next release), so that circumstance has come to pass, and we no longer
have reason to want `uninit_array()` other than convenience. Therefore,
let’s evaluate the inconvenience by not using `uninit_array()` in
the standard library, before potentially deleting it entirely.
|
|
Rollup of 3 pull requests
Successful merges:
- #126140 (Rename `std::fs::try_exists` to `std::fs::exists` and stabilize fs_try_exists)
- #126318 (Add a `x perf` command for integrating bootstrap with `rustc-perf`)
- #126552 (Remove use of const traits (and `feature(effects)`) from stdlib)
r? `@ghost`
`@rustbot` modify labels: rollup
|
|
|
|
|
|
Make both `hint_assert_unchecked` and `const_hint_assert_unchecked`
stable as `hint_assert_unchecked`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Fully stabilize the following API, including const where applicable:
impl <T> NonNull<T> {
pub const unsafe fn offset(self, count: isize) -> Self;
pub const unsafe fn add(self, count: usize) -> Self;
pub const unsafe fn sub(self, count: usize) -> Self;
pub const unsafe fn offset_from(self, origin: NonNull<T>) -> isize;
pub const unsafe fn read(self) -> T;
pub unsafe fn read_volatile(self) -> T;
pub const unsafe fn read_unaligned(self) -> T;
pub unsafe fn write_volatile(self, val: T);
pub unsafe fn replace(self, src: T) -> T;
}
impl<T: ?Sized> NonNull<T> {
pub const unsafe fn byte_offset(self, count: isize) -> Self;
pub const unsafe fn byte_add(self, count: usize) -> Self;
pub const unsafe fn byte_sub(self, count: usize) -> Self;
pub const unsafe fn byte_offset_from<U: ?Sized>(self, origin: NonNull<U>) -> isize;
pub unsafe fn drop_in_place(self);
}
Stabilize the following without const:
impl <T> NonNull<T> {
// const under `const_intrinsic_copy`
pub const unsafe fn copy_to(self, dest: NonNull<T>, count: usize);
pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull<T>, count: usize);
pub const unsafe fn copy_from(self, src: NonNull<T>, count: usize);
pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull<T>, count: usize);
// const under `const_ptr_write`
pub const unsafe fn write(self, val: T);
pub const unsafe fn write_bytes(self, val: u8, count: usize);
pub const unsafe fn write_unaligned(self, val: T);
// const under `const_swap`
pub const unsafe fn swap(self, with: NonNull<T>);
// const under `const_align_offset`
pub const fn align_offset(self, align: usize) -> usize;
// const under `const_pointer_is_aligned`
pub const fn is_aligned(self) -> bool;
}
Left the following unstable:
impl <T> NonNull<T> {
// moved gate to `ptr_sub_ptr`
pub const unsafe fn sub_ptr(self, subtracted: NonNull<T>) -> usize;
}
impl <T: ?Sized> NonNull<T> {
// moved gate to `pointer_is_aligned_to`
pub const fn is_aligned_to(self, align: usize) -> bool;
}
Fixes: https://github.com/rust-lang/rust/issues/117691
|
|
Stabilize `Utf8Chunks`
Pending FCP in https://github.com/rust-lang/rust/issues/99543.
This PR includes the proposed modification in https://github.com/rust-lang/libs-team/issues/190 as agreed in https://github.com/rust-lang/rust/issues/99543#issuecomment-2050406568.
|
|
|
|
|
|
|
|
Add the following methods, that work similarly to VecDeque::as_slices:
- alloc::collections::vec_deque::Iter::as_slices
- alloc::collections::vec_deque::IterMut::into_slices
- alloc::collections::vec_deque::IterMut::as_slices
- alloc::collections::vec_deque::IterMut::as_mut_slices
Obtaining slices from a VecDeque iterator was not previously possible.
|
|
|
|
Do not allocate for ZST ThinBox (attempt 2 using const_allocate)
There's PR https://github.com/rust-lang/rust/pull/123184 which avoids allocation for ZST ThinBox.
That PR has an issue with unsoundness with padding in `MaybeUninit` (see comments in that PR). Also that PR relies on `Freeze` trait.
This PR is much simpler implementation which does not have this problem, but it uses `const_allocate` feature.
`@oli-obk` suggested that `const_allocate` should not be used for that feature. But I like how easy it to do this feature with `const_allocate`. Maybe it's OK to use `const_allocate` while `ThinBox` is unstable? Or, well, we can abandon this PR.
r? `@oli-obk`
|
|
|