Revert const hacks and use const closures in std
This revealed some smaller bugs in stability checking that I fixed where needed:
* const closures use the const stability of their parent
* trait method default bodies use the const stability of their trait
Otherwise trivial reverts of the const hacks that were added
fixesrust-lang/rust#155781
Relax `T: Sized` bound on `try_as_dyn` / `try_as_dyn_mut`
`trait_info_of` already returns `None` for unsized types, so allowing `T: ?Sized` is sound and lets callers in generic contexts use these functions without a separate `Sized` bound. For unsized `T`, the function always returns `None`.
Tracking issue: rust-lang/rust#144361
## Motivation
Currently, it is not possible to use `try_as_dyn` as "specialization-like" dispatch in
blanket impls with `?Sized` type.
```rust
// Cannot add ?Sized now.
impl<T: 'static /* + ?Sized */, S: Serializer + 'static> Serialize<S> for T {
fn serialize(&self, serializer: &mut S) -> Result<S::Ok, S::Error> {
if let Some(spec) = try_as_dyn::<_, dyn SpecializedSer<S>>(self) {
spec.specialized_serialize(serializer)
} else {
// fall back to compile-time reflection via TypeId
...
}
}
}
```
Remove unnecessary `get_unchecked`
My benchmarking did not show any issue with using the safe method instead so I assume this isn't an issue any more. But let's do a perf run to be sure.
`trait_info_of` already returns `None` for unsized types, so allowing
`T: ?Sized` is sound and lets callers in generic contexts use these
functions without a separate `Sized` bound. For unsized `T`, the
function always returns `None`.
c-variadic: more precise compatibility check in const-eval
tracking issue: https://github.com/rust-lang/rust/issues/44930
This came up in the stabilization report discussion https://github.com/rust-lang/rust/pull/155697#discussion_r3139778447.
As a reminder, this is what C says (in section 7.16.1.1 of the [C23 standard](https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf#page=302).
> If type is not compatible with the type of the actual next argument (as promoted according to the default argument promotions), the behavior is undefined, except for the following cases:
>
> - both types are pointers to qualified or unqualified versions of compatible types;
> - one type is compatible with a signed integer type, the other type is compatible with the
> corresponding unsigned integer type, and the value is representable in both types;
> - one type is pointer to qualified or unqualified void and the other is a pointer to a qualified or
> unqualified character type;
> - or, the type of the next argument is `nullptr_t` and type is a pointer type that has the same representation and alignment requirements as a pointer to a character type
I think the last rule is not relevant for us, we don't really have an equivalent of `nullptr_t` as far as I know.
r? RalfJung
cc @tgross35
fix: ✏️ forgot to change the stable version for `assert_matches!` macro.
The `assert_matches` macro was delayed because of rust-lang/rust#154406 and the `#[stable(since)]` wasn't changed to the next version.
Document that CFI diverges from Rust wrt. ABI-compatibility rules
The CFI sanitizer is a sanitizer that checks that no ABI-incompatible function calls are made at runtime, but there is currently an unfortunate divergence between the Rust ABI-compatibility rules and what the CFI sanitizer checks. Thus, document that this divergence exists.
There are proposals for how we can align the ABI rules to eliminate this discrepancy, and I would like to follow through with those, but for now I think we can at least document that the discrepancy exists.
For further discussion please see [Re-evaluate ABI compatibility rules in light of CFI](https://github.com/rust-lang/unsafe-code-guidelines/issues/489) and [Can CFI be made compatible with type erasure schemes?](https://github.com/rust-lang/rust/issues/128728) and [`fn_cast!` macro](https://github.com/rust-lang/rust/issues/140803).
cc @rcvalle @samitolvanen @maurer @bjorn3 @RalfJung
Rendered:
<img width="956" height="391" alt="image" src="https://github.com/user-attachments/assets/410d3eaa-9476-4800-9ef8-bbb100a100c5" />
My benchmarking did not show any issue with using the safe method instead so I assume this isn't an issue any more. But let's do a perf run to be sure.
Implement more traits for FRTs
From https://github.com/rust-lang/rust/pull/154927#discussion_r3068460955.
FRTs now implement the following traits: `Sized + Freeze + RefUnwindSafe + Send + Sync + Unpin + UnsafeUnpin + UnwindSafe + Copy + Debug + Default + Eq + Hash + Ord`.
Let me know if there is any trait missing.
I also removed the explicit `Send` and `Sync` impls, since commit cb37ee2c87 ("make field representing types invariant over the base type") made the auto-trait impl work even if `T: !Send` or `T: !Sync`. Very happy to see unsafe impls get dropped :)
Note that I used the reflection feature (cc @oli-obk) to print the actual field names in the debug implementation. I think this is a cool way to use it, but if it isn't ready for that, I'm happy to change it to the alternative implementation I gave in the note comment (it's essentially Mark's suggestion but printing `T`'s name instead of `Self`'s).
Since this is a library change, I'll give this to Mark; feel free to also take a look/leave comments, Oli :)
r? @Mark-Simulacrum
These changes were made falsely assuming documentation links from `core` to `std` were not possible. Since it is possible, we can restore the documentation to its original form prior to the `core::io` move.
Move `std::io::RawOsError` to `core::io`
ACP: https://github.com/rust-lang/libs-team/issues/755
Tracking issue: https://github.com/rust-lang/rust/issues/154046
Related: https://github.com/rust-lang/rust/pull/154654
## Description
As a part of moving components of `std::io` into `alloc::io` and `core::io`, there will need to be a new home for the type `RawOsError`. In this PR, I propose moving it to `core::io`, and removing it from `std::sys`. I suspect this will be quite controversial as it is a platform dependent type, but this is not the only instance of a type being conditioned on `target_os` in `core` (e.g., `core::os` and `core::ffi`).
Since `RawOsError` is currently unstable, I think it's reasonable to make this move now, and worry about making it platform independent if/when it is stabilized (e.g., replacing it with a wrapper around `isize` on all platforms).
---
## Notes
* No AI tooling of any kind was used during the creation of this PR.
Add intrinsic for launch-sized workgroup memory on GPUs
Workgroup memory is a memory region that is shared between all
threads in a workgroup on GPUs. Workgroup memory can be allocated
statically or after compilation, when launching a gpu-kernel.
The intrinsic added here returns the pointer to the memory that is
allocated at launch-time.
# Interface
With this change, workgroup memory can be accessed in Rust by
calling the new `gpu_launch_sized_workgroup_mem<T>() -> *mut T`
intrinsic.
It returns the pointer to workgroup memory guaranteeing that it is
aligned to at least the alignment of `T`.
The pointer is dereferencable for the size specified when launching the
current gpu-kernel (which may be the size of `T` but can also be larger
or smaller or zero).
All calls to this intrinsic return a pointer to the same address.
See the intrinsic documentation for more details.
## Alternative Interfaces
It was also considered to expose dynamic workgroup memory as extern
static variables in Rust, like they are represented in LLVM IR.
However, due to the pointer not being guaranteed to be dereferencable
(that depends on the allocated size at runtime), such a global must be
zero-sized, which makes global variables a bad fit.
# Implementation Details
Workgroup memory in amdgpu and nvptx lives in address space 3.
Workgroup memory from a launch is implemented by creating an
external global variable in address space 3. The global is declared with
size 0, as the actual size is only known at runtime. It is defined
behavior in LLVM to access an external global outside the defined size.
There is no similar way to get the allocated size of launch-sized
workgroup memory on amdgpu an nvptx, so users have to pass this
out-of-band or rely on target specific ways for now.
Tracking issue: rust-lang/rust#135516
Workgroup memory is a memory region that is shared between all
threads in a workgroup on GPUs. Workgroup memory can be allocated
statically or after compilation, when launching a gpu-kernel.
The intrinsic added here returns the pointer to the memory that is
allocated at launch-time.
# Interface
With this change, workgroup memory can be accessed in Rust by
calling the new `gpu_launch_sized_workgroup_mem<T>() -> *mut T`
intrinsic.
It returns the pointer to workgroup memory guaranteeing that it is
aligned to at least the alignment of `T`.
The pointer is dereferencable for the size specified when launching the
current gpu-kernel (which may be the size of `T` but can also be larger
or smaller or zero).
All calls to this intrinsic return a pointer to the same address.
See the intrinsic documentation for more details.
## Alternative Interfaces
It was also considered to expose dynamic workgroup memory as extern
static variables in Rust, like they are represented in LLVM IR.
However, due to the pointer not being guaranteed to be dereferencable
(that depends on the allocated size at runtime), such a global must be
zero-sized, which makes global variables a bad fit.
# Implementation Details
Workgroup memory in amdgpu and nvptx lives in address space 3.
Workgroup memory from a launch is implemented by creating an
external global variable in address space 3. The global is declared with
size 0, as the actual size is only known at runtime. It is defined
behavior in LLVM to access an external global outside the defined size.
There is no similar way to get the allocated size of launch-sized
workgroup memory on amdgpu an nvptx, so users have to pass this
out-of-band or rely on target specific ways for now.
Improved assumptions relating to isqrt
Improved various assumptions relating to values yielded by `isqrt`.
Does not solve but does improve rust-lang/rust#132763.
Re-openeing of rust-lang/rust#154115
Added assumptions are:
* if `x` is nonzero then `x.isqrt()` is nonzero
* `x.isqrt() <= x`
* `x.isqrt() * x.isqrt() <= x`
Document precision considerations of `Duration`-float methods
A `Duration` is essentially a 94-bit value (64-bit sec and ~30-bit ns),
so there's some inherent loss when converting to floating-point for
`mul_f64` and `div_f64`. We could go to greater lengths to compute these
with more accuracy, like rust-lang/rust#150933 or rust-lang/rust#154107,
but it's not clear that it's worth the effort. The least we can do is
document that some rounding is to be expected, which this commit does
with simple examples that only multiply or divide by `1.0`.
This also changes the `f32` methods to just forward to `f64`, so we keep
more of that duration precision, as the range is otherwise much more
limited there.
Using the reflection experiment, we can print the actual names of the
field that an FRT is referring to. In case this breaks, there is an
alternative implementation in the note comment.
Commit cb37ee2c87 ("make field representing types invariant over the
base type") made the auto-trait impl work even if `T: !Send` or `T:
!Sync` thus we can remove these explicit unsafe impls while FRTs still
implement `Send` and `Sync`.