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.
Better closure requirement propagation.
Fixesrust-lang/rust#148289Fixesrust-lang/rust#104477
Should unblock rust-lang/rust#148187
When propagating closure requirements we:
- no longer try to find a post dominiting region for the list of non-local lower bounds of `longer_fr`.
- we filter the list of `longer_fr-: shorter_fr+` to only these constraints between external regions which are required regardless. If no such constraint exists, we fall back to propagating all of them.
See the [FCP](https://github.com/rust-lang/rust/pull/148329#issuecomment-3581019253) for more information.
r? `@lcnr`
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`