stop specializing on `Copy`
fixes https://github.com/rust-lang/rust/issues/132442
`std` specializes on `Copy` to optimize certain library functions such as `clone_from_slice`. This is unsound, however, as the `Copy` implementation may not be always applicable because of lifetime bounds, which specialization does not take into account; the result being that values are copied even though they are not `Copy`. For instance, this code:
```rust
struct SometimesCopy<'a>(&'a Cell<bool>);
impl<'a> Clone for SometimesCopy<'a> {
fn clone(&self) -> Self {
self.0.set(true);
Self(self.0)
}
}
impl Copy for SometimesCopy<'static> {}
let clone_called = Cell::new(false);
// As SometimesCopy<'clone_called> is not 'static, this must run `clone`,
// setting the value to `true`.
let _ = [SometimesCopy(&clone_called)].clone();
assert!(clone_called.get());
```
should not panic, but does ([playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=6be7a48cad849d8bd064491616fdb43c)).
To solve this, this PR introduces a new `unsafe` trait: `TrivialClone`. This trait may be implemented whenever the `Clone` implementation is equivalent to copying the value (so e.g. `fn clone(&self) -> Self { *self }`). Because of lifetime erasure, there is no way for the `Clone` implementation to observe lifetime bounds, meaning that even if the `TrivialClone` has stricter bounds than the `Clone` implementation, its invariant still holds. Therefore, it is sound to specialize on `TrivialClone`.
I've changed all `Copy` specializations in the standard library to specialize on `TrivialClone` instead. Unfortunately, the unsound `#[rustc_unsafe_specialization_marker]` attribute on `Copy` cannot be removed in this PR as `hashbrown` still depends on it. I'll make a PR updating `hashbrown` once this lands.
With `Copy` no longer being considered for specialization, this change alone would result in the standard library optimizations not being applied for user types unaware of `TrivialClone`. To avoid this and restore the optimizations in most cases, I have changed the expansion of `#[derive(Clone)]`: Currently, whenever both `Clone` and `Copy` are derived, the `clone` method performs a copy of the value. With this PR, the derive macro also adds a `TrivialClone` implementation to make this case observable using specialization. I anticipate that most users will use `#[derive(Clone, Copy)]` whenever both are applicable, so most users will still profit from the library optimizations.
Unfortunately, Hyrum's law applies to this PR: there are some popular crates which rely on the precise specialization behaviour of `core` to implement "specialization at home", e.g. [`libAFL`](89cff63702/libafl_bolts/src/tuples.rs (L27-L49)). I have no remorse for breaking such horrible code, but perhaps we should open other, better ways to satisfy their needs – for example by dropping the `'static` bound on `TypeId::of`...
Implement IsZero for ().
Implement default `IsZero` for all arrays, only returning true if the array is empty
(making the existing array impl for `IsZero` elements a specialization).
Optimize `IsZero::is_zero` for arrays of zero-sized `IsZero` elements.
add extend_front to VecDeque with specialization like extend
ACP: https://github.com/rust-lang/libs-team/issues/658
Tracking issue: rust-lang/rust#146975
_Text below was written before opening the ACP_
Feature was requested in rust-lang/rust#69939, I recently also needed it so decided to implement it as my first contribution to the Rust standard library. I plan on doing more but wanted to start with a small change.
Some questions I had (both on implementation and design) with answers:
- Q: `extend` allows iterators that yield `&T` where `T` is `Clone`, should extend_front do too?
A: No, users can use [`copied`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.copied) and/or [`cloned`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.cloned).
- Q: Does this need a whole new trait like Extend or only a method on `VecDeque`?
A: No, see ACP.
- Q: How do I deal with all the code duplication? Most code is similar to that of `extend`, maybe there is a nice way to factor out the code around `push_unchecked`/`push_front_unchecked`.
Will come back to this later.
- Q: Why are certain things behind feature gates, `cfg(not(test))` like `vec::IntoIter` here and `cfg(not(no_global_oom_handling))` like `Vec::extend_from_within`? (I am also looking at implementing `VecDeque::extend_from_within`)
A: See https://github.com/rust-lang/rust/pull/146861#pullrequestreview-3250163369
- Q: Should `extend_front` act like repeated pushes to the front of the queue? This reverses the order of the elements. Doing it different might incur an extra move if the iterator length is not known up front (where do you start placing elements in the buffer?).
A: `extend_front` acts like repeated pushes, `prepend` preserves the element order, see ACP or tracking issue.
Stabilize `fmt::from_fn`
Resolvesrust-lang/rust#146705, pending its FCP.
As discussed in that tracking issue and rust-lang/rust#117729, this splits `fmt::from_fn` out from the `debug_closure_helpers` feature.
Turn `Cow::is_borrowed,is_owned` into associated functions.
This is done because `Cow` implements `Deref`. Therefore, to avoid conflicts with an inner type having a method of the same name, we use an associated method, like `Box::into_raw`.
Tracking issue: #65143
Revert constification of `AsRef for Cow` due to inference failure
Reported issue: rust-lang/rust#147964
Original PR: rust-lang/rust#145279
`const AsRef` tracking issue: rust-lang/rust#143773
Should have additional crater run to verify this fixes the issue.
Add `String::replace_first` and `String::replace_last`
Rebase of #97977 (cc `@WilliamVenner)`
> Convenience methods that use `match_indices` and `replace_range` to efficiently replace a substring in a string without reallocating, if capacity (and the implementation of `Vec::splice`) allows.
The intra-doc link to `str::replacen` is a direct url-based link to `str::replacen` in `std`'s docs to work around #98941. This means that when building only `alloc`'s docs (and not `std`'s), it will be a broken link. There is precedent for this e.g. in [`core::hint::spin_loop`](https://doc.rust-lang.org/nightly/src/core/hint.rs.html#214) which links to `std:🧵:yield_now` using a [url-based link](https://github.com/rust-lang/rust/blob/master/library/core/src/hint.rs#L265) and thus is a dead link when only building `core`'s docs.
ACP: https://github.com/rust-lang/libs-team/issues/506
Add `FromIterator` impls for `ascii::Char`s to `String`s
Wanted to `collect` ascii chars into a `String` while working on #141369 , and was surprised these impls don't exist. Seems to me to be simply oversight.
BTW, I only added `impl FromIterator<ascii::Char> for Cow<'_, str>`, without a corresponding `FromIterator<&Char>` impl, because there's no existing impl for `FromIterator<&char>`, but that might be oversight too.
cc #110998
Implement `Debug` for `EncodeWide`
Since `std::os::windows::ffi::EncodeWide` was reexported from `std::sys_common::wtf8::EncodeWide`, which has `#![allow(missing_debug_implementations)]` in the parent module, it did not implement `Debug`. When it was moved to `core`, a placeholder impl was added; fill it in.
This becomes insta-stable.
r? libs-api
Move computation of allocator shim contents to cg_ssa
In the future this should make it easier to use weak symbols for the allocator shim on platforms that properly support weak symbols. And it would allow reusing the allocator shim code for handling default implementations of the upcoming externally implementable items feature on platforms that don't properly support weak symbols.
In addition to make this possible, the alloc error handler is now handled in a way such that it is possible to avoid using the allocator shim when liballoc is compiled without `no_global_oom_handling` if you use `#[alloc_error_handler]`. Previously this was only possible if you avoided liballoc entirely or compiled it with `no_global_oom_handling`. You still need to avoid libstd and to define the symbol that indicates that avoiding the allocator shim is unstable.
Move more code to `RawVec::finish_grow`
This move a branch and more code into the cold method `finish_grow`, which means that less code is inlined at each `try_reserve` site. Additionally, this reduces the amount of parameters, so they can all be passed by registers.
Currently it is possible to avoid linking the allocator shim when
__rust_no_alloc_shim_is_unstable_v2 is defined when linking rlibs
directly as some build systems need. However this requires liballoc to
be compiled with --cfg no_global_oom_handling, which places huge
restrictions on what functions you can call and makes it impossible to
use libstd. Or alternatively you have to define
__rust_alloc_error_handler and (when using libstd)
__rust_alloc_error_handler_should_panic
using #[rustc_std_internal_symbol]. With this commit you can either use
libstd and define __rust_alloc_error_handler_should_panic or not use
libstd and use #[alloc_error_handler] instead. Both options are still
unstable though.
Eventually the alloc_error_handler may either be removed entirely
(though the PR for that has been stale for years now) or we may start
using weak symbols for it instead. For the latter case this commit is a
prerequisite anyway.