Tidy up bigint multiplication methods
This tidies up the library version of the bigint multiplication methods after the addition of the intrinsics in #133663. It follows [this summary](https://github.com/rust-lang/rust/issues/85532#issuecomment-2403442775) of what's desired for these methods.
Note that, if `2H = N`, then `uH::MAX * uH::MAX + uH::MAX + uH::MAX` is `uN::MAX`, and that we can effectively add two "carry" values without overflowing.
For ease of terminology, the "low-order" or "least significant" or "wrapping" half of multiplication will be called the low part, and the "high-order" or "most significant" or "overflowing" half of multiplication will be called the high part. In all cases, the return convention is `(low, high)` and left unchanged by this PR, to be litigated later.
## API Changes
The original API:
```rust
impl uN {
// computes self * rhs
pub const fn widening_mul(self, rhs: uN) -> (uN, uN);
// computes self * rhs + carry
pub const fn carrying_mul(self, rhs: uN, carry: uN) -> (uN, uN);
}
```
The added API:
```rust
impl uN {
// computes self * rhs + carry1 + carry2
pub const fn carrying2_mul(self, rhs: uN, carry: uN, add: uN) -> (uN, uN);
}
impl iN {
// note that the low part is unsigned
pub const fn widening_mul(self, rhs: iN) -> (uN, iN);
pub const fn carrying_mul(self, rhs: iN, carry: iN) -> (uN, iN);
pub const fn carrying_mul_add(self, rhs: iN, carry: iN, add: iN) -> (uN, iN);
}
```
Additionally, a naive implementation has been added for `u128` and `i128` since there are no double-wide types for those. Eventually, an intrinsic will be added to make these more efficient, but rather than doing this all at once, the library changes are added first.
## Justifications for API
The unsigned parts are done to ensure consistency with overflowing addition: for a two's complement integer, you want to have unsigned overflow semantics for all parts of the integer except the highest one. This is because overflow for unsigned integers happens on the highest bit (from `MAX` to zero), whereas overflow for signed integers happens on the second highest bit (from `MAX` to `MIN`). Since the sign information only matters in the highest part, we use unsigned overflow for everything but that part.
There is still discussion on the merits of signed bigint *addition* methods, since getting the behaviour right is very subtle, but at least for signed bigint *multiplication*, the sign of the operands does make a difference. So, it feels appropriate that at least until we've nailed down the final API, there should be an option to do signed versions of these methods.
Additionally, while it's unclear whether we need all three versions of bigint multiplication (widening, carrying-1, and carrying-2), since it's possible to have up to two carries without overflow, there should at least be a method to allow that. We could potentially only offer the carry-2 method and expect that adding zero carries afterword will optimise correctly, but again, this can be litigated before stabilisation.
## Note on documentation
While a lot of care was put into the documentation for the `widening_mul` and `carrying_mul` methods on unsigned integers, I have not taken this same care for `carrying_mul_add` or the signed versions. While I have updated the doc tests to be more appropriate, there will likely be many documentation changes done before stabilisation.
## Note on tests
Alongside this change, I've added several tests to ensure that these methods work as expected. These are alongside the codegen tests for the intrinsics.
stabilize const_swap
libs-api FCP passed in https://github.com/rust-lang/rust/issues/83163.
However, I only just realized that this actually involves an intrinsic. The intrinsic could be implemented entirely with existing stable const functionality, but we choose to make it a primitive to be able to detect more UB. So nominating for `@rust-lang/lang` to make sure they are aware; I leave it up to them whether they want to FCP this.
While at it I also renamed the intrinsic to make the "nonoverlapping" constraint more clear.
Fixes#83163
core: fix const ptr::swap_nonoverlapping when there are pointers at odd offsets
Ensure that the pointer gets swapped correctly even if it is not stored at an aligned offset. This rules out implementations that copy things in a `usize` loop -- so our implementation needs to be adjusted to avoid such a loop when running in const context.
Part of https://github.com/rust-lang/rust/issues/133668
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.
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~~
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
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.
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.
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>,
}
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`.
remove const-support for align_offset and is_aligned
As part of the recent discussion to stabilize `ptr.is_null()` in const context, the general vibe was that it's okay for a const function to panic when the same operation would work at runtime (that's just a case of "dynamically detecting that something is not supported as a const operation"), but it is *not* okay for a const function to just return a different result.
Following that, `is_aligned` and `is_aligned_to` have their const status revoked in this PR, since they do return actively wrong results at const time. In the future we can consider having a new intrinsic or so that can check whether a pointer is "guaranteed to be aligned", but the current implementation based on `align_offset` does not have the behavior we want.
In fact `align_offset` itself behaves quite strangely in const, and that support needs a bunch of special hacks. That doesn't seem worth it. Instead, the users that can fall back to a different implementation should just use const_eval_select directly, and everything else should not be made const-callable. So this PR does exactly that, and entirely removes const support for align_offset.
Closes some tracking issues by removing the associated features:
Closes https://github.com/rust-lang/rust/issues/90962
Closes https://github.com/rust-lang/rust/issues/104203
Cc `@rust-lang/wg-const-eval` `@rust-lang/libs-api`
Operations like is_aligned would return actively wrong results at compile-time,
i.e. calling it on the same pointer at compiletime and runtime could yield
different results. That's no good.
Instead of having hacks to make align_offset kind-of work in const-eval, just
use const_eval_select in the few places where it makes sense, which also ensures
those places are all aware they need to make sure the fallback behavior is
consistent.
better test for const HashMap; remove const_hash leftovers
The existing `const_with_hasher` test is kind of silly since the HashMap it constructs can never contain any elements. So this adjusts the test to construct a usable HashMap, which is a bit non-trivial since the default hash builder cannot be built in `const`. `BuildHasherDefault::new()` helps but is unstable (https://github.com/rust-lang/rust/issues/123197), so we also have a test that does not involve that type.
The second commit removes the last remnants of https://github.com/rust-lang/rust/issues/104061, since they aren't actually useful -- without const traits, you can't do any hashing in `const`.
Cc ``@rust-lang/libs-api`` ``@rust-lang/wg-const-eval``
Closes#104061
Related to https://github.com/rust-lang/rust/issues/102575
Add LowerExp and UpperExp implementations to NonZero
Adds `LowerExp` and `UpperExp` trait implementations to `NonZero`, as discussed in rust-lang/libs-team#458.
I had to modify the macro to mark the new impls with a different rust version. Let me know if this is the right way to do it (first timer here!)
Instead of towards negative infinity as is currently the case.
This done so that the obvious expectations of
`midpoint(a, b) == midpoint(b, a)` and
`midpoint(-a, -b) == -midpoint(a, b)` are true, which makes the even
more obvious implementation `(a + b) / 2` true.
https://github.com/rust-lang/rust/issues/110840#issuecomment-2336753931
Const stability checks v2
The const stability system has served us well ever since `const fn` were first stabilized. It's main feature is that it enforces *recursive* validity -- a stable const fn cannot internally make use of unstable const features without an explicit marker in the form of `#[rustc_allow_const_fn_unstable]`. This is done to make sure that we don't accidentally expose unstable const features on stable in a way that would be hard to take back. As part of this, it is enforced that a `#[rustc_const_stable]` can only call `#[rustc_const_stable]` functions. However, some problems have been coming up with increased usage:
- It is baffling that we have to mark private or even unstable functions as `#[rustc_const_stable]` when they are used as helpers in regular stable `const fn`, and often people will rather add `#[rustc_allow_const_fn_unstable]` instead which was not our intention.
- The system has several gaping holes: a private `const fn` without stability attributes whose inherited stability (walking up parent modules) is `#[stable]` is allowed to call *arbitrary* unstable const operations, but can itself be called from stable `const fn`. Similarly, `#[allow_internal_unstable]` on a macro completely bypasses the recursive nature of the check.
Fundamentally, the problem is that we have *three* disjoint categories of functions, and not enough attributes to distinguish them:
1. const-stable functions
2. private/unstable functions that are meant to be callable from const-stable functions
3. functions that can make use of unstable const features
Functions in the first two categories cannot use unstable const features and they can only call functions from the first two categories.
This PR implements the following system:
- `#[rustc_const_stable]` puts functions in the first category. It may only be applied to `#[stable]` functions.
- `#[rustc_const_unstable]` by default puts functions in the third category. The new attribute `#[rustc_const_stable_indirect]` can be added to such a function to move it into the second category.
- `const fn` without a const stability marker are in the second category if they are still unstable. They automatically inherit the feature gate for regular calls, it can now also be used for const-calls.
Also, all the holes mentioned above have been closed. There's still one potential hole that is hard to avoid, which is when MIR building automatically inserts calls to a particular function in stable functions -- which happens in the panic machinery. Those need to be manually marked `#[rustc_const_stable_indirect]` to be sure they follow recursive const stability. But that's a fairly rare and special case so IMO it's fine.
The net effect of this is that a `#[unstable]` or unmarked function can be constified simply by marking it as `const fn`, and it will then be const-callable from stable `const fn` and subject to recursive const stability requirements. If it is publicly reachable (which implies it cannot be unmarked), it will be const-unstable under the same feature gate. Only if the function ever becomes `#[stable]` does it need a `#[rustc_const_unstable]` or `#[rustc_const_stable]` marker to decide if this should also imply const-stability.
Adding `#[rustc_const_unstable]` is only needed for (a) functions that need to use unstable const lang features (including intrinsics), or (b) `#[stable]` functions that are not yet intended to be const-stable. Adding `#[rustc_const_stable]` is only needed for functions that are actually meant to be directly callable from stable const code. `#[rustc_const_stable_indirect]` is used to mark intrinsics as const-callable and for `#[rustc_const_unstable]` functions that are actually called from other, exposed-on-stable `const fn`. No other attributes are required.
Also see the updated dev-guide at https://github.com/rust-lang/rustc-dev-guide/pull/2098.
I think in the future we may want to tweak this further, so that in the hopefully common case where a public function's const-stability just exactly mirrors its regular stability, we never have to add any attribute. But right now, once the function is stable this requires `#[rustc_const_stable]`.
### Open question
There is one point I could see we might want to do differently, and that is putting `#[rustc_const_unstable]` functions (but not intrinsics) in category 2 by default, and requiring an extra attribute for `#[rustc_const_not_exposed_on_stable]` or so. This would require a bunch of extra annotations, but would have the advantage that turning a `#[rustc_const_unstable]` into `#[rustc_const_stable]` will never change the way the function is const-checked. Currently, we often discover in the const stabilization PR that a function needs some other unstable const things, and then we rush to quickly deal with that. In this alternative universe, we'd work towards getting rid of the `rustc_const_not_exposed_on_stable` before stabilization, and once that is done stabilization becomes a trivial matter. `#[rustc_const_stable_indirect]` would then only be used for intrinsics.
I think I like this idea, but might want to do it in a follow-up PR, as it will need a whole bunch of annotations in the standard library. Also, we probably want to convert all const intrinsics to the "new" form (`#[rustc_intrinsic]` instead of an `extern` block) before doing this to avoid having to deal with two different ways of declaring intrinsics.
Cc `@rust-lang/wg-const-eval` `@rust-lang/libs-api`
Part of https://github.com/rust-lang/rust/issues/129815 (but not finished since this is not yet sufficient to safely let us expose `const fn` from hashbrown)
Fixes https://github.com/rust-lang/rust/issues/131073 by making it so that const-stable functions are always stable
try-job: test-various