Remove `finished` flag from `MapWhile`
This PR removes `finished` flag from `MapWhile` as been proposed in https://github.com/rust-lang/rust/pull/66577#discussion_r370958025.
This also resolves open questions of the tracking issue (#68537):
- `MapWhile` can't implement both
+ `DoubleEndedIterator` (discussed in https://github.com/rust-lang/rust/pull/66577#discussion_r370947990 and following comments)
+ `FusedIterator` (this pr removes `finished` flag, so `MapWhile` isn't fused anymore)
- Debug output (this pr removes `finished` flag, so there is no question in including it in debug output)
r? @Mark-Simulacrum
Derive PartialEq, Eq and Hash for RangeInclusive
The manual implementation of `PartialEq`, `Eq` and `Hash` for `RangeInclusive` was functionally equivalent to a derived implementation.
This change removes the manual implementation and adds the respective derives.
A side effect of this change is that the derives also add implementations for `StructuralPartialEq` and `StructuralEq`, which enables `RangeInclusive` to be used in const generics, closing #70155.
This change is enabled by #68835, which changed the field `is_empty: Option<bool>` to `exhausted: bool` removing the need for *semantic* equality instead of *structural* equality.
## PartialEq
original [`PartialEq`](f4c675c476/src/libcore/ops/range.rs (L353-L359)) implementation:
```rust
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: PartialEq> PartialEq for RangeInclusive<Idx> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.start == other.start && self.end == other.end && self.exhausted == other.exhausted
}
}
```
expanded derive implementation (using `cargo expand ops::range`):
```rust
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx> crate::marker::StructuralPartialEq for RangeInclusive<Idx> {}
#[automatically_derived]
#[allow(unused_qualifications)]
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: crate::cmp::PartialEq> crate::cmp::PartialEq for RangeInclusive<Idx> {
#[inline]
fn eq(&self, other: &RangeInclusive<Idx>) -> bool {
match *other {
RangeInclusive { start: ref __self_1_0,end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self {
RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => {
(*__self_0_0) == (*__self_1_0) && (*__self_0_1) == (*__self_1_1) && (*__self_0_2) == (*__self_1_2)
}
},
}
}
#[inline]
fn ne(&self, other: &RangeInclusive<Idx>) -> bool {
match *other {
RangeInclusive { start: ref __self_1_0, end: ref __self_1_1, exhausted: ref __self_1_2 } => match *self {
RangeInclusive { start: ref __self_0_0, end: ref __self_0_1exhausted: ref __self_0_2 } => {
(*__self_0_0) != (*__self_1_0) || (*__self_0_1) != (*__self_1_1) || (*__self_0_2) != (*__self_1_2)
}
},
}
}
}
```
These implementations both test for *structural* equality, with the same order of field comparisons, and the bound `Idx: PartialEq` is the same.
## Eq
original [`Eq`](f4c675c476/src/libcore/ops/range.rs (L361-L362)) implementation:
```rust
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: Eq> Eq for RangeInclusive<Idx> {}
```
expanded derive implementation (using `cargo expand ops::range`):
```rust
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx> crate::marker::StructuralEq for RangeInclusive<Idx> {}
#[automatically_derived]
#[allow(unused_qualifications)]
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: crate::cmp::Eq> crate::cmp::Eq for RangeInclusive<Idx> {
#[inline]
#[doc(hidden)]
fn assert_receiver_is_total_eq(&self) -> () {
{
let _: crate::cmp::AssertParamIsEq<Idx>;
let _: crate::cmp::AssertParamIsEq<Idx>;
let _: crate::cmp::AssertParamIsEq<bool>;
}
}
}
```
These implementations are equivalent since `Eq` is just a marker trait and the bound `Idx: Eq` is the same.
## Hash
original [`Hash`](f4c675c476/src/libcore/ops/range.rs (L364-L371)) implementation:
```rust
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: Hash> Hash for RangeInclusive<Idx> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.start.hash(state);
self.end.hash(state);
self.exhausted.hash(state);
}
}
```
expanded derive implementation (using `cargo expand ops::range`):
```rust
#[automatically_derived]
#[allow(unused_qualifications)]
#[stable(feature = "inclusive_range", since = "1.26.0")]
impl<Idx: crate:#️⃣:Hash> crate:#️⃣:Hash for RangeInclusive<Idx> {
fn hash<__H: crate:#️⃣:Hasher>(&self, state: &mut __H) -> () {
match *self { RangeInclusive { start: ref __self_0_0, end: ref __self_0_1, exhausted: ref __self_0_2 } => {
crate:#️⃣:Hash::hash(&(*__self_0_0), state);
crate:#️⃣:Hash::hash(&(*__self_0_1), state);
crate:#️⃣:Hash::hash(&(*__self_0_2), state)
}
}
}
}
```
These implementations are functionally equivalent, with the same order of field hashing, and the bound `Idx: Hash` is the same.
add `Option::{zip,zip_with}` methods under "option_zip" gate
This PR introduces 2 methods - `Option::zip` and `Option::zip_with` with
respective signatures:
- zip: `(Option<T>, Option<U>) -> Option<(T, U)>`
- zip_with: `(Option<T>, Option<U>, (T, U) -> R) -> Option<R>`
Both are under the feature gate "option_zip".
I'm not sure about the name "zip", maybe we can find a better name for this.
(I would prefer `union` for example, but this is a keyword :( )
--------------------------------------------------------------------------------
Recently in a russian rust begginers telegram chat a newbie asked (translated):
> Are there any methods for these conversions:
>
> 1. `(Option<A>, Option<B>) -> Option<(A, B)>`
> 2. `Vec<Option<T>> -> Option<Vec<T>>`
>
> ?
While second (2.) is clearly `vec.into_iter().collect::<Option<Vec<_>>()`, the
first one isn't that clear.
I couldn't find anything similar in the `core` and I've come to this solution:
```rust
let tuple: (Option<A>, Option<B>) = ...;
let res: Option<(A, B)> = tuple.0.and_then(|a| tuple.1.map(|b| (a, b)));
```
However this solution isn't "nice" (same for just `match`/`if let`), so I thought
that this functionality should be in `core`.
Use generator resume arguments in the async/await lowering
This removes the TLS requirement from async/await and enables it in `#![no_std]` crates.
Closes https://github.com/rust-lang/rust/issues/56974
I'm not confident the HIR lowering is completely correct, there seem to be quite a few undocumented invariants in there. The `async-std` and tokio test suites are passing with these changes though.
The manual implementation of PartialEq, Eq and Hash for RangeInclusive was functionally equivalent to a derived implementation.
This change removes the manual implementation and adds the respective derives.
A side effect of this change is that the derives also add implementations for StructuralPartialEq and StructuralEq, which enables RangeInclusive to be used in const generics.
As discussed on reddit, this commit addresses two issues with the
documentation of `mem::forget()`:
* The documentation of `mem::forget()` can confuse the reader because of the
discrepancy between usage examples that show correct usage and the
accompanying text which speaks of the possibility of double-free. The
text that says "if the panic occurs before `mem::forget` was called"
refers to a variant of the second example that was never shown, modified
to use `mem::forget` instead of `ManuallyDrop`. Ideally the documentation
should show both variants, so it's clear what it's talking about.
Also, the double free could be fixed just by placing `mem::forget(v)`
before the construction of `s`. Since the lifetimes of `s` and `v`
wouldn't overlap, there would be no point where panic could cause a double
free. This could be mentioned, and contrasted against the more robust fix
of using `ManuallyDrop`.
* This sentence seems unjustified: "For some types, operations such as
passing ownership (to a funcion like `mem::forget`) requires them to
actually be fully owned right now [...]". Unlike C++, Rust has no move
constructors, its moves are (possibly elided) bitwise copies. Even if you
pass an invalid object to `mem::forget`, no harm should come to pass
because `mem::forget` consumes the object and exists solely to prevent
drop, so there no one left to observe the invalid state state.
This commit introduces 2 methods - `Option::zip` and `Option::zip_with` with
respective signatures:
- zip: `(Option<T>, Option<U>) -> Option<(T, U)>`
- zip_with: `(Option<T>, Option<U>, (T, U) -> R) -> Option<R>`
Both are under the feature gate "option_zip".
I'm not sure about the name "zip", maybe we can find a better name for this.
(I would prefer `union` for example, but this is a keyword :( )
--------------------------------------------------------------------------------
Recently in a russian rust begginers telegram chat a newbie asked (translated):
> Are there any methods for these conversions:
>
> 1. `(Option<A>, Option<B>) -> Option<(A, B)>`
> 2. `Vec<Option<T>> -> Option<Vec<T>>`
>
> ?
While second (2.) is clearly `vec.into_iter().collect::<Option<Vec<_>>()`, the
first one isn't that clear.
I couldn't find anything similar in the `core` and I've come to this solution:
```rust
let tuple: (Option<A>, Option<B>) = ...;
let res: Option<(A, B)> = tuple.0.and_then(|a| tuple.1.map(|b| (a, b)));
```
However this solution isn't "nice" (same for just `match`/`if let`), so I thought
that this functionality should be in `core`.
Fix bugs in Peekable and Flatten when using non-fused iterators
I fixed a couple of bugs with regard to the `Peekable` and `Flatten`/`FlatMap` iterators when the underlying iterator isn't fused. For testing, I also added a `NonFused` iterator wrapper that panics when `next` or `next_back` is called on an iterator that has returned `None` before, which will hopefully make it easier to spot these mistakes in the future.
### Peekable
`Peekable::next_back` was implemented as
```rust
self.iter.next_back().or_else(|| self.peeked.take().and_then(|x| x))
```
which is incorrect because when the `peeked` field is `Some(None)`, then `None` has already been returned from the inner iterator and what it returns from `next_back` can no longer be relied upon. `test_peekable_non_fused` tests this.
### Flatten
When a `FlattenCompat` instance only has a `backiter` remaining (i.e. `self.frontiter` is `None` and `self.iter` is empty), then `next` will call `self.iter.next()` every time, so the `iter` field needs to be fused. I fixed it by giving it the type `Fuse<I>` instead of `I`, I think this is the only way to fix it. `test_flatten_non_fused_outer` tests this.
Furthermore, previously `FlattenCompat::next` did not set `self.frontiter` to `None` after it returned `None`, which is incorrect when the inner iterator type isn't fused. I just delegated it to `try_fold` because that already handles it correctly. `test_flatten_non_fused_inner` tests this.
r? @scottmcm
expand: Implement something similar to `#[cfg(accessible(path))]`
cc https://github.com/rust-lang/rust/issues/64797
The feature is implemented as a `#[cfg_accessible(path)]` attribute macro rather than as `#[cfg(accessible(path))]` because it needs to wait until `path` becomes resolvable, and `cfg` cannot wait, but macros can wait.
Later we can think about desugaring or not desugaring `#[cfg(accessible(path))]` into `#[cfg_accessible(path)]`.
This implementation is also incomplete in the sense that it never returns "false" from `cfg_accessible(path)`, it requires some tweaks to resolve, which is not quite ready to answer queries like this during early resolution.
However, the most important part of this PR is not `cfg_accessible` itself, but expansion infrastructure for retrying expansions.
Before this PR we could say "we cannot resolve this macro path, let's try it later", with this PR we can say "we cannot expand this macro, let's try it later" as well.
This is a pre-requisite for
- turning `#[derive(...)]` into a regular attribute macro,
- properly supporting eager expansion for macros that cannot yet be resolved like
```
fn main() {
println!(not_available_yet!());
}
macro_rules! make_available {
() => { #[macro_export] macro_rules! not_available_yet { () => { "Hello world!" } }}
}
make_available!();
```
Implement a feature for a sound specialization subset
This implements a new feature (`min_specialization`) that restricts specialization to a subset that is reasonable for the standard library to use.
The plan is to then:
* Update `libcore` and `liballoc` to compile with `min_specialization`.
* Add a lint to forbid use of `feature(specialization)` (and other unsound, type system extending features) in the standard library.
* Fix the soundness issues around `specialization`.
* Remove `min_specialization`
The rest of this is an overview from a comment in this PR
## Basic approach
To enforce this requirement on specializations we take the following approach:
1. Match up the substs for `impl2` so that the implemented trait and self-type match those for `impl1`.
2. Check for any direct use of `'static` in the substs of `impl2`.
3. Check that all of the generic parameters of `impl1` occur at most once in the *unconstrained* substs for `impl2`. A parameter is constrained if its value is completely determined by an associated type projection predicate.
4. Check that all predicates on `impl1` also exist on `impl2` (after matching substs).
## Example
Suppose we have the following always applicable impl:
```rust
impl<T> SpecExtend<T> for std::vec::IntoIter<T> { /* specialized impl */ }
impl<T, I: Iterator<Item=T>> SpecExtend<T> for I { /* default impl */ }
```
We get that the subst for `impl2` are `[T, std::vec::IntoIter<T>]`. `T` is constrained to be `<I as Iterator>::Item`, so we check only `std::vec::IntoIter<T>` for repeated parameters, which it doesn't have. The predicates of `impl1` are only `T: Sized`, which is also a predicate of impl2`. So this specialization is sound.
## Extensions
Unfortunately not all specializations in the standard library are allowed by this. So there are two extensions to these rules that allow specializing on some traits.
### rustc_specialization_trait
If a trait is always applicable, then it's sound to specialize on it. We check trait is always applicable in the same way as impls, except that step 4 is now "all predicates on `impl1` are always applicable". We require that `specialization` or `min_specialization` is enabled to implement these traits.
### rustc_specialization_marker
There are also some specialization on traits with no methods, including the `FusedIterator` trait which is advertised as allowing optimizations. We allow marking marker traits with an unstable attribute that means we ignore them in point 3 of the checks above. This is unsound but we allow it in the short term because it can't cause use after frees with purely safe code in the same way as specializing on traits methods can.
r? @nikomatsakis
cc #31844#67194
Add undo_leak to reset RefCell borrow state
This method is complementary for the feature cell_leak added in an
earlier PR. It allows *safely* reverting the effects of leaking a borrow guard by
statically proving that such a guard could not longer exist. This was
not added to the existing `get_mut` out of concern of impacting the
complexity of the otherwise pure pointer cast and because the name
`get_mut` poorly communicates the intent of resetting remaining borrows.
This is a follow-up to #68712 and uses the same tracking issue, #69099,
as these methods deal with the same mechanism and the idea came up
[in a review comment](https://github.com/rust-lang/rust/pull/68712#discussion_r384670041).
@dtolnay who reviewed the prior PR.
cc @RalfJung
Remove `sip::Hasher::short_write`.
`sip::Hasher::short_write` is currently unused. It is called by
`sip::Hasher::write_{u8,usize}`, but those methods are also unused,
because `DefaultHasher`, `SipHasher` and `SipHasher13` don't implement
any of the `write_xyz` methods, so all their write operations end up
calling `sip::Hasher::write`.
(I confirmed this by inserting a `panic!` in `sip::Hasher::short_write`
and running the tests -- they all passed.)
The alternative would be to add all the missing `write_xyz` methods.
This does give some significant speed-ups, but it hurts compile times a
little in some cases. See #69152 for details. This commit does the
conservative thing and doesn't change existing behaviour.
r? @rust-lang/libs
Optimize catch_unwind to match C++ try/catch
This refactors the implementation of catching unwinds to allow LLVM to inline the "try" closure directly into the happy path, avoiding indirection. This means that the catch_unwind implementation is (after this PR) zero-cost unless a panic is thrown.
https://rust.godbolt.org/z/cZcUSB is an example of the current codegen in a simple case. Notably, the codegen is *exactly the same* if `-Cpanic=abort` is passed, which is clearly not great.
This PR, on the other hand, generates the following assembly:
```asm
# -Cpanic=unwind:
push rbx
mov ebx,0x2a
call QWORD PTR [rip+0x1c53c] # <happy>
mov eax,ebx
pop rbx
ret
mov rdi,rax
call QWORD PTR [rip+0x1c537] # cleanup function call
call QWORD PTR [rip+0x1c539] # <unfortunate>
mov ebx,0xd
mov eax,ebx
pop rbx
ret
# -Cpanic=abort:
push rax
call QWORD PTR [rip+0x20a1] # <happy>
mov eax,0x2a
pop rcx
ret
```
Fixes#64224, and resolves#64222.