Overhaul filename handling for cross-compiler consistency
This PR overhauls the way we handle filenames in the compiler and `rmeta` in order to achieve achieve cross-compiler consistency (ie. having the same path no matter if the filename was created in the current compiler session or is coming from `rmeta`).
This is required as some parts of the compiler rely on consistent paths for the soundness of generated code (see rust-lang/rust#148328).
In order to achieved consistency multiple steps are being taken by this PR:
- by making `RealFileName` immutable
- by only having `SourceMap::to_real_filename` create `RealFileName`
- currently `RealFileName` can be created from any `Path` and are remapped afterwards, which creates consistency issue
- by also making `RealFileName` holds it's working directory, embeddable name and the remapped scopes
- this removes the need for a `Session`, to know the current(!) scopes and cwd, which is invalid as they may not be equal to the scopes used when creating the filename
In order for `SourceMap::to_real_filename` to know which scopes to apply `FilePathMapping` now takes the current remapping scopes to apply, which makes `FileNameDisplayPreference` and company useless and are removed.
This PR is split-up in multiple commits (unfortunately not atomic), but should help review the changes.
Unblocks https://github.com/rust-lang/rust/pull/147611
Fixes https://github.com/rust-lang/rust/issues/148328
Move `struct Placeholder<T>`
r? ghost
Couple of issues I've encountered;
- `compiler/rustc_infer/src/infer/region_constraints/mod.rs` `GenericKind` I can't call `write!(f, "{p}")` due to error 1. Which looks like I may need to implement `Lift` for `Placeholder`?
- Using the `define_print_and_forward_display!` for `ty::PlaceholderType` caused error 2, as I've moved the struct it no longer exists in the crate. I suspect because I'm not using that macro it causes the error for `GenericKind`
<details>
<summary>Error 1</summary>
```
error: lifetime may not live long enough
--> compiler/rustc_infer/src/infer/region_constraints/mod.rs:672:38
|
668 | impl<'tcx> fmt::Display for GenericKind<'tcx> {
| ---- lifetime `'tcx` defined here
...
672 | GenericKind::Placeholder(ref p) => write!(f, "{p}"),
| ^^^^^ assignment requires that `'tcx` must outlive `'static`
|
= note: requirement occurs because of the type `rustc_middle::ty::TyCtxt<'_>`, which makes the generic argument `'_` invariant
= note: the struct `rustc_middle::ty::TyCtxt<'tcx>` is invariant over the parameter `'tcx`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: implementation of `Lift` is not general enough
--> compiler/rustc_infer/src/infer/region_constraints/mod.rs:672:38
|
672 | GenericKind::Placeholder(ref p) => write!(f, "{p}"),
| ^^^^^ implementation of `Lift` is not general enough
|
= note: `Lift<rustc_middle::ty::TyCtxt<'0>>` would have to be implemented for the type `rustc_type_ir::Placeholder<rustc_middle::ty::TyCtxt<'_>, BoundTy>`, for any lifetime `'0`...
= note: ...but `Lift<rustc_middle::ty::TyCtxt<'1>>` is actually implemented for the type `rustc_type_ir::Placeholder<rustc_middle::ty::TyCtxt<'1>, BoundTy>`, for some specific lifetime `'1`
error: implementation of `Print` is not general enough
--> compiler/rustc_infer/src/infer/region_constraints/mod.rs:672:38
|
672 | GenericKind::Placeholder(ref p) => write!(f, "{p}"),
| ^^^^^ implementation of `Print` is not general enough
```
</details>
<details>
<summary>Error 2</summary>
```
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> compiler/rustc_middle/src/ty/print/pretty.rs:3060:38
|
3057 | / macro_rules! forward_display_to_print {
3058 | | ($($ty:ty),+) => {
3059 | | // Some of the $ty arguments may not actually use 'tcx
3060 | | $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
... |
3072 | | };
3073 | | }
| |_- in this expansion of `forward_display_to_print!`
...
3093 | / forward_display_to_print! {
3094 | | ty::Region<'tcx>,
3095 | | Ty<'tcx>,
3096 | | &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3097 | | ty::Const<'tcx>,
3098 | | &'tcx ty::PlaceholderType<'tcx>
| | ------------------------------- `rustc_type_ir::Placeholder` is not defined in the current crate
3099 | | }
| |_- in this macro invocation
|
= note: impl doesn't have any local type before any uncovered type parameters
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
= note: define and implement a trait or new type instead
error: implementation of `Lift` is not general enough
--> compiler/rustc_middle/src/ty/print/pretty.rs:3060:38
|
3057 | / macro_rules! forward_display_to_print {
3058 | | ($($ty:ty),+) => {
3059 | | // Some of the $ty arguments may not actually use 'tcx
3060 | | $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `Lift` is not general enough
... |
3072 | | };
3073 | | }
| |_- in this expansion of `forward_display_to_print!`
...
3093 | / forward_display_to_print! {
3094 | | ty::Region<'tcx>,
3095 | | Ty<'tcx>,
3096 | | &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3097 | | ty::Const<'tcx>,
3098 | | &'tcx ty::PlaceholderType<'tcx>
3099 | | }
| |_- in this macro invocation
|
= note: `Lift<context::TyCtxt<'0>>` would have to be implemented for the type `rustc_type_ir::Placeholder<context::TyCtxt<'tcx>, BoundTy>`, for any lifetime `'0`...
= note: ...but `Lift<context::TyCtxt<'1>>` is actually implemented for the type `rustc_type_ir::Placeholder<context::TyCtxt<'1>, BoundTy>`, for some specific lifetime `'1`
error: implementation of `print::Print` is not general enough
--> compiler/rustc_middle/src/ty/print/pretty.rs:3060:38
|
3057 | / macro_rules! forward_display_to_print {
3058 | | ($($ty:ty),+) => {
3059 | | // Some of the $ty arguments may not actually use 'tcx
3060 | | $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `print::Print` is not general enough
... |
3072 | | };
3073 | | }
| |_- in this expansion of `forward_display_to_print!`
...
3093 | / forward_display_to_print! {
3094 | | ty::Region<'tcx>,
3095 | | Ty<'tcx>,
3096 | | &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3097 | | ty::Const<'tcx>,
3098 | | &'tcx ty::PlaceholderType<'tcx>
3099 | | }
| |_- in this macro invocation
|
= note: `print::Print<'0, print::pretty::FmtPrinter<'a, '0>>` would have to be implemented for the type `rustc_type_ir::Placeholder<context::TyCtxt<'tcx>, BoundTy>`, for any lifetime `'0`...
= note: ...but `print::Print<'1, print::pretty::FmtPrinter<'a, 'tcx>>` is actually implemented for the type `rustc_type_ir::Placeholder<context::TyCtxt<'1>, BoundTy>`, for some specific lifetime `'1`
error: specializing impl repeats parameter `'tcx`
--> compiler/rustc_middle/src/ty/print/pretty.rs:3060:38
|
3057 | / macro_rules! forward_display_to_print {
3058 | | ($($ty:ty),+) => {
3059 | | // Some of the $ty arguments may not actually use 'tcx
3060 | | $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
... |
3072 | | };
3073 | | }
| |_- in this expansion of `forward_display_to_print!`
...
3093 | / forward_display_to_print! {
3094 | | ty::Region<'tcx>,
3095 | | Ty<'tcx>,
3096 | | &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3097 | | ty::Const<'tcx>,
3098 | | &'tcx ty::PlaceholderType<'tcx>
3099 | | }
| |_- in this macro invocation
error[E0277]: the trait bound `&Placeholder<TyCtxt<'tcx>, BoundTy>: Lift<...>` is not satisfied
--> compiler/rustc_middle/src/ty/print/pretty.rs:3064:30
|
3057 | / macro_rules! forward_display_to_print {
3058 | | ($($ty:ty),+) => {
3059 | | // Some of the $ty arguments may not actually use 'tcx
3060 | | $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
... |
3064 | | tcx.lift(*self)
| | ---- ^^^^^ unsatisfied trait bound
| | |
| | required by a bound introduced by this call
... |
3072 | | };
3073 | | }
| |_- in this expansion of `forward_display_to_print!`
...
3093 | / forward_display_to_print! {
3094 | | ty::Region<'tcx>,
3095 | | Ty<'tcx>,
3096 | | &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3097 | | ty::Const<'tcx>,
3098 | | &'tcx ty::PlaceholderType<'tcx>
3099 | | }
| |_- in this macro invocation
|
= help: the trait `Lift<context::TyCtxt<'_>>` is not implemented for `&rustc_type_ir::Placeholder<context::TyCtxt<'tcx>, BoundTy>`
note: required by a bound in `context::TyCtxt::<'tcx>::lift`
--> compiler/rustc_middle/src/ty/context.rs:1807:20
|
1807 | pub fn lift<T: Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> {
| ^^^^^^^^^^^^^^^^^^ required by this bound in `TyCtxt::<'tcx>::lift`
= note: the full name for the type has been written to '/home/jambar02/Documents/arm/rust/build/x86_64-unknown-linux-gnu/stage1-rustc/x86_64-unknown-linux-gnu/release/deps/rustc_middle-16e5c44041028d8b.long-type-3843651570422266958.txt'
= note: consider using `--verbose` to print the full type name to the console
help: consider dereferencing here
|
3064 | tcx.lift(**self)
| +
error[E0282]: type annotations needed
--> compiler/rustc_middle/src/ty/print/pretty.rs:3064:21
|
3057 | / macro_rules! forward_display_to_print {
3058 | | ($($ty:ty),+) => {
3059 | | // Some of the $ty arguments may not actually use 'tcx
3060 | | $(#[allow(unused_lifetimes)] impl<'tcx> fmt::Display for $ty {
... |
3064 | |/ tcx.lift(*self)
3065 | || .expect("could not lift for printing")
| ||______________________________________________________________^ cannot infer type
... |
3072 | | };
3073 | | }
| |__- in this expansion of `forward_display_to_print!`
...
3093 | / forward_display_to_print! {
3094 | | ty::Region<'tcx>,
3095 | | Ty<'tcx>,
3096 | | &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
3097 | | ty::Const<'tcx>,
3098 | | &'tcx ty::PlaceholderType<'tcx>
3099 | | }
| |_- in this macro invocation
```
</details>
This removes variance information from some diagnostics. However,
that variance information is not actually relevant here. Casting
`*const dyn Cat<'a>` to `*const S<dyn Cat<'static>>` is an error
regardless of whether `S` requires its argument to be invariant.
Wide-pointer casts always require the trait object arguments to be
invariant.
rustc_borrowck: Don't suggest changing closure param type not under user control
This changes output of a handful of tests more than the one added in the first commit, but as far as I can tell, all removed suggestions were invalid.
Closesrust-lang/rust#128381 which is **D-invalid-suggestion** with two 👍-votes.
Improve diagnostics for buffer reuse with borrowed references
Addresses rust-lang/rust#147694
I'm not sure the current note wording is the best so I appreciate any feedback.
Provide more context when mutably borrowing an imutably borrowed value
Point at statics and consts being mutable borrowed or written to:
```
error[E0594]: cannot assign to immutable static item `NUM`
--> $DIR/E0594.rs:4:5
|
LL | static NUM: i32 = 18;
| --------------- this `static` cannot be written to
...
LL | NUM = 20;
| ^^^^^^^^ cannot assign
```
Point at the expression that couldn't be mutably borrowed from a pattern:
```
error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/mut-pattern-of-immutable-borrow.rs:19:14
|
LL | match &arg.field {
| ---------- this cannot be borrowed as mutable
LL | Some(ref mut s) => s.push('a'),
| ^^^^^^^^^ cannot borrow as mutable
```
Partially address rust-lang/rust#74617.
Point at statics and consts being mutable borrowed or written to:
```
error[E0594]: cannot assign to immutable static item `NUM`
--> $DIR/E0594.rs:4:5
|
LL | static NUM: i32 = 18;
| --------------- this `static` cannot be written to
...
LL | NUM = 20;
| ^^^^^^^^ cannot assign
```
Point at the expression that couldn't be mutably borrowed from a pattern:
```
error[E0596]: cannot borrow data in a `&` reference as mutable
--> $DIR/mut-pattern-of-immutable-borrow.rs:19:14
|
LL | match &arg.field {
| ---------- this cannot be borrowed as mutable
LL | Some(ref mut s) => s.push('a'),
| ^^^^^^^^^ cannot borrow as mutable
```
Add `overflow_checks` intrinsic
This adds an intrinsic which allows code in a pre-built library to inherit the overflow checks option from a crate depending on it. This enables code in the standard library to explicitly change behavior based on whether `overflow_checks` are enabled, regardless of the setting used when standard library was compiled.
This is very similar to the `ub_checks` intrinsic, and refactors the two to use a common mechanism.
The primary use case for this is to allow the new `RangeFrom` iterator to yield the maximum element before overflowing, as requested [here](https://github.com/rust-lang/rust/issues/125687#issuecomment-2151118208). This PR includes a working `IterRangeFrom` implementation based on this new intrinsic that exhibits the desired behavior.
[Prior discussion on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/219381-t-libs/topic/Ability.20to.20select.20code.20based.20on.20.60overflow_checks.60.3F)
Provide more context on `Fn` closure modifying binding
When modifying a binding from inside of an `Fn` closure, point at the binding definition and suggest using an `std::sync` type that would allow the code to compile.
```
error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure
--> f703.rs:6:9
|
4 | let mut counter = 0;
| ----------- `counter` declared here, outside the closure
5 | let x: Box<dyn Fn()> = Box::new(|| {
| -- in this closure
6 | counter += 1;
| ^^^^^^^^^^^^ cannot assign
|
= help: consider using `std::sync::atomic::AtomicI32` instead, which allows for multiple threads to access and modify the value
```
This provides more context on where the binding being modified was declared, and more importantly, guides newcomers towards `std::sync` when encountering cases like these.
When the requirement comes from an argument of a local function, we already tell the user that they might want to change from `Fn` to `FnMut`:
```
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:21:27
|
LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
| - change this to accept `FnMut` instead of `Fn`
...
LL | let mut x = 0;
| ----- `x` declared here, outside the closure
LL | let _f = to_fn(|| x = 42);
| ----- -- ^^^^^^ cannot assign
| | |
| | in this closure
| expects `Fn` instead of `FnMut`
|
= help: consider using `std::sync::atomic::AtomicI32` instead, which allows for multiple threads to access and modify the value
```
We might want to avoid the `help` in this case.
_Inspired by a [part of Niko's keynote at RustNation UK 2024](https://youtu.be/04gTQmLETFI?si=dgJL2OJRtuShkxdD&t=600)._
When modifying a binding from inside of an `Fn` closure, point at the binding definition and suggest using an `std::sync` type that would allow the code to compile.
```
error[E0594]: cannot assign to `counter`, as it is a captured variable in a `Fn` closure
--> f703.rs:6:9
|
4 | let mut counter = 0;
| ----------- `counter` declared here, outside the closure
5 | let x: Box<dyn Fn()> = Box::new(|| {
| -- in this closure
6 | counter += 1;
| ^^^^^^^^^^^^ cannot assign
```
Suggest making binding `mut` on `&mut` reborrow
When a binding needs to be mutably reborrowed multiple times, suggesting removing `&mut` will lead to follow up errors. Instead suggest both making the binding mutable and removing the reborrow.
```
error[E0596]: cannot borrow `outer` as mutable, as it is not declared as mutable
--> f14.rs:2:12
|
2 | match (&mut outer, 23) {
| ^^^^^^^^^^ cannot borrow as mutable
|
note: the binding is already a mutable borrow
--> f14.rs:1:16
|
1 | fn test(outer: &mut Option<i32>) {
| ^^^^^^^^^^^^^^^^
help: consider making the binding mutable if you need to reborrow multiple times
|
1 | fn test(mut outer: &mut Option<i32>) {
| +++
help: if there is only one mutable reborrow, remove the `&mut`
|
2 - match (&mut outer, 23) {
2 + match (outer, 23) {
|
```
Address rust-lang/rust#81059.
Implement pin-project in pattern matching for `&pin mut|const T`
This PR implements part of rust-lang/rust#130494. It supports pin-project in pattern matching for `&pin mut|const T`.
~Pin-projection by field access (i.e. `&pin mut|const place.field`) is not fully supported yet since pinned-borrow is not ready (rust-lang/rust#135731).~
CC ``````@traviscross``````
When a binding needs to be mutably reborrowed multiple times, suggesting removing `&mut` will lead to follow up errors. Instead suggest both making the binding mutable and removing the reborrow.
```
error[E0596]: cannot borrow `outer` as mutable, as it is not declared as mutable
--> f14.rs:2:12
|
2 | match (&mut outer, 23) {
| ^^^^^^^^^^ cannot borrow as mutable
|
note: the binding is already a mutable borrow
--> f14.rs:1:16
|
1 | fn test(outer: &mut Option<i32>) {
| ^^^^^^^^^^^^^^^^
help: consider making the binding mutable if you need to reborrow multiple times
|
1 | fn test(mut outer: &mut Option<i32>) {
| +++
help: if there is only one mutable reborrow, remove the `&mut`
|
2 - match (&mut outer, 23) {
2 + match (outer, 23) {
|
```
Use `mut` less in dataflow analysis
`&mut Analysis` is used a lot:
- In results visitors, even though only one visitor needs mutability.
- In all the `apply_*` methods, even though only one visitor needs mutability.
I've lost track of the number of times I've thought "why are these `mut` again?" and had to look through the code to remind myself. It's really unexpected, and most `Analysis` instances are immutable, because the `state` values are what get mutated.
This commit introduces `RefCell` in one analysis and one results visitor. This then lets another existing `RefCell` be removed, and a ton of `&mut Analysis` arguments become `&Analysis`. And then `Analysis` and `Results` can be recombined.
r? `@cjgillot`
`Results` used to contain an `Analysis`, but it was removed in #140234.
That change made sense because the analysis was mutable but the entry
states were immutable and it was good to separate them so the mutability
of the different pieces was clear.
Now that analyses are immutable there is no need for the separation,
lots of analysis+results pairs can be combined, and the names are going
back to what they were before:
- `Results` -> `EntryStates`
- `AnalysisAndResults` -> `Results`
The `state: A::Domain` value is the primary things that's modified when
performing an analysis. The `Analysis` impl is immutable in every case
but one (`MaybeRequiredStorage`) and it now uses interior mutability.
As well as changing many `&mut A` arguments to `&A`, this also:
- lets `CowMut` be replaced with the simpler `SimpleCow` in `cursor.rs`;
- removes the need for the `RefCell` in `Formatter`;
- removes the need for `MaybeBorrowedLocals` to impl `Clone`, because
it's a unit type and it's now clear that its constructor can be used
directly instead of being put into a local variable and cloned.
Limit impl_trait_header query to only trait impls
Changes `impl_trait_header` to panic on inherent impls intstead of returning None. A few downstream functions are split into option and non-option returning functions. This gets rid of a lot of unwraps where we know we have a trait impl, while there are still some cases where the Option is helpful.
Summary of changes to tcx methods:
* `impl_is_of_trait` (new)
* `impl_trait_header` -> `impl_trait_header`/`impl_opt_trait_header`
* `impl_trait_ref` -> `impl_trait_ref`/`impl_opt_trait_ref`
* `trait_id_of_impl` -> `impl_trait_id`/`impl_opt_trait_id`
Pre-compute MIR CFG caches for borrowck and other analyses
I was puzzled that https://github.com/rust-lang/rust/pull/142390 introduces additional computations of CFG traversals: borrowck computes them, right?
It turns out that borrowck clones the MIR body, so doesn't share its cache with other analyses.
This PR:
- forces the computation of all caches in `mir_promoted` query;
- modifies region renumbering to avoid dropping that cache.
Polonius liveness has to contain boring locals, and we ignore them in
diagnostics to match NLL diagnostics, since they doesn't contain boring locals.
We ignored these when explaining why a loan contained a point due to
a use of a live var, but not when it contained a point due to a drop of
a live var.