Fix drop handling for `if let` expressions
MIR lowering for `if let` expressions is now more complicated now that
`if let` exists in HIR. This PR adds a scope for the variables bound in
an `if let` expression and then uses an approach similar to how we
handle loops to ensure that we reliably drop the correct variables.
Closes#88307
cc `@flip1995` `@richkadel` `@c410-f3r`
MIR lowering for `if let` expressions is now more complicated now that
`if let` exists in HIR. This PR adds a scope for the variables bound in
an `if let` expression and then uses an approach similar to how we
handle loops to ensure that we reliably drop the correct variables.
Introduce `let...else`
Tracking issue: #87335
The trickiest part for me was enforcing the diverging else block with clear diagnostics. Perhaps the obvious solution is to expand to `let _: ! = ..`, but I decided against this because, when a "mismatched type" error is found in typeck, there is no way to trace where in the HIR the expected type originated, AFAICT. In order to pass down this information, I believe we should introduce `Expectation::LetElseNever(HirId)` or maybe add `HirId` to `Expectation::HasType`, but I left that as a future enhancement. For now, I simply assert that the block is `!` with a custom `ObligationCauseCode`, and I think this is clear enough, at least to start. The downside here is that the error points at the entire block rather than the specific expression with the wrong type. I left a todo to this effect.
Overall, I believe this PR is feature-complete with regard to the RFC.
rustc_target: `TyAndLayout::field` should never error.
This refactor (making `TyAndLayout::field` return `TyAndLayout` without any `Result` around it) is based on a simple observation, regarding `TyAndLayout::field`:
If `cx.layout_of(ty)` succeeds (for some `cx` and `ty`), then `.field(cx, i)` on the resulting `TyAndLayout` should *always* succeed in computing `cx.layout_of(field_ty)` (where `field_ty` is the type of the `i`th field of `ty`).
The reason for this is that no matter which field is chosen, `cx.layout_of(field_ty)` *will have already been computed*, as part of computing `cx.layout_of(ty)`, as we cannot determine the layout of *any* type without considering the layouts of *all* of its fields.
And so it should be fine to turn any errors into ICEs, since they likely indicate a `cx` mismatch, or some other edge case that is due to a compiler bug (as opposed to ever being an user-facing error).
<hr/>
Each commit should probably be reviewed separately, though note that there's some `where` clauses (in `rustc_target::abi::call::*`) that change in most commits.
cc `@nagisa` `@oli-obk`
Introduce `~const`
- [x] Removed `?const` and change uses of `?const`
- [x] Added `~const` to the AST. It is gated behind const_trait_impl.
- [x] Validate `~const` in ast_validation.
- [x] Update UI Tests
- [x] Add enum `BoundConstness` (With variants `NotConst` and
`ConstIfConst` allowing future extensions)
- [x] Adjust trait selection and pre-existing code to use `BoundConstness`.
- [ ] Optional steps for this PR
- [x] Fix#88155
- [x] ~~Do something with constness bounds in chalk~~ Must be done to rust-lang/chalk (just tried to refactor, there are a lot of errors to resolve :( )
- [ ] Adjust Error messages for `~const` bounds that can't be satisfied.
r? `@oli-obk`
`#[inline]` non-generic `pub fn`s in `rustc_target::abi` and `ty::layout`.
Mostly doing this as a perf curiosity, having spotted that `#[inline]` usage is a bit spotty.
- [x] Removed `?const` and change uses of `?const`
- [x] Added `~const` to the AST. It is gated behind const_trait_impl.
- [x] Validate `~const` in ast_validation.
- [ ] Add enum `BoundConstness` to the HIR. (With variants `NotConst` and
`ConstIfConst` allowing future extensions)
- [ ] Adjust trait selection and pre-existing code to use `BoundConstness`.
- [ ] Optional steps (*for this PR, obviously*)
- [ ] Fix#88155
- [ ] Do something with constness bounds in chalk
lazily "compute" anon const default substs
Continuing the work of #83086, this implements the discussed solution for the [unused substs problem](https://github.com/rust-lang/project-const-generics/blob/master/design-docs/anon-const-substs.md#unused-substs). As of now, anonymous constants inherit all of their parents generics, even if they do not use them, e.g. in `fn foo<T, const N: usize>() -> [T; N + 1]`, the array length has `T` as a generic parameter even though it doesn't use it. These *unused substs* cause some backwards incompatible, and imo incorrect behavior, e.g. #78369.
---
We do not actually filter any generic parameters here and the `default_anon_const_substs` query still a dummy which only checks that
- we now prevent the previously existing query cycles and are able to call `predicates_of(parent)` when computing the substs of anonymous constants
- the default anon consts substs only include the typeflags we assume it does.
Implementing that filtering will be left as future work.
---
The idea of this PR is to delay the creation of the anon const substs until after we've computed `predicates_of` for the parent of the anon const. As the predicates of the parent can however contain the anon const we still have to create a `ty::Const` for it.
We do this by changing the substs field of `ty::Unevaluated` to an option and modifying accesses to instead call the method `unevaluated.substs(tcx)` which returns the substs as before. If the substs - now `substs_` - of `ty::Unevaluated` are `None`, it means that the anon const currently has its default substs, i.e. the substs it has when first constructed, which are the generic parameters it has available. To be able to call `unevaluated.substs(tcx)` in a `TypeVisitor`, we add the non-defaulted method `fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>>`. In case `tcx_for_anon_const_substs` returns `None`, unknown anon const default substs are skipped entirely.
Even when `substs_` is `None` we still have to treat the constant as if it has its default substs. To do this, `TypeFlags` are modified so that it is clear whether they can still change when *exposing* any anon const default substs. A new flag, `HAS_UNKNOWN_DEFAULT_CONST_SUBSTS`, is added in case some default flags are missing.
The rest of this PR are some smaller changes to either not cause cycles by trying to access the default anon const substs too early or to be able to access the `tcx` in previously unused locations.
cc `@rust-lang/project-const-generics`
r? `@nikomatsakis`
Morph `layout_raw` query into `layout_of`.
Before this PR, `LayoutCx::layout_of` wrapped the `layout_raw` query, to:
* normalize the type, before attempting to compute the layout
* pass the layout to `record_layout_for_printing`, for `-Zprint-type-sizes`
Moving those two responsibilities into the query may reduce overhead (due to cached calls skipping those steps), but I want to do a perf run to know.
One of the changes I had to make was changing the return type of the query, to be able to both get out the type produced by normalizing inside the query *and* to match the signature of the old `TyCtxt::layout_of`. This change may be worse, perf-wise, so that's another reason I want to check.
r? `@nagisa` cc `@oli-obk`
Use undef for uninitialized bytes in constants
Fixes#83657
This generates good code when the const is fully uninit, e.g.
```rust
#[no_mangle]
pub const fn fully_uninit() -> MaybeUninit<[u8; 10]> {
const M: MaybeUninit<[u8; 10]> = MaybeUninit::uninit();
M
}
```
generates
```asm
fully_uninit:
ret
```
as you would expect.
There is no improvement, however, when it's partially uninit, e.g.
```rust
pub struct PartiallyUninit {
x: u64,
y: MaybeUninit<[u8; 10]>
}
#[no_mangle]
pub const fn partially_uninit() -> PartiallyUninit {
const X: PartiallyUninit = PartiallyUninit { x: 0xdeadbeefcafe, y: MaybeUninit::uninit() };
X
}
```
generates
```asm
partially_uninit:
mov rax, rdi
mov rcx, qword ptr [rip + .L__unnamed_1+16]
mov qword ptr [rdi + 16], rcx
movups xmm0, xmmword ptr [rip + .L__unnamed_1]
movups xmmword ptr [rdi], xmm0
ret
.L__unnamed_1:
.asciz "\376\312\357\276\255\336\000"
.zero 16
.size .L__unnamed_1, 24
```
which copies a bunch of zeros in place of the undef bytes, the same as before this change.
Edit: generating partially-undef constants isn't viable at the moment anyways due to #84565, so it's disabled
Use if-let guards in the codebase and various other pattern cleanups
Dogfooding if-let guards as experimentation for the feature.
Tracking issue #51114. Conflicts with #87937.