`MaybeUninit`: use `assume_init_drop()` in the partially initialized array example
The `assume_init_drop()` method does the same thing as the pointer conversion, and makes the example more straightforward.
kmc-solid: Handle errors returned by `SOLID_FS_ReadDir`
Fixes the issue where the `std::fs::ReadDir` implementaton of the [`*-kmc-solid_*`](https://doc.rust-lang.org/nightly/rustc/platform-support/kmc-solid.html) Tier 3 targets silently suppressed errors returned by the underlying `SOLID_FS_ReadDir` system function. The new implementation correctly handles all cases:
- `SOLID_ERR_NOTFOUND` indicates the end of directory stream.
- `SOLID_ERR_OK` + non-empty `d_name` indicates success.
- Some old filesystem drivers may return `SOLID_ERR_OK` + empty `d_name` to indicate the end of directory stream.
- Any other negative values (per ITRON convention) represent an error.
Document surprising and dangerous fs::Permissions behaviour on Unix
This documents the very surprising behaviour that `set_readonly(false)` will make a file *world writable* on Unix. I would go so far as to say that this function should be deprecated on Unix, or maybe even entirely. But documenting the bad behaviour is a good first step.
Fixes#74895
Clarify `array::from_fn` documentation
I've seen quite a few of people on social media confused of where the length of array is coming from in the newly stabilized `array::from_fn` example.
This PR tries to clarify the documentation on this.
Eliminate 280-byte memset from ReadDir iterator
This guy:
1536ab1b38/library/std/src/sys/unix/fs.rs (L589)
It turns out `libc::dirent64` is quite big—https://docs.rs/libc/0.2.135/libc/struct.dirent64.html. In #103135 this memset accounted for 0.9% of the runtime of iterating a big directory.
Almost none of the big zeroed value is ever used. We memcpy a tiny prefix (19 bytes) into it, and then read just 9 bytes (`d_ino` and `d_type`) back out. We can read exactly those 9 bytes we need directly from the original entry_ptr instead.
## History
This code got added in #93459 and tweaked in #94272 and #94750.
Prior to #93459, there was no memset but a full 280 bytes were being copied from the entry_ptr.
<table><tr><td>copy 280 bytes</td></tr></table>
This was not legal because not all of those bytes might be initialized, or even allocated, depending on the length of the directory entry's name, leading to a segfault. That PR fixed the segfault by creating a new zeroed dirent64 and copying just the guaranteed initialized prefix into it.
<table><tr><td>memset 280 bytes</td><td>copy 19 bytes</td></tr></table>
However this was still buggy because it used `addr_of!((*entry_ptr).d_name)`, which is considered UB by Miri in the case that the full extent of entry_ptr is not in bounds of the same allocation. (Arguably this shouldn't be a requirement, but here we are.)
The UB got fixed by #94272 by replacing `addr_of` with some pointer manipulation based on `offset_from`, but still fundamentally the same operation.
<table><tr><td>memset 280 bytes</td><td>copy 19 bytes</td></tr></table>
Then #94750 noticed that only 9 of those 19 bytes were even being used, so we could pick out only those 9 to put in the ReadDir value.
<table><tr><td>memset 280 bytes</td><td>copy 19 bytes</td><td>copy 9 bytes</td></tr></table>
After my PR we just grab the 9 needed bytes directly from entry_ptr.
<table><tr><td>copy 9 bytes</td></tr></table>
The resulting code is more complex but I believe still worthwhile to land for the following reason. This is an extremely straightforward thing to accomplish in C and clearly libc assumes that; literally just `entry_ptr->d_name`. The extra work in comparison to accomplish it in Rust is not an example of any actual safety being provided by Rust. I believe it's useful to have uncovered that and think about what could be done in the standard library or language to support this obvious operation better.
## References
- https://man7.org/linux/man-pages/man3/readdir.3.html
Reduce false positives in msys2 detection
Currently msys2 will be detected by getting the file path and looking to see if it contains the substrings "msys-" and "-ptr" (or "cygwin-" and "-pty"). This risks false positives, especially with filesystem files and if `GetFileInformationByHandleEx` returns a [full path](https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntifs/nf-ntifs-ntqueryinformationfile#remarks).
This PR adds a check to see if the handle is a pipe before doing the substring search. Additionally, for "msys2-" or "cygwin-" it only checks if the file name starts with the substring rather than looking at the whole path.
Adjust argument type for mutable with_metadata_of (#75091)
The method takes two pointer arguments: one `self` supplying the pointer value, and a second pointer supplying the metadata.
The new parameter type more clearly reflects the actual requirements. The provenance of the metadata parameter is disregarded completely. Using a mutable pointer in the call site can be coerced to a const pointer while the reverse is not true.
In some cases, the current parameter type can thus lead to a very slightly confusing additional cast. [Example](cad93775eb).
```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;
let ptr = val as *const _ as *mut T;
let ptr = uninit.as_ptr().with_metadata_of(ptr);
```
This could then instead be simplified to:
```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;
let ptr = uninit.as_ptr().with_metadata_of(&**val);
```
Tracking issue: https://github.com/rust-lang/rust/issues/75091
``@dtolnay`` you're reviewed #95249, would you mind chiming in?
These targets have system limits on the thread names, 16 and 64 bytes
respectively, and `pthread_setname_np` returns an error if the name is
longer. However, we're not in a context that can propagate errors when
we call this, and we used to implicitly truncate on Linux with `prctl`,
so now we manually truncate these names ahead of time.
Rollup of 9 pull requests
Successful merges:
- #102635 (make `order_dependent_trait_objects` show up in future-breakage reports)
- #103335 (Replaced wrong test with the correct mcve)
- #103339 (Fix some typos)
- #103340 (WinConsole::new is not actually fallible)
- #103341 (Add test for issue 97607)
- #103351 (Require Drop impls to have the same constness on its bounds as the bounds on the struct have)
- #103359 (Remove incorrect comment in `Vec::drain`)
- #103364 (rustdoc: clean up rustdoc-toggle CSS)
- #103370 (rustdoc: remove unused CSS `.out-of-band { font-weight: normal }`)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Remove incorrect comment in `Vec::drain`
r? ``@scottmcm``
Turns out this comment wasn't correct for 6 years, since #34951, which switched from using `slice::IterMut` into using `slice::Iter`.
Add default trait implementations for "c-unwind" ABI function pointers
Following up on #92964, only add default trait implementations for the `c-unwind` family of function pointers. The previous attempt in #92964 added trait implementations for many more ABIs and ran into concerns regarding the increase in size of the libcore rlib.
An attempt to abstract away function pointer types behind a unified trait to reduce the duplication of trait impls is being discussed in #99531 but this change looks to be blocked on a lang MCP.
Following `@RalfJung's` suggestion in https://github.com/rust-lang/rust/pull/99531#issuecomment-1233440142, this commit is another cut at #92964 but it _only_ adds the impls for `extern "C-unwind" fn` and `unsafe extern "C-unwind" fn`.
I am interested in landing this patch to unblock the stabilization of the `c_unwind` feature.
RFC: https://github.com/rust-lang/rfcs/pull/2945
Tracking Issue: https://github.com/rust-lang/rust/issues/74990
Change process spawning to inherit the parent's signal mask by default
Previously, the signal mask was always reset when a child process is
started. This breaks tools like `nohup` which expect `SIGHUP` to be
blocked for all transitive processes.
With this change, the default behavior changes to inherit the signal mask.
This also changes the signal disposition for `SIGPIPE` to only be changed if the `#[unix_sigpipe]` attribute isn't set.
The method takes two pointer arguments: one `self` supplying the pointer
value, and a second pointer supplying the metadata.
The new parameter type more clearly reflects the actual requirements.
The provenance of the metadata parameter is disregarded completely.
Using a mutable pointer in the call site can be coerced to a const
pointer while the reverse is not true.
An example of the current use:
```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;
let ptr = val as *const _ as *mut T;
let ptr = uninit.as_ptr().with_metadata_of(ptr);
```
This could then instead be simplified to:
```rust
// Manually taking an unsized object from a `ManuallyDrop` into another allocation.
let val: &core::mem::ManuallyDrop<T> = …;
let ptr = uninit.as_ptr().with_metadata_of(&**val);
```
Mark `std::os::wasi::io::AsFd` etc. as stable.
io_safety was stabilized in Rust 1.63, so mark the io_safety exports in `std::os::wasi::io` as stable.
Fixes#103306.
Previously, the signal mask is always reset when a child process is
started. This breaks tools like `nohup` which expect `SIGHUP` to be
blocked.
With this change, the default behavior changes to inherit the signal mask.
This also changes the signal disposition for `SIGPIPE` to only be
changed if the `#[unix_sigpipe]` attribute isn't set.
Fixed docs typo in `library/std/src/time.rs`
* Changed comment from `Previous rust versions panicked when self was earlier than the current time.` to `Previous rust versions panicked when the current time was earlier than self.`
* Resolves#103282.
Adjust `transmute{,_copy}` to be clearer about which of `T` and `U` is input vs output
This is essentially a documentation-only change (although it does touch code in an irrelevant way).
Following up on #92964, only add default trait implementations for the
`c-unwind` family of function pointers. The previous attempt in #92964
added trait implementations for many more ABIs and ran into concerns
regarding the increase in size of the libcore rlib.
An attempt to abstract away function pointer types behind a unified
trait to reduce the duplication of trait impls is being discussed in #99531
but this change looks to be blocked on a lang MCP.
Following @RalfJung's suggestion in
https://github.com/rust-lang/rust/pull/99531#issuecomment-1233440142,
this commit is another cut at #92964 but it _only_ adds the impls for
`extern "C-unwind" fn` and `unsafe extern "C-unwind" fn`.
I am interested in landing this patch to unblock the stabilization of
the `c_unwind` feature.
RFC: https://github.com/rust-lang/rfcs/pull/2945
Tracking Issue: https://github.com/rust-lang/rust/issues/74990
Make transpose const and inline
r? `@scottmcm`
- These should have been const from the beginning since we're never going to do more than a transmute.
- Inline these always because that's what every other method in MaybeUninit which simply casts does. :) Ok, but a stronger justification is that because we're taking in arrays by `self`, not inlining would defeat the whole purpose of using `MaybeUninit` due to the copying.
Optimize `slice_iter.copied().next_chunk()`
```
OLD:
test iter::bench_copied_array_chunks ... bench: 371 ns/iter (+/- 7)
NEW:
test iter::bench_copied_array_chunks ... bench: 31 ns/iter (+/- 0)
```
The default `next_chunk` implementation suffers from having to assemble the array byte by byte via `next()`, checking the `Option<&T>` and then dereferencing `&T`. The specialization copies the chunk directly from the slice.
More slice::partition_point examples
After seeing the discussion of `binary_search` vs `partition_point` in #101999, I thought some more example code could be helpful.
doc: rewrite doc for uint::{carrying_add,borrowing_sub}
Reword the documentation for bigint helper methods `uint::{carrying_add,borrowing_sub}` (#85532).
The examples were also rewritten to demonstrate how the methods can be used in bignum arithmetic. No loops are used in the examples, but the variable names were chosen to include indices so that it is clear how this can be used in a loop if required.
Also, previously `carrying_add` had an example to say that if the input carry is false, the method is equivalent to `overflowing_add`. While the note was kept, the example was removed and an extra note was added to make sure this equivalence is not assumed for signed integers as well.
Remove the redundant `Some(try_opt!(..))` in `checked_pow`
The final return value doesn't need to be tried at all -- we can just
return the checked option directly. The optimizer can probably figure
this out anyway, but there's no need to make it work here.
Make diagnostic for unsatisfied `Termination` bounds more precise
Don't blindly emit a diagnostic claiming that “*`main` has an invalid return type*” if we encounter a type that should but doesn't implement `std::process::Termination` and isn't actually the return type of the program entry `main`.
Fixes#103052.
``@rustbot`` label A-diagnostics T-compiler T-libs
r? diagnostics
Add `Box<[T; N]>: TryFrom<Vec<T>>`
We have `[T; N]: TryFrom<Vec<T>>` (#76310) and `Box<[T; N]>: TryFrom<Box<[T]>>`, but not this combination.
`vec.into_boxed_slice().try_into()` isn't quite a replacement for this, as that'll reallocate unnecessarily in the error case.
**Insta-stable, so needs an FCP**
(I tried to make this work with `, A`, but that's disallowed because of `#[fundamental]` https://github.com/rust-lang/rust/issues/29635#issuecomment-1247598385)
The final return value doesn't need to be tried at all -- we can just
return the checked option directly. The optimizer can probably figure
this out anyway, but there's no need to make it work here.
Clarify the possible return values of `len_utf16`
`char::len_utf16` always return 1 or 2. Clarify this in the docs, in the same way as `char::len_utf8`.
Documentation BTreeMap::append's behavior for already existing keys
`BTreeMap::append` overwrites existing values with new ones. This commit adds explicit documentation for that.
Add documentation about the memory layout of `UnsafeCell<T>`
The documentation for `UnsafeCell<T>` currently does not make any promises about its memory layout. This PR adds this documentation, namely that the memory layout of `UnsafeCell<T>` is the same as the memory layout of its inner `T`.
# Use case
Without this layout promise, the following cast would not be legally possible:
```rust
fn example<T>(ptr: *mut T) -> *const UnsafeCell<T> {
ptr as *const UnsafeCell<T>
}
```
A use case where this can come up involves FFI. If Rust receives a pointer over a FFI boundary which provides shared read-write access (with some form of custom synchronization), and this pointer is managed by some Rust struct with lifetime `'a`, then it would greatly simplify its (internal) API and safety contract if a `&'a UnsafeCell<T>` can be created from a raw FFI pointer `*mut T`. A lot of safety checks can be done when receiving the pointer for the first time through FFI (non-nullness, alignment, initialize uninit bytes, etc.) and these properties can then be encoded into the `&UnsafeCell<T>` type. Without this documentation guarantee, this is not legal today outside of the standard library.
# Caveats
Casting in the opposite direction is still not valid, even with this documentation change:
```rust
fn example2<T>(ptr: &UnsafeCell<T>) -> &mut T {
let t = ptr as *const UnsafeCell<T> as *mut T;
unsafe { &mut *t }
}
```
This is because the only legal way to obtain a mutable pointer to the contents of the shared reference is through [`UnsafeCell::get`](https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html#method.get) and [`UnsafeCell::raw_get`](https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html#method.raw_get). Although there might be a desire to also make this legal at some point in the future, that part is outside the scope of this PR. Also see this relevant [Zulip thread](https://rust-lang.zulipchat.com/#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/transmuting.20.26.20-.3E.20.26mut).
# Alternatives
Instead of adding a new documentation promise, it's also possible to add a new method to `UnsafeCell<T>` with signature `pub fn from_ptr_bikeshed(ptr: *mut T) -> *const UnsafeCell<T>` which indirectly only allows one-way casting to `*const UnsafeCell<T>`.
std: use `sync::Mutex` for internal statics
Since `sync::Mutex` is now `const`-constructible, it can be used for internal statics, removing the need for `sys_common::StaticMutex`. This adds some extra allocations on platforms which need to box their mutexes (currently SGX and some UNIX), but these will become unnecessary with the lock improvements tracked in #93740.
I changed the program argument implementation on Hermit, it does not need `Mutex` but can use atomics like some UNIX systems (ping `@mkroening` `@stlankes).`
Use semaphores for thread parking on Apple platforms
Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, `pthread_cond_timedwait` uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since `unpark` does not need to wait for a lock to be released.
Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a [dispatch semaphore](https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc) instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.
Tested on macOS 12.5.
r? ``````@thomcc``````
Add `IsTerminal` trait to determine if a descriptor or handle is a terminal
The UNIX implementation uses `isatty`. The Windows implementation uses
the same logic the `atty` crate uses, including the hack needed to
detect msys terminals.
Implement this trait for `Stdin`/`Stdout`/`Stderr`/`File` on all
platforms. On Unix, implement it for `BorrowedFd`/`OwnedFd`. On Windows,
implement it for `BorrowedHandle`/`OwnedHandle`.
Based on https://github.com/rust-lang/rust/pull/91121
Co-authored-by: Matt Wilkinson <mattwilki17@gmail.com>
Rather than referencing a slice's pointer and then creating a new slice
with a longer length, offset from the base structure pointer instead.
This makes some choices of Rust semantics happier.
The UNIX and WASI implementations use `isatty`. The Windows
implementation uses the same logic the `atty` crate uses, including the
hack needed to detect msys terminals.
Implement this trait for `File` and for `Stdin`/`Stdout`/`Stderr` and
their locked counterparts on all platforms. On UNIX and WASI, implement
it for `BorrowedFd`/`OwnedFd`. On Windows, implement it for
`BorrowedHandle`/`OwnedHandle`.
Based on https://github.com/rust-lang/rust/pull/91121
Co-authored-by: Matt Wilkinson <mattwilki17@gmail.com>
Fix `Duration::{try_,}from_secs_f{32,64}(-0.0)`
Make `Duration::{try_,}from_secs_f{32,64}(-0.0)` return `Duration::ZERO` (as they did before #90247) instead of erroring/panicking.
I'll update this PR to remove the `#![feature(duration_checked_float)]` if #102271 is merged before this PR.
Tracking issue for `try_from_secs_f{32,64}`: #83400
sync thread_local key conditions exactly with what the macro uses
This makes the `cfg` in `mod.rs` syntactically the same as those in `local.rs`.
I don't think this should actually change anything, but seems better to be consistent?
I looked into this due to https://github.com/rust-lang/rust/issues/102549, but this PR would make it *less* likely that `__OsLocalKeyInner` is going to get provided, so this cannot help with that issue.
r? `@thomcc`
Detect and reject out-of-range integers in format string literals
Until now out-of-range integers in format string literals were silently ignored. They wrapped around to zero at usize::MAX, producing unexpected results.
When using debug builds of rustc, such integers in format string literals even cause an 'attempt to add with overflow' panic in rustc.
Fix this by producing an error diagnostic for integers in format string literals which do not fit into usize.
Fixes#102528
More dupe word typos
I only picked those changes (from the regex search) that I am pretty certain doesn't change meaning and is just a typo fix. Do correct me if any fix is undesirable and I can revert those. Thanks.
impl AsFd and AsRawFd for io::{Stdin, Stdout, Stderr}, not the sys versions
https://github.com/rust-lang/rust/pull/100892 implemented AsFd for the
sys versions, rather than for the public types. Change the
implementations to apply to the public types.
Rollup of 6 pull requests
Successful merges:
- #102765 (Suggest `==` to the first expr which has `ExprKind::Assign` kind)
- #102854 (openbsd: don't reallocate a guard page on the stack.)
- #102904 (Print return-position `impl Trait` in trait verbosely if `-Zverbose`)
- #102947 (Sort elaborated existential predicates in `object_ty_for_trait`)
- #102956 (Use `full_res` instead of `expect_full_res`)
- #102999 (Delay `is_intrinsic` query until after we've determined the callee is a function)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
openbsd: don't reallocate a guard page on the stack.
the kernel currently enforce that a stack is immutable. calling mmap(2) or mprotect(2) to change it will result in EPERM, which generate a panic!().
so just do like for Linux, and trust the kernel to do the right thing.
Optimize TLS on Windows
This implements the suggestion in the current TLS code to embed the linked list of destructors in the `StaticKey` structure to save allocations. Additionally, locking is avoided when no destructor needs to be run. By using one Windows-provided `Once` per key instead of a global lock, locking is more finely-grained (this unblocks #100579).
Allow compiling the `wasm32-wasi` std library with atomics
The issue #102157 demonstrates how currently the `-Z build-std` option will fail when re-compiling the standard library with `RUSTFLAGS` like `RUSTFLAGS="-C target-feature=+atomics,+bulk-memory -C link-args=--shared-memory"`. This change attempts to resolve those build issues by depending on the the WebAssembly `futex` module and providing an implementation for `env_lock`. Fixes#102157.
nicer errors from assert_unsafe_precondition
This makes the errors shown by cargo-careful nicer, and since `panic_no_unwind` is `nounwind noreturn` it hopefully doesn't have bad codegen impact. Thanks to `@bjorn3` for the hint!
Would be nice if we could somehow supply our own (static) message to print, currently it always prints `panic in a function that cannot unwind`. But still, this is better than before.
Prevent UB in child process after calling libc::fork
After calling libc::fork, the child process tried to access a TLS variable when processing a panic. This caused a memory allocation which is UB in the child.
To prevent this from happening, the panic handler will not access the TLS variable in case `panic::always_abort` was called before.
Fixes#85261 (not only on Android systems, but also on Linux/QNX with TLS disabled, see issue for more details)
Main drawbacks of this fix:
* Panic messages can incorrectly omit `core::panic::PanicInfo` struct in case several panics (of multiple threads) occur at the same time. The handler cannot distinguish between multiple panics in different threads or recursive ones in the same thread, but the message will contain a hint about the uncertainty.
* `panic_count::increase()` will be a bit slower as it has an additional `if`, but this should be irrelevant as it is only called in case of a panic.
Use memset to initialize readbuf
The write loop was found to be slow in #102727
The proper fix is in #102760 but this might still help debug builds and code running under miri by using the write_bytes intrinsic instead of writing one byte at a time.
Remove `TokenStreamBuilder`
`TokenStreamBuilder` is used to combine multiple token streams. It can be removed, leaving the code a little simpler and a little faster.
r? `@Aaron1011`
Interpret EH actions properly
The EH actions stored in the LSDA follows the format of GCC except table (even for LLVM-generated code). An missing action in the table is the encoding for `Terminate`, see https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/libsupc%2B%2B/eh_personality.cc#L522-L526.
The currently code interprets it as `None`, as a workaround for #35011, an issue that seems to occur in LLVM 3.7 and not after 3.9. These are very old versions of LLVM and we don't support them anymore, so remove this workaround and interpret them properly.
Note that LLVM currently does not emit any `Terminate` actions, but GCC does. Although GCC backend currently doesn't do unwinding, removing it preemptively would prevent future developers from wasting time to figure out what's wrong.
``@rustbot`` label: +T-compiler
fs::get_path solarish version.
similar to linux, albeit there is no /proc/self notion on solaris
based system thus flattening the difference for simplification sake.
Warn about safety of `fetch_update`
Specifically as it relates to the ABA problem.
`fetch_update` is a useful function, and one that isn't provided by, say, C++. However, this does not mean the function is magic. It is implemented in terms of `compare_exchange_weak`, and in particular, suffers from the ABA problem. See the following code, which is a naive implementation of `pop` in a lock-free queue:
```rust
fn pop(&self) -> Option<i32> {
self.front.fetch_update(Ordering::Relaxed, Ordering::Acquire, |front| {
if front == ptr::null_mut() {
None
}
else {
Some(unsafe { (*front).next })
}
}.ok()
}
```
This code is unsound if called from multiple threads because of the ABA problem. Specifically, suppose nodes are allocated with `Box`. Suppose the following sequence happens:
```
Initial: Queue is X -> Y.
Thread A: Starts popping, is pre-empted.
Thread B: Pops successfully, twice, leaving the queue empty.
Thread C: Pushes, and `Box` returns X (very common for allocators)
Thread A: Wakes up, sees the head is still X, and stores Y as the new head.
```
But `Y` is deallocated. This is undefined behaviour.
Adding a note about this problem to `fetch_update` should hopefully prevent users from being misled, and also, a link to this common problem is, in my opinion, an improvement to our docs on atomics.
scoped threads: pass closure through MaybeUninit to avoid invalid dangling references
The `main` function defined here looks roughly like this, if it were written as a more explicit stand-alone function:
```rust
// Not showing all the `'lifetime` tracking, the point is that
// this closure might live shorter than `thread`.
fn thread(control: ..., closure: impl FnOnce() + 'lifetime) {
closure();
control.signal_done();
// A lot of time can pass here.
}
```
Note that `thread` continues to run even after `signal_done`! Now consider what happens if the `closure` captures a reference of lifetime `'lifetime`:
- The type of `closure` is a struct (the implicit unnameable closure type) with a `&'lifetime mut T` field. References passed to a function are marked with `dereferenceable`, which is LLVM speak for *this reference will remain live for the entire duration of this function*.
- The closure runs, `signal_done` runs. Then -- potentially -- this thread gets scheduled away and the main thread runs, seeing the signal and returning to the user. Now `'lifetime` ends and the memory the reference points to might be deallocated.
- Now we have UB! The reference that as passed to `thread` with the promise of remaining live for the entire duration of the function, actually got deallocated while the function still runs. Oops.
Long-term I think we should be able to use `ManuallyDrop` to fix this without `unsafe`, or maybe a new `MaybeDangling` type. I am working on an RFC for that. But in the mean time it'd be nice to fix this so that Miri with `-Zmiri-retag-fields` (which is needed for "full enforcement" of all the LLVM flags we generate) stops erroring on scoped threads.
Fixes https://github.com/rust-lang/rust/issues/101983
r? `@m-ou-se`