const-eval: always do mem-to-mem copies if there might be padding involved
This is the final piece of the puzzle for https://github.com/rust-lang/rust/issues/148470: when copying data of a type that has padding, always do a mem-to-mem copy, so that we always preserve the source padding exactly. That prevents rustc implementation choices from leaking into user-visible behavior.
This is technically a breaking change: the example at the top of https://github.com/rust-lang/rust/issues/148470 no longer compiles with this. However, it seems very unlikely that anyone would have depended on this. My main concern is not backwards compatibility, it is performance.
Fixesrust-lang/rust#148470
---
> Actually that seems to be entirely fine, it even helps with some benchmarks! I guess the mem-to-mem codepath is actually faster than the scalar pair codepath for the copy itself. It can slow things down later since now we have to do everything bytewise, but that doesn't show up in our benchmarks and might not be very relevant after all (in particular, it only affects types with padding, so the rather common wide pointers still always use the efficient scalar representation).
>
> So that would be my proposal to for resolving this issue then: to make const-eval behavior consistent, we always copy the padding from the source to the target. IOW, potentially pre-existing provenance in the target always gets overwritten (that part is already in https://github.com/rust-lang/rust/pull/148259), and potentially existing provenance in padding in the source always gets carried over (that's https://github.com/rust-lang/rust/pull/148967). If there's provenance elsewhere in the source our existing handling is fine:
> - If it's in an integer, that's UB during const-eval so we can do whatever.
> - If it's in a pointer, the the fragments must combine back together to a pointer or else we have UB.
> - If it's in a union we just carry it over unchanged.
>
> @traviscross we should check that this special const-eval-only UB is properly reflected in the reference. Currently we have [this](https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html#r-undefined.const-transmute-ptr2int) but that only talks about int2ptr, not about invalid pointer fragments at pointer type. I also wonder if this shouldn't rather be part of ["invalid values"](https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html#r-undefined.validity) to make it clear that this applies recursively inside fields as well.
> EDIT: Reference PR is up at https://github.com/rust-lang/reference/pull/2091.
_Originally posted by @RalfJung in [#148470](https://github.com/rust-lang/rust/issues/148470#issuecomment-3538447283)_
> Worth noting that this does not resolve the concerns @theemathas had about `-Zextra-const-ub-checks` sometimes causing *more* code to compile. Specifically, with that flag, the behavior changes to "potentially existing provenance in padding in the source never gets carried over". However, it's a nightly-only flag (used by Miri) so while the behavior is odd, I don't think this is a problem.
_Originally posted by @RalfJung in [#148470](https://github.com/rust-lang/rust/issues/148470#issuecomment-3538450164)_
---
Related:
- https://github.com/rust-lang/rust/issues/148470
- https://github.com/rust-lang/reference/pull/2091
add `simd_splat` intrinsic
Add `simd_splat` which lowers to the LLVM canonical splat sequence.
```llvm
insertelement <N x elem> poison, elem %x, i32 0
shufflevector <N x elem> v0, <N x elem> poison, <N x i32> zeroinitializer
```
Right now we try to fake it using one of
```rust
fn splat(x: u32) -> u32x8 {
u32x8::from_array([x; 8])
}
```
or (in `stdarch`)
```rust
fn splat(value: $elem_type) -> $name {
#[derive(Copy, Clone)]
#[repr(simd)]
struct JustOne([$elem_type; 1]);
let one = JustOne([value]);
// SAFETY: 0 is always in-bounds because we're shuffling
// a simd type with exactly one element.
unsafe { simd_shuffle!(one, one, [0; $len]) }
}
```
Both of these can confuse the LLVM optimizer, producing sub-par code. Some examples:
- https://github.com/rust-lang/rust/issues/60637
- https://github.com/rust-lang/rust/issues/137407
- https://github.com/rust-lang/rust/issues/122623
- https://github.com/rust-lang/rust/issues/97804
---
As far as I can tell there is no way to provide a fallback implementation for this intrinsic, because there is no `const` way of evaluating the number of elements (there might be issues beyond that, too). So, I added implementations for all 4 backends.
Both GCC and const-eval appear to have some issues with simd vectors containing pointers. I have a workaround for GCC, but haven't yet been able to make const-eval work. See the comments below.
Currently this just adds the intrinsic, it does not actually use it anywhere yet.
Handle unevaluated ConstKind in in_operand
fix: rust-lang/rust#151248
r? BoxyUwU
~~I can't reproduce rust-lang/rust#151246 in my local(x86_64-pc-windows-msvc) even before this change. 🤔
create a draft and test it in different environments.~~
Support pointers in type reflection
Tracking issue: rust-lang/rust#146922
This PR adds support for inspecting pointers `*const T` and `*mut T` through type reflection. It does so by adding the new `Pointer` struct + variant:
```rust
pub struct Pointer {
/// The type of the value being pointed to.
pub ty: TypeId,
/// Whether this pointer is mutable or not.
pub mutable: bool,
}
```
This can be gathered using `Type::of`, for example:
```rust
match const { Type::of::<*const u8>() }.kind {
TypeKind::Pointer(pointer) => {
assert_eq!(pointer.ty, TypeId::of::<u8>());
assert!(!pointer.mutable);
}
_ => unreachable!(),
}
```
Remove the diagnostic lints
Removes the `untranslatable_diagnostic` and `diagnostic_outside_of_impl` lints
These lints are allowed for a while already. Per https://github.com/rust-lang/compiler-team/issues/959, we no longer want to enforce struct diagnostics for all usecases, so this is no longer useful.
r? @Kivooeo
I recommend reviewing commit by commit (also feel free to wait with reviewing until the MCP is accepted)
@rustbot +S-blocked
Blocked by https://github.com/rust-lang/compiler-team/issues/959
Fix ICE: When Trying to check visibility of a #[type_const], check RHS instead.
This PR fixes https://github.com/rust-lang/rust/issues/150956 for min_const_generic_args https://github.com/rust-lang/rust/issues/132980.
The first part of this PR checks in `reachable.rs` if we have a type const use `visit_const_item_rhs(init);` instead of calling `const_eval_poly_to_alloc()`
The second part is I noticed that if `const_eval_poly_to_alloc()` returns a `ErrorHandled::TooGeneric` then switches to `visit_const_item_rhs()`. So further up `const_eval_poly_to_alloc()` call order it eventual gets to `eval_in_interpreter()`. So I added a debug_assert in `eval_in_interpreter()` if we happen to try and run CTFE on a `type_const`.
The other bit is just a test case, and some duplicated code I noticed.
While the PR does get rid of the ICE for a type_const with `pub` visibility. If I try using the const though it will ICE with the following:
```
error: internal compiler error: /home/keith/GitHub/rust_kc/compiler/rustc_const_eval/src/check_consts/qualifs.rs:355:13: expected ConstKind::Param or ConstKind::Value here, found UnevaluatedConst { def: DefId(20:4 ~ colorkit[c783]::TYPE_CONST), args: [] }
thread 'rustc' (819687) panicked at /home/keith/GitHub/rust_kc/compiler/rustc_const_eval/src/check_consts/qualifs.rs:355:13:
```
I suspect it is a similar issue to inherent associated consts. Since if I apply the same fix I had here:
https://github.com/rust-lang/rust/pull/150799#discussion_r2676504639
I then can use the const internally and in external crates without any issues.
Although, did not include that fix since if it is a similar issue it would need to be addressed elsewhere.
r? @BoxyUwU
@rustbot label +F-associated_const_equality +F-min_generic_const_args
We want to evaluate the rhs of a type_const.
Also added an early return/guard in eval_in_interpreter which is used in functions like `eval_to_allocation_raw_provider`
Lastly add a debug assert to `thir_body()` if we have gotten there with a type_const something as gone wrong.
Get rid of a call to is_type_const() and instead use a match arm.
Change this is_type_const() check to a debug_assert!()
Change to use an if else statment instead.
Update type_const-pub.rs
Fix formatting.
Noticed that this is the same check as is_type_const() centralize it.
Add test case for pub type_const.
Support primitives in type info reflection
Tracking issue: rust-lang/rust#146922 `#![feature(type_info)]`
This PR supports {`bool`,`char`,`int`,`uint`,`float`,`str`} primitive types for feature `type_info` reflection.
r? @oli-obk
Remove `Deref`/`DerefMut` impl for `Providers`.
It's described as a "backwards compatibility hack to keep the diff small". Removing it requires only a modest amount of churn, and the resulting code is clearer without the invisible derefs.
r? @oli-obk
It's described as a "backwards compatibility hack to keep the diff
small". Removing it requires only a modest amount of churn, and the
resulting code is clearer without the invisible derefs.
Because these folders only change regions.
Note: `BottomUpFolder` folds all regions, while `fold_regions` skips
some bound regions. But that's ok because these two folders only modify
`ReVar`s.
Fix ICE: can't type-check body of DefId for issue #148729
This commit fixes https://github.com/rust-lang/rust/issues/148729 for min_const_generic_args https://github.com/rust-lang/rust/issues/132980.
It's pretty small PR. The first commit makes sure that the `type_const`s are made into normal consts in const expressions.
The next one just handles the case https://github.com/rust-lang/rust/issues/148729 of where the type of the const was omitted at which point it was trying to treat a `type_const` again as a regular const. That obviously will fail since a type_const does not have a body.
@rustbot label +F-associated_const_equality +F-min_generic_const_args +I-ICE
Handling for inherent associated consts is missing elsewhere, remove so it can be handled later in that handling.
Diagnostic not always be emitted on associated constant
Add a test case and Fix for a different ICE I encountered.
I noticed when trying various permuations of the test case code to see if I could find anymore ICEs. I did, but not one that I expected. So in the instances of the a named const not having any args, insantiate it directly. Since it is likely an inherent assocaiated const.
Added tests.
Centralize the is_type_const() logic.
I also noticed basically the exact same check in other part the code.
Const blocks can't be a type_const, therefore this check is uneeded.
Fix comment spelling error.
get_all_attrs is not valid to call for all DefIds it seems.
Make sure that if the type is omitted for a type_const that we don't ICE.
Co-Authored-By: Boxy <rust@boxyuwu.dev>
Don't use `matches!` when `==` suffices
In the codebase we sometimes use `matches!` for values that can actually just be compared. Replace them with `==`.
Subset of rust-lang/rust#149933.
interpreter/visitor: always iterate in in-memory order
Now that this is directly available in the type, there's no reason to ever iterate in any other order.
Replace Rvalue::NullaryOp by a variant in mir::Operand.
Based on https://github.com/rust-lang/rust/pull/148151
This PR fully removes the MIR `Rvalue::NullaryOp`. After rust-lang/rust#148151, it was only useful for runtime checks like `ub_checks`, `contract_checks` and `overflow_checks`.
These are "runtime" checks, boolean constants that may only be `true` in codegen. It depends on a rustc flag passed to codegen, so we need to represent those flags cross-crate.
This PR replaces those runtime checks by special variants in MIR `ConstValue`. This allows code that expects constants to manipulate those as such, even if we may not always be able to evaluate them to actual scalars.
miri genmc: fix exit() handling
In genmc mode, Miri does not want to stop execution when `exit` is called. Instead we want to continue running other threads to ensure we covered all possible concurrent behaviors (including the ones where the exiting thread was delayed so the other threads took their turns first). However, the core interpreter has a sanity check that prevents us from just doing nothing in `exit`. This leaves us in a pickle: there's nowhere we can jump to (exit has return type `!` so there's no next block), but if we don't jump anywhere we ICE.
The first commit fixes that by disabling the sanity check when there is no block to jump to. That still catches the mistake of forgetting to jump for the vast majority of shims.
We currently don't build Miri's genmc integration in rustc CI so I had to hack the feature into the bootstrap miri integration. That turned out to use the wrong Miri binary, which is fixed by the second commit: we can just rely on CARGO_BIN_EXE_miri, there's no need for a MIRI environment variable.
r? ``@oli-obk``
All usages of `memory_index` start by calling `invert_bijective_mapping`, so
storing the inverted mapping directly saves some work and simplifies the code.