Refactor borrowck liveness values
This PR starts cleaning up `rustc_borrowck`, in particular around liveness values:
- refactors simple names that make no sense anymore: either referring to older structures using region elements, or to bitset containers and values.
- improves comments and fixes others
- removes unused return values and unneeded generic arguments
r? `@matthewjasper`
Currently we always do this:
```
use rustc_fluent_macro::fluent_messages;
...
fluent_messages! { "./example.ftl" }
```
But there is no need, we can just do this everywhere:
```
rustc_fluent_macro::fluent_messages! { "./example.ftl" }
```
which is shorter.
The `fluent_messages!` macro produces uses of
`crate::{D,Subd}iagnosticMessage`, which means that every crate using
the macro must have this import:
```
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
```
This commit changes the macro to instead use
`rustc_errors::{D,Subd}iagnosticMessage`, which avoids the need for the
imports.
Some types have a `body: &'mir Body<'tcx>` and some have `body: &'a
Body<'tcx>`. The former is more readable, so this commit converts some
fo the latter to the former.
By default, `newtype_index!` types get a default `Encodable`/`Decodable`
impl. You can opt out of this with `custom_encodable`. Opting out is the
opposite to how Rust normally works with autogenerated (derived) impls.
This commit inverts the behaviour, replacing `custom_encodable` with
`encodable` which opts into the default `Encodable`/`Decodable` impl.
Only 23 of the 59 `newtype_index!` occurrences need `encodable`.
Even better, there were eight crates with a dependency on
`rustc_serialize` just from unused default `Encodable`/`Decodable`
impls. This commit removes that dependency from those eight crates.
Fix early param lifetimes in generic_const_exprs
In cases like below, we never actually be able to capture region name for two reasons, first `'static` becomes anonymous lifetime and second we never capture region if it doesn't have a name so this results in ICE.
```
struct DataWrapper<'static> {
data: &'a [u8; Self::SIZE],
}
impl DataWrapper<'a> {
```
Fixes https://github.com/rust-lang/rust/issues/118021
Note about object lifetime defaults in does not live long enough error
This is a aspect of Rust that frequently trips up people who are not aware of it yet. This diagnostic attempts to explain what's happening and why the lifetime constraint, that was never mentioned in the source, arose.
The implementation feels a bit questionable, I'm not sure whether there are better ways to do this. There probably are.
fixes#117835
r? types
ignore implied bounds with placeholders
given the following code:
```rust
trait Trait {
type Ty<'a> where Self: 'a;
}
impl<T> Trait for T {
type Ty<'a> = () where Self: 'a;
}
struct Foo<T: Trait>(T)
where
for<'x> T::Ty<'x>: Sized;
```
when computing the implied bounds from `Foo<X>` we incorrectly get the bound `X: !x` from the normalization of ` for<'x> <X as Trait>::Ty::<'x>: Sized`. This is a a known bug! we shouldn't use the constraints that arise from normalization as implied bounds. See #109628.
Ignore these bounds for now. This should prevent later ICEs.
Fixes#112250Fixes#107409
This is a aspect of Rust that frequently trips up people who are not
aware of it yet. This diagnostic attempts to explain what's happening
and why the lifetime constraint, that was never mentioned in the source,
arose.
generator layout: ignore fake borrows
fixes#117059
We emit fake shallow borrows in case the scrutinee place uses a `Deref` and there is a match guard. This is necessary to prevent the match guard from mutating the scrutinee: fab1054e17/compiler/rustc_mir_build/src/build/matches/mod.rs (L1250-L1265)
These fake borrows end up impacting the generator witness computation in `mir_generator_witnesses`, which causes the issue in #117059. This PR now completely ignores fake borrows during this computation. This is sound as thse are always removed after analysis and the actual computation of the generator layout happens afterwards.
Only the second commit impacts behavior, and could be backported by itself.
r? types
Compute polonius loan scopes over the region graph
In issue #117146 a loan flows into an SCC containing a placeholder, and whose representative is an existential region. Since we currently compute loan scopes by looking at SCCs and their representatives only, polonius would compute kill points for this loan here whereas NLLs would not of course.
There are a few ways to fix this:
- don't try to be efficient by doing the computation over SCCs, and simply look for free regions and placeholders in the successors of the issuing region.
- change how the SCC representatives are picked, biasing towards placeholders over existential regions. They *shouldn't* matter much, but some downstream code may subtly depend on the current scheme (though no tests fail if we do such a change). This is for unrelated reasons also the way #116891 changes the representative computation. So that PR would also fix issue #117146.
- try to remove placeholders from the main path, and contain them to a pre-pass + a post-pass kind of polonius leak check. If possible, it would fix this issue by turning an outlives constraints to a placeholder into a constraint to 'static. This should also fix the issue, as the representative would be the free region in the SCC. We want to prototype this change to see if it's possible to try to simplify the borrowck main path from having to deal with placeholders and higher-ranked subtyping 🤞.
I'd like to take advantage of fuzzing and a crater run sooner rather than later, so that we grow more confidence that the 2 models are indeed equivalent empirically. Therefore this PR implements option 1 to fix the issue now.
We can take care of efficiency later after validation, and once we implement option 3 (which could also impact option 2 and that associated PR, maybe the lack of placeholders could remove the need to change the representative computation) to traverse SCCs and their representative again.
(Or we maybe will have some kind of naive position-dependent outlives propagation by then and this code would have been changed)
Fixes#117146.
r? `@matthewjasper`
Emit explanatory note for move errors in packed struct derives
Derive expansions for packed structs with non-`Copy` fields cause move errors because they prefer copying over borrowing since borrowing the fields of a packed struct can result in unaligned access.
This underlying cause of the errors, however, is not apparent to the user. This PR adds a diagnostic note to make it clear to the user (the new note is on the second last line):
```
tests/ui/derives/deriving-with-repr-packed-move-errors.rs:13:16
|
12 | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)]
| ----- in this derive macro expansion
13 | struct StructA(String);
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait
|
= note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
```
Fixes#117406
Partially addresses #110777
By using SCC for better performance, we also have to take into account
SCCs whose representative is an existential region but also contains a
placeholder.
By only checking the representative, we may miss that the loan escapes
the function. This can be fixed by picking a better representative, or
removing placeholders from the main path.
This is the simplest fix: forgo efficiency and traverse the region graph
instead of the SCCs.
Derive expansions for packed structs cause move errors because
they prefer copying over borrowing since borrowing the fields of a
packed struct can result in unaligned access and therefore undefined
behaviour.
This underlying cause of the errors, however, is not apparent
to the user. We add a diagnostic note here to remedy that.
Most notably, this commit changes the `pub use crate::*;` in that file
to `use crate::*;`. This requires a lot of `use` items in other crates
to be adjusted, because everything defined within `rustc_span::*` was
also available via `rustc_span::source_map::*`, which is bizarre.
The commit also removes `SourceMap::span_to_relative_line_string`, which
is unused.
- Sort dependencies and features sections.
- Add `tidy` markers to the sorted sections so they stay sorted.
- Remove empty `[lib`] sections.
- Remove "See more keys..." comments.
Excluded files:
- rustc_codegen_{cranelift,gcc}, because they're external.
- rustc_lexer, because it has external use.
- stable_mir, because it has external use.
Consider alias bounds when computing liveness in NLL (but this time sound hopefully)
This is a revival of #116040, except removing the changes to opaque lifetime captures check to make sure that we're not triggering any unsoundness due to the lack of general existential regions and the currently-existing `ReErased` hack we use instead.
r? `@aliemjay` -- I appreciate you pointing out the unsoundenss in the previous iteration of this PR, and I'd like to hear that you're happy with this iteration of this PR before this goes back into FCP :>
Fixes#116794 as well
---
(mostly copied from #116040 and reworked slightly)
# Background
Right now, liveness analysis in NLL is a bit simplistic. It simply walks through all of the regions of a type and marks them as being live at points. This is problematic in the case of aliases, since it requires that we mark **all** of the regions in their args[^1] as live, leading to bugs like #42940.
In reality, we may be able to deduce that fewer regions are allowed to be present in the projected type (or "hidden type" for opaques) via item bounds or where clauses, and therefore ideally, we should be able to soundly require fewer regions to be live in the alias.
For example:
```rust
trait Captures<'a> {}
impl<T> Captures<'_> for T {}
fn capture<'o>(_: &'o mut ()) -> impl Sized + Captures<'o> + 'static {}
fn test_two_mut(mut x: ()) {
let _f1 = capture(&mut x);
let _f2 = capture(&mut x);
//~^ ERROR cannot borrow `x` as mutable more than once at a time
}
```
In the example above, we should be able to deduce from the `'static` bound on `capture`'s opaque that even though `'o` is a captured region, it *can never* show up in the opaque's hidden type, and can soundly be ignored for liveness purposes.
# The Fix
We apply a simple version of RFC 1214's `OutlivesProjectionEnv` and `OutlivesProjectionTraitDef` rules to NLL's `make_all_regions_live` computation.
Specifically, when we encounter an alias type, we:
1. Look for a unique outlives bound in the param-env or item bounds for that alias. If there is more than one unique region, bail, unless any of the outlives bound's regions is `'static`, and in that case, prefer `'static`. If we find such a unique region, we can mark that outlives region as live and skip walking through the args of the opaque.
2. Otherwise, walk through the alias's args recursively, as we do today.
## Limitation: Multiple choices
This approach has some limitations. Firstly, since liveness doesn't use the same type-test logic as outlives bounds do, we can't really try several options when we're faced with a choice.
If we encounter two unique outlives regions in the param-env or bounds, we simply fall back to walking the opaque via its args. I expect this to be mostly mitigated by the special treatment of `'static`, and can be fixed in a forwards-compatible by a more sophisticated analysis in the future.
## Limitation: Opaque hidden types
Secondly, we do not employ any of these rules when considering whether the regions captured by a hidden type are valid. That causes this code (cc #42940) to fail:
```rust
trait Captures<'a> {}
impl<T> Captures<'_> for T {}
fn a() -> impl Sized + 'static {
b(&vec![])
}
fn b<'o>(_: &'o Vec<i32>) -> impl Sized + Captures<'o> + 'static {}
```
We need to have existential regions to avoid [unsoundness](https://github.com/rust-lang/rust/pull/116040#issuecomment-1751628189) when an opaque captures a region which is not represented in its own substs but which outlives a region that does.
## Read more
Context: https://github.com/rust-lang/rust/pull/115822#issuecomment-1731153952 (for the liveness case)
More context: https://github.com/rust-lang/rust/issues/42940#issuecomment-455198309 (for the opaque capture case, which this does not fix)
[^1]: except for bivariant region args in opaques, which will become less relevant when we move onto edition 2024 capture semantics for opaques.