Implementation of `fmt::FormattingOptions`
Tracking issue: #118117
Public API:
```rust
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct FormattingOptions { … }
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Sign {
Plus,
Minus
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DebugAsHex {
Lower,
Upper
}
impl FormattingOptions {
pub fn new() -> Self;
pub fn sign(&mut self, sign: Option<Sign>) -> &mut Self;
pub fn sign_aware_zero_pad(&mut self, sign_aware_zero_pad: bool) -> &mut Self;
pub fn alternate(&mut self, alternate: bool) -> &mut Self;
pub fn fill(&mut self, fill: char) -> &mut Self;
pub fn align(&mut self, alignment: Option<Alignment>) -> &mut Self;
pub fn width(&mut self, width: Option<usize>) -> &mut Self;
pub fn precision(&mut self, precision: Option<usize>) -> &mut Self;
pub fn debug_as_hex(&mut self, debug_as_hex: Option<DebugAsHex>) -> &mut Self;
pub fn get_sign(&self) -> Option<Sign>;
pub fn get_sign_aware_zero_pad(&self) -> bool;
pub fn get_alternate(&self) -> bool;
pub fn get_fill(&self) -> char;
pub fn get_align(&self) -> Option<Alignment>;
pub fn get_width(&self) -> Option<usize>;
pub fn get_precision(&self) -> Option<usize>;
pub fn get_debug_as_hex(&self) -> Option<DebugAsHex>;
pub fn create_formatter<'a>(self, write: &'a mut (dyn Write + 'a)) -> Formatter<'a>;
}
impl<'a> Formatter<'a> {
pub fn new(write: &'a mut (dyn Write + 'a), options: FormattingOptions) -> Self;
pub fn with_options<'b>(&'b mut self, options: FormattingOptions) -> Formatter<'b>;
pub fn sign(&self) -> Option<Sign>;
pub fn options(&self) -> FormattingOptions;
}
```
Relevant changes from the public API in the tracking issue (I'm leaving out some stuff I consider obvious mistakes, like missing `#[derive(..)]`s and `pub` specifiers):
- `enum DebugAsHex`/`FormattingOptions::debug_as_hex`/`FormattingOptions::get_debug_as_hex`: To support `{:x?}` as well as `{:X?}`. I had completely missed these options in the ACP. I'm open for any and all bikeshedding, not married to the name.
- `fill`/`get_fill` now takes/returns `char` instead of `Option<char>`. This simply mirrors what `Formatter::fill` returns (with default being `' '`).
- Changed `zero_pad`/`get_zero_pad` to `sign_aware_zero_pad`/`get_sign_aware_zero_pad`. This also mirrors `Formatter::sign_aware_zero_pad`. While I'm not a fan of this quite verbose name, I do believe that having the interface of `Formatter` and `FormattingOptions` be compatible is more important.
- For the same reason, renamed `alignment`/`get_alignment` to `aling`/`get_align`.
- Deviating from my initial idea, `Formatter::with_options` returns a `Formatter` which has the lifetime of the `self` reference as its generic lifetime parameter (in the original API spec, the generic lifetime of the returned `Formatter` was the generic lifetime used by `self` instead). Otherwise, one could construct two `Formatter`s that both mutably borrow the same underlying buffer, which would be unsound. This solution still has performance benefits over simply using `Formatter::new`, so I believe it is worthwhile to keep this method.
Stabilize noop_waker
Tracking Issue: #98286
This is a handy feature that's been used widely in tests and example async code and it'd be nice to make it available to users.
cc `@rust-lang/wg-async`
Replace black with ruff in `tidy`
`ruff` can both lint and format Python code (in fact, it should be a mostly drop-in replacement for `black` in terms of formatting), so it's not needed to use `black` anymore. This PR removes `black` and replaces it with `ruff`, to get rid of one Python dependency, and also to make Python formatting faster (although that's a small thing).
If we decide to merge this, we'll need to "reformat the world" - `ruff` is not perfectly compatible with `black`, and it also looks like `black` was actually ignoring some files before. I tried it locally (`./x test tidy --extra-checks=py:fmt --bless`) and it also reformatted some code in subtrees (e.g. `clippy` or `rustc_codegen_gcc`) - I'm not sure how to handle that.
Formatter::with_options takes self as a mutable reference (`&'a mut
Formatter<'b>`). `'a` and `'b` need to be different lifetimes. Just taking `&'a
mut Formatter<'a>` and trusting in Rust being able to implicitely convert from
`&'a mut Formatter<'b>` if necessary (after all, `'a` must be smaller than `'b`
anyway) fails because `'b` is behind a *mutable* reference. For background on
on this behavior, see https://doc.rust-lang.org/nomicon/subtyping.html#variance.
The idea behind this is to make implementing `fmt::FormattingOptions` (as well
as any future changes to `std::Formatter`) easier.
In theory, this might have a negative performance impact because of the
additional function calls. However, I strongly believe that those will be
inlined anyway, thereby producing assembly code that has comparable performance.
clarify simd_relaxed_fma non-determinism
This is the safer spec in the sense that it is more likely to be satisfied by the backend -- and if people are okay with a non-deterministic result, I assume they don't care whether it's the same choice across all lanes or not?
Cc ``@calebzulawski`` ``@workingjubilee``
Rename `core_pattern_type` and `core_pattern_types` lib feature gates to `pattern_type_macro`
That's what the gates are actually gating, and the single char difference in naming was not helpful either
fixes#128987
Add lint against function pointer comparisons
This is kind of a follow-up to https://github.com/rust-lang/rust/pull/117758 where we added a lint against wide pointer comparisons for being ambiguous and unreliable; well function pointer comparisons are also unreliable. We should IMO follow a similar logic and warn people about it.
-----
## `unpredictable_function_pointer_comparisons`
*warn-by-default*
The `unpredictable_function_pointer_comparisons` lint checks comparison of function pointer as the operands.
### Example
```rust
fn foo() {}
let a = foo as fn();
let _ = a == foo;
```
### Explanation
Function pointers comparisons do not produce meaningful result since they are never guaranteed to be unique and could vary between different code generation units. Furthermore different function could have the same address after being merged together.
----
This PR also uplift the very similar `clippy::fn_address_comparisons` lint, which only linted on if one of the operand was an `ty::FnDef` while this PR lints proposes to lint on all `ty::FnPtr` and `ty::FnDef`.
```@rustbot``` labels +I-lang-nominated
~~Edit: Blocked on https://github.com/rust-lang/libs-team/issues/323 being accepted and it's follow-up pr~~
Update `NonZero` and `NonNull` to not field-project (per MCP#807)
https://github.com/rust-lang/compiler-team/issues/807#issuecomment-2506098540 was accepted, so this is the first PR towards moving the library to not using field projections into `[rustc_layout_scalar_valid_range_*]` types.
`NonZero` was already using `transmute` nearly everywhere, so there are very few changes to it.
`NonNull` needed more changes, but they're mostly simple, changing `.pointer` to `.as_ptr()`.
r? libs
cc #133324, which will tidy up some of the MIR from this a bit more, but isn't a blocker.
LLVM does not include an implementation of the va_arg instruction for
Xtensa. From what I understand, this is a conscious decision and
instead language frontends are encouraged to implement it themselves.
The rationale seems to be that loading values correctly requires
language and ABI-specific knowledge that LLVM lacks.
This is true of most architectures, and rustc already provides
implementation for a number of them. This commit extends the support to
include Xtensa.
See https://lists.llvm.org/pipermail/llvm-dev/2017-August/116337.html
for some discussion on the topic.
Unfortunately there does not seem to be a reference document for the
semantics of the va_list and va_arg on Xtensa. The most reliable source
is the GCC implementation, which this commit tries to follow. Clang also
provides its own compatible implementation.
This was tested for all the types that rustc allows in variadics.
Co-authored-by: Brian Tarricone <brian@tarricone.org>
Co-authored-by: Jonathan Bastien-Filiatrault <joe@x2a.org>
Co-authored-by: Paul Lietar <paul@lietar.net>
Approved in [ACP 491](https://github.com/rust-lang/libs-team/issues/491).
Remove the `unsafe` on `core::intrinsics::breakpoint()`, since it's a
safe intrinsic to call and has no prerequisites.
(Thanks to @zachs18 for figuring out the `bootstrap`/`not(bootstrap)`
logic.)
Stabilize `const_maybe_uninit_write`
Mark the following API const stable:
```rust
impl<T> MaybeUninit<T> {
pub const fn write(&mut self, val: T) -> &mut T;
}
```
This depends on `const_mut_refs` and [`const_maybe_uninit_assume_init`](https://github.com/rust-lang/rust/issues/86722), both of which have recently been stabilized.
Closes: <https://github.com/rust-lang/rust/issues/63567>
Mark the following API const stable:
impl<T> MaybeUninit<T> {
pub const fn write(&mut self, val: T) -> &mut T;
}
This depends on `const_mut_refs` and `const_maybe_uninit_assume_init`,
both of which have recently been stabilized.
Tracking issue: <https://github.com/rust-lang/rust/issues/63567>
Stabilize unsigned and float variants of `num_midpoint` feature
This PR proposes that we stabilize the unsigned variants of the [`num_midpoint`](https://github.com/rust-lang/rust/issues/110840#issue-1684506201) feature as well as the floats variants, since they are not subject to any unresolved questions, which is equivalent to doing `(a + b) / 2` (and `(a + b) >> 1`) in a sufficiently large number.
The stabilized API surface would be:
```rust
/// Calculates the middle point of `self` and `rhs`.
///
/// `midpoint(a, b)` is `(a + b) / 2` as if it were performed in a sufficiently-large unsigned integral type.
/// This implies that the result is always rounded towards negative infinity and that no overflow will ever occur.
impl u{8,16,32,64,128,size} {
pub const fn midpoint(self, rhs: Self) -> Self;
}
impl NonZeroU{8,16,32,64,size} {
pub const fn midpoint(self, rhs: Self) -> Self;
}
impl f{32,64} {
pub const fn midpoint(self, rhs: Self) -> Self;
}
```
The signed variants `u{8,16,32,64,128,size}` would remain gated, until a decision is made about the rounding mode, in other words that the [unresolved questions](https://github.com/rust-lang/rust/issues/110840#issue-1684506201) are resolved.
cc `@rust-lang/libs-api`
cc `@scottmcm`
r? libs-api
Mark `slice::copy_from_slice` unstably const
Tracking issue #131415
I used `const_eval_select` for runtime and const panic functions because const formatting isn't available yet.
Add diagnostic item for `std::ops::ControlFlow`
This will be used in Clippy to detect useless conversions done through `ControlFlow::map_break()` and `ControlFlow::map_continue()`.
Something about the MIR lowering for `||` ended up breaking this, but it's fixed by changing the code to use `|` instead.
I also added an assembly test to ensure it *keeps* being `adc`.
changes old intrinsic declaration to new declaration
This pr is for issue #132735
It changes old `extern "intrinsic"` code block with new declaration.
There are other blocks that use old declaration but as the changes needed in single block is quite large I do them in parts
Bump boostrap compiler to new beta
Currently failing due to something about the const stability checks and `panic!`. I'm not sure why though since I wasn't able to see any PRs merged in the past few days that would result in a `cfg(bootstrap)` that shouldn't be removed. cc `@RalfJung` #131349
Use consistent wording in docs, use is zero instead of is 0
In documentation, wording of _"`rhs` is zero"_ and _"`rhs` is 0"_ is intermixed. This is especially visible [here](https://doc.rust-lang.org/std/primitive.usize.html#method.div_ceil).
This changes all occurrences to _"`rhs` is zero"_ for better readability.
That is, differentiate between out-of-bounds and overlapping indices, and remove the generic parameter `N`.
I also exported `GetManyMutError` from `alloc` (and `std`), which was apparently forgotten.
Changing the error to carry additional details means LLVM no longer generates separate short-circuiting branches for the checks, instead it generates one branch at the end. I therefore changed the code to use early returns to make LLVM generate jumps. Benchmark results between the approaches are somewhat mixed, but I chose this approach because it is significantly faster with ranges and also faster with `unwrap()`.
Add `as_array` and `as_mut_array` conversion methods to slices.
Tracking issue: #133508
This PR unstably implements the `as_array` and `as_mut_array` converters to `[T]`, `*const [T]`, and `*mut [T]`.
Shorten the `MaybeUninit` `Debug` implementation
Currently the `Debug` implementation for `MaybeUninit` winds up being pretty verbose. This struct:
```rust
#[derive(Debug)]
pub struct Foo {
pub a: u32,
pub b: &'static str,
pub c: MaybeUninit<u32>,
pub d: MaybeUninit<String>,
}
```
Prints as:
Foo {
a: 0,
b: "hello",
c: core::mem::maybe_uninit::MaybeUninit<u32>,
d: core::mem::maybe_uninit::MaybeUninit<alloc::string::String>,
}
The goal is just to be a standin for content so the path prefix doesn't add any useful information. Change the implementation to trim `MaybeUninit`'s leading path, meaning the new result is now:
Foo {
a: 0,
b: "hello",
c: MaybeUninit<u32>,
d: MaybeUninit<alloc::string::String>,
}
Support ranges in `<[T]>::get_many_mut()`
As per T-libs-api decision in #104642.
I implemented that with a separate trait and not within `SliceIndex`, because doing that via `SliceIndex` requires adding support for range types that are (almost) always overlapping e.g. `RangeFrom`, and also adding fake support code for `impl SliceIndex<str>`.
An inconvenience that I ran into was that slice indexing takes the index by value, but I only have it by reference. I could change slice indexing to take by ref, but this is pretty much the hottest code ever so I'm afraid to touch it. Instead I added a requirement for `Clone` (which all index types implement anyway) and cloned. This is an internal requirement the user won't see and the clone should always be optimized away.
I also implemented `Clone`, `PartialEq` and `Eq` for the error type, since I noticed it does not do that when writing the tests and other errors in std seem to implement them. I didn't implement `Copy` because maybe we will want to put something non-`Copy` there.
Reduce integer `Display` implementation size
I was thinking about #128204 and how we could reduce the size of the code and just realized that we didn't need the `_fmt` method to be implemented on signed integers, which in turns allow to simplify greatly the macro call.
r? `@workingjubilee`
I implemented that with a separate trait and not within `SliceIndex`, because doing that via `SliceIndex` requires adding support for range types that are (almost) always overlapping e.g. `RangeFrom`, and also adding fake support code for `impl SliceIndex<str>`.
An inconvenience that I ran into was that slice indexing takes the index by value, but I only have it by reference. I could change slice indexing to take by ref, but this is pretty much the hottest code ever so I'm afraid to touch it. Instead I added a requirement for `Clone` (which all index types implement anyway) and cloned. This is an internal requirement the user won't see and the clone should always be optimized away.
I also implemented `Clone`, `PartialEq` and `Eq` for the error type, since I noticed it does not do that when writing the tests and other errors in std seem to implement them. I didn't implement `Copy` because maybe we will want to put something non-`Copy` there.
Constify the `Deref`/`DerefMut` traits, too
One more constification. Rebased on that one commit that makes it so we don't need to provide stability on const impls.
r? fee1-dead
Add code example for `wrapping_neg` method for signed integers
With this example, we make it obvious that `wrapping_neg` works both ways (neg to pos and pos to neg).
r? `@workingjubilee`
Minimally constify `Add`
* This PR removes the requirement for `impl const` to have a const stability attribute. cc ``@RalfJung`` I believe you mentioned that it would make much more sense to require `const_trait`s to have const stability instead. I agree with that sentiment but I don't think that is _required_ for a small scale experimentation like this PR. https://github.com/rust-lang/project-const-traits/issues/16 should definitely be prioritized in the future, but removing the impl check should be good for now as all callers need `const_trait_impl` enabled for any const impl to work.
* This PR is intentionally minimal as constifying other traits can become more complicated (`PartialEq`, for example, would run into requiring implementing it for `str` as that is used in matches, which runs into the implementation for slice equality which uses specialization)
Per the reasons above, anyone who is interested in making traits `const` in the standard library are **strongly encouraged** to reach out to us on the [Zulip channel](https://rust-lang.zulipchat.com/#narrow/channel/419616-t-compiler.2Fproject-const-traits) before proceeding with the work.
cc ``@rust-lang/project-const-traits``
I believe there is prior approval from libs that we can experiment, so
r? project-const-traits
Mark `<[T; N]>::as_mut_slice` with the `const` specifier.
Tracking issue: #133333
`<[T; N]>::as_mut_slice` can have the `const` specifier without any changes to the function body.
Implement `~const Destruct` effect goal in the new solver
This also fixed a subtle bug/limitation of the `NeedsConstDrop` check. Specifically, the "`Qualif`" API basically treats const drops as totally structural, even though dropping something that has an explicit `Drop` implementation cannot be structurally decomposed. For example:
```rust
#![feature(const_trait_impl)]
#[const_trait] trait Foo {
fn foo();
}
struct Conditional<T: Foo>(T);
impl Foo for () {
fn foo() {
println!("uh oh");
}
}
impl<T> const Drop for Conditional<T> where T: ~const Foo {
fn drop(&mut self) {
T::foo();
}
}
const FOO: () = {
let _ = Conditional(());
//~^ This should error.
};
fn main() {}
```
In this example, when checking if the `Conditional(())` rvalue is const-drop, since `Conditional` has a const destructor, we would previously recurse into the `()` value and determine it has nothing to drop, which means that it is considered to *not* need a const drop -- even though dropping `Conditional(())` would mean evaluating the destructor which relies on that `T: const Foo` bound to hold!
This could be fixed alternatively by banning any const conditions on `const Drop` impls, but that really sucks -- that means that basically no *interesting* const drop impls could be written. We have the capability to totally and intuitively support the right behavior, which I've implemented here.
Currently the `Debug` implementation for `MaybeUninit` winds up being
pretty verbose. This struct:
#[derive(Debug)]
pub struct Foo {
pub a: u32,
pub b: &'static str,
pub c: MaybeUninit<u32>,
pub d: MaybeUninit<String>,
}
Prints as:
Foo {
a: 0,
b: "hello",
c: core::mem::maybe_uninit::MaybeUninit<u32>,
d: core::mem::maybe_uninit::MaybeUninit<alloc::string::String>,
}
The goal is just to be a standin for content so the path prefix doesn't
add any useful information. Change the implementation to trim
`MaybeUninit`'s leading path, meaning the new result is now:
Foo {
a: 0,
b: "hello",
c: MaybeUninit<u32>,
d: MaybeUninit<alloc::string::String>,
}
Rollup of 8 pull requests
Successful merges:
- #133238 (re-export `is_loongarch_feature_detected`)
- #133288 (Support `each_ref` and `each_mut` in `[T; N]` in constant expressions.)
- #133311 (Miri subtree update)
- #133313 (Use arc4random of libc for RTEMS target)
- #133319 (Simplify `fulfill_implication`)
- #133323 (Bail in effects in old solver if self ty is ty var)
- #133330 (library: update comment around close())
- #133337 (Fix typo in `std:🧵:Scope::spawn` documentation.)
r? `@ghost`
`@rustbot` modify labels: rollup
Support `each_ref` and `each_mut` in `[T; N]` in constant expressions.
Tracking issue: #133289
The methods `<[T; N]>::each_ref` and `<[T; N]>::each_mut` can easily be reimplemented to allow marking them with the `const` specifier.
This specific implementation takes a different approach than the original as to avoid using iterators (which are illegal in constant expressions).
Stabilize `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local`
Make `Ipv6Addr::is_unique_local` and `Ipv6Addr::is_unicast_link_local` stable (+const).
Newly stable API:
```rust
impl Ipv6Addr {
// Newly stable under `ipv6_is_unique_local`
const fn is_unique_local(&self) -> bool;
// Newly stable under `ipv6_is_unique_local`
const fn is_unicast_link_local(&self) -> bool;
}
```
These stabilise a subset of the following tracking issue:
- #27709
I have looked and could not find any issues with `is_unique_local` and `is_unicast_link_local`. There is a well received comment calling for stabilisation of the latter function.
Both functions are well defined and consistent with implementations in other languages:
- [Go](https://cs.opensource.google/go/go/+/refs/tags/go1.23.0:src/net/netip/netip.go;l=518)
- [Python](e9d1bf353c/Lib/ipaddress.py (L2319-L2321))
- [Ruby (unique local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#private-3F-source)
- [Ruby (unicast link local)](https://ruby-doc.org/stdlib-2.5.1/libdoc/ipaddr/rdoc/IPAddr.html#link_local-3F-source)
cc implementor `@little-dude`
(I can't find the original PR for `is_unqiue_local`)
r? libs-api
`@rustbot` label +T-libs-api +needs-fcp
Make `PointerLike` opt-in instead of built-in
The `PointerLike` trait currently is a built-in trait that computes the layout of the type. This is a bit problematic, because types implement this trait automatically. Since this can be broken due to semver-compatible changes to a type's layout, this is undesirable. Also, calling `layout_of` in the trait system also causes cycles.
This PR makes the trait implemented via regular impls, and adds additional validation on top to make sure that those impls are valid. This could eventually be `derive()`d for custom smart pointers, and we can trust *that* as a semver promise rather than risking library authors accidentally breaking it.
On the other hand, we may never expose `PointerLike`, but at least now the implementation doesn't invoke `layout_of` which could cause ICEs or cause cycles.
Right now for a `PointerLike` impl to be valid, it must be an ADT that is `repr(transparent)` and the non-1zst field needs to implement `PointerLike`. There are also some primitive impls for `&T`/ `&mut T`/`*const T`/`*mut T`/`Box<T>`.
Use attributes for `dangling_pointers_from_temporaries` lint
Checking for dangling pointers by function name isn't ideal, and leaves out certain pointer-returning methods that don't follow the `as_ptr` naming convention. Using an attribute for this lint cleans things up and allows more thorough coverage of other methods, such as `UnsafeCell::get()`.
mark is_val_statically_known intrinsic as stably const-callable
The intrinsic doesn't actually "do" anything in terms of language semantics, and we are already using it in stable const fn. So let's just properly mark it as stably const-callable to avoid needing `rustc_allow_const_fn_unstable` (and thus reducing noise and keeping the remaining `rustc_allow_const_fn_unstable` as a more clear signal).
Cc `@rust-lang/lang` usually you have to approve exposing intrinsics in const, but this intrinsic is basically just a compiler implementation detail. So FCP doesn't seem necessary.
Cc `@rust-lang/wg-const-eval`
Always inline functions signatures containing `f16` or `f128`
There are a handful of tier 2 and tier 3 targets that cause a LLVM crash or linker error when generating code that contains `f16` or `f128`. The cranelift backend also does not support these types. To work around this, every function in `std` or `core` that contains these types must be marked `#[inline]` in order to avoid sending any code to the backend unless specifically requested.
However, this is inconvenient and easy to forget. Introduce a check for these types in the frontend that automatically inlines any function signatures that take or return `f16` or `f128`.
Note that this is not a perfect fix because it does not account for the types being passed by reference or as members of aggregate types, but this is sufficient for what is currently needed in the standard library.
Fixes: https://github.com/rust-lang/rust/issues/133035
Closes: https://github.com/rust-lang/rust/pull/133037
These types are currently passed by reference, which does not avoid the
backend crashes. Change these back to being passed by value, which makes
the types easier to detect for automatic inlining.
Rollup of 7 pull requests
Successful merges:
- #131304 (float types: move copysign, abs, signum to libcore)
- #132907 (Change intrinsic declarations to new style)
- #132971 (Handle infer vars in anon consts on stable)
- #133003 (Make `CloneToUninit` dyn-compatible)
- #133004 (btree: simplify the backdoor between set and map)
- #133008 (update outdated comment about test-float-parse)
- #133012 (Add test cases for #125918)
r? `@ghost`
`@rustbot` modify labels: rollup
Make `CloneToUninit` dyn-compatible
Make `CloneToUninit` dyn-compatible, by making `clone_to_uninit`'s `dst` parameter `*mut u8` instead of `*mut Self`, so the method does not reference `Self` except in the `self` parameter and is thus dispatchable from a trait object.
This allows, among other things, adding `CloneToUninit` as a supertrait bound for `trait Foo` to allow cloning `dyn Foo` in some containers. Currently, this means that `Rc::make_mut` and `Arc::make_mut` can work with `dyn Foo` where `trait Foo: CloneToUninit`.
<details><summary>Example</summary>
```rs
#![feature(clone_to_uninit)]
use std::clone::CloneToUninit;
use std::rc::Rc;
use std::fmt::Debug;
use std::borrow::BorrowMut;
trait Foo: BorrowMut<u32> + CloneToUninit + Debug {}
impl<T: BorrowMut<u32> + CloneToUninit + Debug> Foo for T {}
fn main() {
let foo: Rc<dyn Foo> = Rc::new(42_u32);
let mut bar = foo.clone();
*Rc::make_mut(&mut bar).borrow_mut() = 37;
dbg!(foo, bar); // 42, 37
}
```
</details>
Eventually, `Box::<T>::clone` is planned to be converted to use `T::clone_to_uninit`, which when combined with this change, will allow cloning `Box<dyn Foo>` where `trait Foo: CloneToUninit` without any additional `unsafe` code for the author of `trait Foo`.[^1]
This PR should have no stable side-effects, as `CloneToUninit` is unstable so cannot be mentioned on stable, and `CloneToUninit` is not used as a supertrait anywhere in the stdlib.
This change removes some length checks that could only fail if library UB was already hit (e.g. calling `<[T]>::clone_to_uninit` with a too-small-length `dst` is library UB and was previously detected[^2]; since `dst` does not have a length anymore, this now cannot be detected[^3]).
r? libs-api
-----
I chose to make the parameter `*mut u8` instead of `*mut ()` because that might make it simpler to pass the result of `alloc` to `clone_to_uninit`, but `*mut ()` would also make sense, and any `*mut ConcreteType` would *work*. The original motivation for [using specifically `*mut ()`](https://github.com/rust-lang/rust/pull/116113#discussion_r1335303908) appears to be `std::ptr::from_raw_parts_mut`, but that now [takes `*mut impl Thin`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_raw_parts.html) instead of `*mut ()`. I have another branch where the parameter is `*mut ()`, if that is preferred.
It *could* also take something like `&mut [MaybeUninit<u8>]` to be dyn-compatible but still allow size-checking and in some cases safe writing, but this is already an `unsafe` API where misuse is UB, so I'm not sure how many guardrails it's worth adding here, and `&mut [MaybeUninit<u8>]` might be overly cumbersome to construct for callers compared to `*mut u8`
[^1]: Note that `impl<T: CloneToUninit + ?Sized> Clone for Box` must be added before or at the same time as when `CloneToUninit` becomes stable, due to `Box` being `#[fundamental]`, as if there is any stable gap between the stabilization of `CloneToUninit` and `impl<T: CloneToUninit + ?Sized> Clone for Box`, then users could implement both `CloneToUninit for dyn LocalTrait` and separately `Clone for Box<dyn LocalTrait>` during that gap, and be broken by the introduction of `impl<T: CloneToUninit + ?Sized> Clone for Box`.
[^2]: Using a `debug_assert_eq` in [`core::clone::uninit::CopySpec::clone_slice`](https://doc.rust-lang.org/nightly/src/core/clone/uninit.rs.html#28).
[^3]: This PR just uses [the metadata (length) from `self`](e0c1c8bc50/library/core/src/clone.rs (L286)) to construct the `*mut [T]` to pass to `CopySpec::clone_slice` in `<[T]>::clone_to_uninit`.
Change intrinsic declarations to new style
Pr is for issue #132735
This changes the first `extern "rust-intrinsic"` block to the new style.
r? `@RalfJung`
float types: move copysign, abs, signum to libcore
These operations are explicitly specified to act "bitwise", i.e. they just act on the sign bit and do not even quiet signaling NaNs. We also list them as ["non-arithmetic operations"](https://doc.rust-lang.org/nightly/std/primitive.f32.html#nan-bit-patterns), and all the other non-arithmetic operations are in libcore. There's no reason to expect them to require any sort of runtime support, and from [these experiments](https://github.com/rust-lang/rust/issues/50145#issuecomment-997301250) it seems like LLVM indeed compiles them in a way that does not require any sort of runtime support.
Nominating for `@rust-lang/libs-api` since this change takes immediate effect on stable.
Part of https://github.com/rust-lang/rust/issues/50145.
improve codegen of fmt_num to delete unreachable panic
it seems LLVM doesn't realize that `curr` is always decremented at least once in either loop formatting characters of the input string by their appropriate radix, and so the later `&buf[curr..]` generates a check for out-of-bounds access and panic. this is unreachable in reality as even for `x == T::zero()` we'll produce at least the character `Self::digit(T::zero())`, yielding at least one character output, and `curr` will always be at least one below `buf.len()`.
adjust `fmt_int` to make this fact more obvious to the compiler, which fortunately (or unfortunately) results in a measurable performance improvement for workloads heavy on formatting integers.
in the program i'd noticed this in, you can see the `cmp $0x80,%rdi; ja 7c` here, which branches to a slice index fail helper:
<img width="660" alt="before" src="https://github.com/rust-lang/rust/assets/4615790/ac482d54-21f8-494b-9c83-4beadc3ca0ef">
where after this change the function is broadly similar, but smaller, with one fewer registers updated in each pass through the loop in addition the never-taken `cmp/ja` being gone:
<img width="646" alt="after" src="https://github.com/rust-lang/rust/assets/4615790/1bee1d76-b674-43ec-9b21-4587364563aa">
this represents a ~2-3% difference in runtime in my [admittedly comically i32-formatting-bound](https://github.com/athre0z/disas-bench/blob/master/bench/yaxpeax/src/main.rs#L58-L67) use case (printing x86 instructions, including i32 displacements and immediates) as measured on a ryzen 9 3950x.
the impact on `<impl LowerHex for i8>::fmt` is both more dramatic and less impactful: it continues to have a loop that is evaluated at most twice, though the compiler doesn't know that to unroll it. the generated code there is identical to the impl for `i32`. there, the smaller loop body has less effect on runtime, and removing the never-taken slice bounds check is offset by whatever address recalculation is happening with the `lea/add/neg` at the end of the loop. it behaves about the same before and after.
---
i initially measured slightly better outcomes using `unreachable_unchecked()` here instead, but that was hacking on std and rebuilding with `-Z build-std` on an older rustc (nightly 5b377cece, 2023-06-30). it does not yield better outcomes now, so i see no reason to proceed with that approach at all.
<details>
<summary>initial notes about that, seemingly irrelevant on modern rustc</summary>
i went through a few tries at getting llvm to understand the bounds check isn't necessary, but i should mention the _best_ i'd seen here was actually from the existing `fmt_int` with a diff like
```diff
if x == zero {
// No more digits left to accumulate.
break;
};
}
}
+
+ if curr >= buf.len() {
+ unsafe { core::hint::unreachable_unchecked(); }
+ }
let buf = &buf[curr..];
```
posting a random PR to `rust-lang/rust` to do that without a really really compelling reason seemed a bit absurd, so i tried to work that into something that seems more palatable at a glance. but if you're interested, that certainly produced better (x86_64) code through LLVM. in that case with `buf.iter_mut().rev()` as the iterator, `<impl LowerHex for i8>::fmt` actually unrolls into something like
```
put_char(x & 0xf);
let mut len = 1;
if x > 0xf {
put_char((x >> 4) & 0xf);
len = 2;
}
pad_integral(buf[buf.len() - len..]);
```
it's pretty cool! `<impl LowerHex for i32>::fmt` also was slightly better. that all resulted in closer to an 6% difference in my use case.
</details>
---
i have not looked at formatters other than LowerHex/UpperHex with this change, though i'd be a bit shocked if any were _worse_.
(i have absolutely _no_ idea how you'd regression test this, but that might be just my not knowing what the right tool for that would be in rust-lang/rust. i'm of half a mind that this is small and fiddly enough to not be worth landing lest it quietly regress in the future anyway. but i didn't want to discard the idea without at least offering it upstream here)