Provide more context and suggestions in borrowck errors involving closures
Start pointing to where bindings where declared when they are captured in closures:
```
error[E0597]: `x` does not live long enough
--> $DIR/suggest-return-closure.rs:23:9
|
LL | let x = String::new();
| - binding `x` declared here
...
LL | |c| {
| --- value captured here
LL | x.push(c);
| ^ borrowed value does not live long enough
...
LL | }
| -- borrow later used here
| |
| `x` dropped here while still borrowed
```
Suggest cloning in more cases involving closures:
```
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
|
LL | if { (|| { let mut bar = foo; bar.take() })(); false } => {},
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
help: consider cloning the value if the performance cost is acceptable
|
LL | if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {},
| ++++++++
```
Mention when type parameter could be Clone
```
error[E0382]: use of moved value: `t`
--> $DIR/use_of_moved_value_copy_suggestions.rs:7:9
|
LL | fn duplicate_t<T>(t: T) -> (T, T) {
| - move occurs because `t` has type `T`, which does not implement the `Copy` trait
...
LL | (t, t)
| - ^ value used here after move
| |
| value moved here
|
help: if `T` implemented `Clone`, you could clone the value
--> $DIR/use_of_moved_value_copy_suggestions.rs:4:16
|
LL | fn duplicate_t<T>(t: T) -> (T, T) {
| ^ consider constraining this type parameter with `Clone`
...
LL | (t, t)
| - you could clone this value
help: consider restricting type parameter `T`
|
LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) {
| ++++++
```
The `help` is new. On ADTs, we also extend the output with span labels:
```
error[E0507]: cannot move out of static item `FOO`
--> $DIR/issue-17718-static-move.rs:6:14
|
LL | let _a = FOO;
| ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/issue-17718-static-move.rs:1:1
|
LL | struct Foo;
| ^^^^^^^^^^ consider implementing `Clone` for this type
...
LL | let _a = FOO;
| --- you could clone this value
help: consider borrowing here
|
LL | let _a = &FOO;
| +
```
Suggest cloning captured binding in move closure
```
error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
--> $DIR/borrowck-move-by-capture.rs:9:29
|
LL | let bar: Box<_> = Box::new(3);
| --- captured outer variable
LL | let _g = to_fn_mut(|| {
| -- captured by this `FnMut` closure
LL | let _h = to_fn_once(move || -> isize { *bar });
| ^^^^^^^^^^^^^^^^ ----
| | |
| | variable moved due to use in closure
| | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
| `bar` is moved here
|
help: clone the value before moving it into the closure 1
|
LL ~ let value = bar.clone();
LL ~ let _h = to_fn_once(move || -> isize { value });
|
```
```
error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
--> $DIR/borrowck-move-by-capture.rs:9:29
|
LL | let bar: Box<_> = Box::new(3);
| --- captured outer variable
LL | let _g = to_fn_mut(|| {
| -- captured by this `FnMut` closure
LL | let _h = to_fn_once(move || -> isize { *bar });
| ^^^^^^^^^^^^^^^^ ----
| | |
| | variable moved due to use in closure
| | move occurs because `bar` has type `Box<isize>`, which does not implement the `Copy` trait
| `bar` is moved here
|
help: clone the value before moving it into the closure
|
LL ~ let value = bar.clone();
LL ~ let _h = to_fn_once(move || -> isize { value });
|
```
```
error[E0382]: use of moved value: `t`
--> $DIR/use_of_moved_value_copy_suggestions.rs:7:9
|
LL | fn duplicate_t<T>(t: T) -> (T, T) {
| - move occurs because `t` has type `T`, which does not implement the `Copy` trait
...
LL | (t, t)
| - ^ value used here after move
| |
| value moved here
|
help: if `T` implemented `Clone`, you could clone the value
--> $DIR/use_of_moved_value_copy_suggestions.rs:4:16
|
LL | fn duplicate_t<T>(t: T) -> (T, T) {
| ^ consider constraining this type parameter with `Clone`
...
LL | (t, t)
| - you could clone this value
help: consider restricting type parameter `T`
|
LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) {
| ++++++
```
The `help` is new. On ADTs, we also extend the output with span labels:
```
error[E0507]: cannot move out of static item `FOO`
--> $DIR/issue-17718-static-move.rs:6:14
|
LL | let _a = FOO;
| ^^^ move occurs because `FOO` has type `Foo`, which does not implement the `Copy` trait
|
note: if `Foo` implemented `Clone`, you could clone the value
--> $DIR/issue-17718-static-move.rs:1:1
|
LL | struct Foo;
| ^^^^^^^^^^ consider implementing `Clone` for this type
...
LL | let _a = FOO;
| --- you could clone this value
help: consider borrowing here
|
LL | let _a = &FOO;
| +
```
Start pointing to where bindings were declared when they are captured in closures:
```
error[E0597]: `x` does not live long enough
--> $DIR/suggest-return-closure.rs:23:9
|
LL | let x = String::new();
| - binding `x` declared here
...
LL | |c| {
| --- value captured here
LL | x.push(c);
| ^ borrowed value does not live long enough
...
LL | }
| -- borrow later used here
| |
| `x` dropped here while still borrowed
```
Suggest cloning in more cases involving closures:
```
error[E0507]: cannot move out of `foo` in pattern guard
--> $DIR/issue-27282-move-ref-mut-into-guard.rs:11:19
|
LL | if { (|| { let mut bar = foo; bar.take() })(); false } => {},
| ^^ --- move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait
| |
| `foo` is moved here
|
= note: variables bound in patterns cannot be moved from until after the end of the pattern guard
help: consider cloning the value if the performance cost is acceptable
|
LL | if { (|| { let mut bar = foo.clone(); bar.take() })(); false } => {},
| ++++++++
```
Improve diagnostic for unknown `--print` request
This PR improves the diagnostic when encountering a unknown `--print` request.
It also moves the run-make test to a simple UI test.
Stabilise inline_const
# Stabilisation Report
## Summary
This PR will stabilise `inline_const` feature in expression position. `inline_const_pat` is still unstable and will *not* be stabilised.
The feature will allow code like this:
```rust
foo(const { 1 + 1 })
```
which is roughly desugared into
```rust
struct Foo;
impl Foo {
const FOO: i32 = 1 + 1;
}
foo(Foo::FOO)
```
This feature is from https://github.com/rust-lang/rfcs/pull/2920 and is tracked in #76001 (the tracking issue should *not* be closed as it needs to track inline const in pattern position). The initial implementation is done in #77124.
## Difference from RFC
There are two major differences (enhancements) as implemented from the RFC. First thing is that the RFC says that the type of an inline const block inferred from the content *within* it, but we currently can infer the type using the information from outside the const block as well. This is a frequently requested feature to the initial implementation (e.g. #89964). The inference is implemented in #89561 and is done by treating inline const similar to a closure and therefore share inference context with its parent body.
This allows code like:
```rust
let v: Vec<i32> = const { Vec::new() };
```
Another enhancement that differs from the RFC is that we currently allow inline consts to reference generic parameters. This is implemented in #96557.
This allows code like:
```rust
fn create_none_array<T, const N: usize>() -> [Option<T>; N] {
[const { None::<T> }; N]
}
```
This enhancement also makes inline const usable as static asserts:
```rust
fn require_zst<T>() {
const { assert!(std::mem::size_of::<T>() == 0) }
}
```
## Documentation
Reference: rust-lang/reference#1295
## Unresolved issues
We still have a few issues that are not resolved, but I don't think it necessarily has to block stabilisation:
* expr fragment specifier issue: #86730
* ~~`const {}` behaves similar to `async {}` but not to `{}` and `unsafe {}` (they are treated as `ExpressionWithoutBlock` rather than `ExpressionWithBlock`): https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/const.20blocks.20differ.20from.20normal.20and.20from.20unsafe.20blocks/near/290229453~~
## Tests
There are a few tests in https://github.com/rust-lang/rust/tree/master/src/test/ui/inline-const
Add diagnostic item for `std::iter::Enumerate`
This adds a diagnostic item for `std::iter::Enumerate`. The change will be used by the clippy `unused_enumerate_index` lint to move away from type paths to using diagnostic items.
see: https://github.com/rust-lang/rust-clippy/issues/5393
windows fill_utf16_buf: explain the expected return value
The comment just says "return what the syscall returns", but that doesn't work for all syscalls as the Windows API is not consistent in how buffer size is negotiated. For instance, GetUserProfileDirectoryW works a bit differently, and so home_dir_crt has to translate this to the usual protocol itself. So it's worth describing that protocol.
r? ``@ChrisDenton``
Bump Fuchsia versions
This updates the Fuchsia commit used in `auto - x86_64-gnu-integration` CI bot to use the Rust commit 703dc9ce64. This should help improve the coverage of this builder.
It also updates the SDK version to F20.20240412.3.1, and the Fuchsia Clang version to c777c011a709dffd4fa5e79cad7947b7c3405d02.
r? ``@tmandry``
More DefineOpaqueTypes::Yes
This accepts more code on stable. It is now possible to have match arms return a function item `foo::<ConcreteType>` and a function item `foo::<OpaqueTypeInDefiningScope>` in another, and that will constrain `OpaqueTypeInDefiningScope` to have the hidden type `ConcreteType`. So the following function will now compile, but on master it errors with a type mismatch on the second match arm
```rust
// The function item whose generic params we want to merge.
fn foo<T>(t: T) -> T { t }
// Helper ensuring we can constrain `T` on `F` without explicitly specifying it
fn bind<T, F: FnOnce(T) -> T>(_: T, f: F) -> F { f }
fn k() -> impl Sized {
let x = match true {
true => {
// `f` is `FnDef(foo, [infer_var])`
let f = foo;
// Get a value of an opaque type on stable
let t = k();
// this returns `FnDef(foo, [k::return])`
bind(t, f)
}
false => foo::<()>,
};
todo!()
}
```
r? ``@compiler-errors``
cc https://github.com/rust-lang/rust/issues/116652
Test `#[unix_sigpipe = "inherit"]` with both `SIG_DFL` and `SIG_IGN`
Extend our `#[unix_sigpipe = "inherit"]` test so that it detects if `SIGPIPE` wrongly ends up being `SIG_DFL` when the parent has `SIG_IGN`. We have no current test for this particular case.
Tracking issue: https://github.com/rust-lang/rust/issues/97889
delegation: Support renaming, and async, const, extern "ABI" and C-variadic functions
Also allow delegating to functions with opaque types (`impl Trait`).
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created, which seems like a reasonable behavior.
(Such delegation items will cause query cycles when used in trait impls, but it can be fixed later.)
Part of https://github.com/rust-lang/rust/issues/118212.
Require explicitly marking closures as coroutines
instead of relying on patching up the closure to be a coroutine if it happens to contain a `yield` expression.
I only do this in the 2024 edition, as the `gen` keyword is only available there.
CI: dynamic jobs
This PR modifies our CI workflows to be dynamic. This means that when a GitHub event is generated, we will run a Python script (`calculate-job-matrix.py`), which decides which CI jobs should be generated. These jobs are defined in `src/ci/github-actions/jobs.yml`).
This should provide a few benefits:
- Once the migration to dynamic jobs is complete, we shouldn't need `expand-yaml-anchors` anymore.
- The job table on PRs (and also the left job column on auto/try builds) should be much cleaner and contain only the jobs that are actually relevant/executed.
- It should be much easier to support dynamic try builds, i.e. to run an arbitrary CI job on a try build.
See [this Zulip discussion](https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra/topic/job.20matrix.20re-ordered.20PR.20list) for more context.
r? `@ghost`
Stop using LLVM struct types for alloca
The alloca type has no semantic meaning, only the size (and alignment, but we specify it explicitly) matter. Using `[N x i8]` is a more direct way to specify that we want `N` bytes, and avoids relying on LLVM's struct layout. It is likely that a future LLVM version will change to an untyped alloca representation.
Split out from #121577.
r? `@ghost`
restrict promotion of `const fn` calls
We only promote them in `const`/`static` initializers, but even that is still unfortunate -- we still cannot add promoteds to required_consts. But we should add them there to make sure it's always okay to evaluate every const we encounter in a MIR body. That effort of not promoting things that can fail to evaluate is tracked in https://github.com/rust-lang/rust/issues/80619. These `const fn` calls are the last missing piece.
So I propose that we do not promote const-fn calls in const when that may fail without the entire const failing, thereby completing https://github.com/rust-lang/rust/issues/80619. Unfortunately we can't just reject promoting these functions outright due to backwards compatibility. So let's see if we can find a hack that makes crater happy...
For the record, this is the [crater analysis](https://github.com/rust-lang/rust/pull/80243#issuecomment-751885520) from when I tried to entirely forbid this kind of promotion. It's a tiny amount of breakage and if we had a nice alternative for code like that, we could conceivably push it through... but sadly, inline const expressions are still blocked on t-lang concerns about post-monomorphization errors and we haven't yet figured out an implementation that can resolve those concerns. So we're forced to make progress via other means, such as terrible hacks like this.
Attempt one: only promote calls on the "safe path" at the beginning of a MIR block. This is the path that starts at the start block and continues via gotos and calls, but stops at the first branch. If we had imposed this restriction before stabilizing `if` and `match` in `const`, this would have definitely been sufficient...
EDIT: Turns out that works. :)
**Here's the t-lang [nomination comment](https://github.com/rust-lang/rust/pull/121557#issuecomment-1990902440).** And here's the [FCP comment](https://github.com/rust-lang/rust/pull/121557#issuecomment-2010306165).
r? `@oli-obk`
Enable `CrateNum` query feeding via `TyCtxt`
Instead of having a magic function that violates some `TyCtxtFeed` invariants, add a `create_def` equivalent for `CrateNum`s.
Note that this still isn't tracked by the query system (unlike `create_def`), and that feeding most `CrateNum` queries for crates other than the local one will likely cause performance regressions.
These things should be attempted on their own separately, but this PR should stand on its own
Also allow `impl Trait` in delegated functions.
The delegation item will refer to the original opaque type from the callee, fresh opaque type won't be created.
Rollup of 3 pull requests
Successful merges:
- #124003 (Dellvmize some intrinsics (use `u32` instead of `Self` in some integer intrinsics))
- #124169 (Don't fatal when calling `expect_one_of` when recovering arg in `parse_seq`)
- #124286 (Subtree sync for rustc_codegen_cranelift)
r? `@ghost`
`@rustbot` modify labels: rollup
Subtree sync for rustc_codegen_cranelift
This fixes a crash when compiling the standard library. In addition the Cranelift update fixes all the 128bit int abi incompatibility between cg_clif and cg_llvm.
r? ``@ghost``
``@rustbot`` label +A-codegen +A-cranelift +T-compiler