Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions library/std/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ use crate::{error, fmt};
/// [`read`]: File::read
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "File")]
#[diagnostic::on_move(note = "you can use `File::try_clone` to duplicate a `File` instance")]
pub struct File {
inner: fs_imp::File,
}
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@
#![feature(const_trait_impl)]
#![feature(decl_macro)]
#![feature(deprecated_suggestion)]
#![feature(diagnostic_on_move)]
#![feature(doc_cfg)]
#![feature(doc_masked)]
#![feature(doc_notable_trait)]
Expand Down
92 changes: 92 additions & 0 deletions src/doc/unstable-book/src/language-features/diagnostic-on-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# `diagnostic_on_move`

The tracking issue for this feature is: [#154181]

------------------------

The `diagnostic_on_move` feature allows use of the `#[diagnostic::on_move]` attribute. It should be
placed on struct, enum and union declarations, though it is not an error to be located in other
positions. This attribute is a hint to the compiler to supplement the error message when the
annotated type is involved in a borrowcheck error.

For example, [`File`] is annotated as such:
```rust
#![feature(diagnostic_on_move)]

#[diagnostic::on_move(note = "you can use `File::try_clone` \
to duplicate a `File` instance")]
pub struct File {
// ...
}
```

When you try to use a `File` after it's already been moved, it will helpfully tell you about `try_clone`.

The message and label can also be customized:

```rust
#![feature(diagnostic_on_move)]

use std::marker::PhantomData;

#[diagnostic::on_move(
message = "`{Self}` cannot be used multiple times",
label = "this token may only be used once",
note = "you can create a new `Token` with `Token::conjure()`"
)]
pub struct Token<'brand> {
spooky: PhantomData<&'brand ()>,
}

impl Token<'_> {
pub fn conjure<'u>() -> Token<'u> {
Token {
spooky: PhantomData,
}
}
}
```
The user may try to use it like this:
```rust,compile_fail,E0382
# #![feature(diagnostic_on_move)]
#
# use std::marker::PhantomData;
#
# #[diagnostic::on_move(
# message = "`{Self}` cannot be used multiple times",
# label = "this token may only be used once",
# note = "you can create a new `Token` with `Token::conjure()`"
# )]
# pub struct Token<'brand> {
# spooky: PhantomData<&'brand ()>,
# }
#
# impl Token<'_> {
# pub fn conjure<'u>() -> Token<'u> {
# Token {
# spooky: PhantomData,
# }
# }
# }
# fn main() {
let token = Token::conjure();
let _ = (token, token);
# }
```
This will result in the following error:
```text
error[E0382]: `Token` cannot be used multiple times
--> src/main.rs:24:21
|
1 | let token = Token::conjure();
| ----- this token may only be used once
2 | let _ = (token, token);
| ----- ^^^^^ value used here after move
| |
| value moved here
|
= note: you can create a new `Token` with `Token::conjure()`
```

[`File`]: https://doc.rust-lang.org/nightly/std/fs/struct.File.html "File in std::fs"
[#154181]: https://github.com/rust-lang/rust/issues/154181 "Tracking Issue for #[diagnostic::on_move]"
25 changes: 25 additions & 0 deletions tests/ui/diagnostic_namespace/on_move/std_impls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//@ dont-require-annotations: NOTE

use std::fs::File;
use std::sync::Arc;
use std::rc::Rc;

fn main(){
let file = File::open("foo.txt").unwrap();
(file, file);
//~^ ERROR use of moved value: `file`
//~| NOTE you can use `File::try_clone` to duplicate a `File` instance

let arc = Arc::new(42);
//~^ NOTE this move could be avoided by cloning the original `Arc`, which is inexpensive
(arc, arc);
//~^ ERROR the type `Arc` does not implement `Copy`
//~| NOTE consider using `Arc::clone`


let rc = Rc::new(12);
//~^ NOTE this move could be avoided by cloning the original `Rc`, which is inexpensive
(rc, rc);
//~^ ERROR the type `Rc` does not implement `Copy`
//~| NOTE consider using `Rc::clone`
}
49 changes: 49 additions & 0 deletions tests/ui/diagnostic_namespace/on_move/std_impls.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
error[E0382]: use of moved value: `file`
--> $DIR/std_impls.rs:9:12
|
LL | let file = File::open("foo.txt").unwrap();
| ---- move occurs because `file` has type `File`, which does not implement the `Copy` trait
LL | (file, file);
| ---- ^^^^ value used here after move
| |
| value moved here
|
= note: you can use `File::try_clone` to duplicate a `File` instance

error[E0382]: the type `Arc` does not implement `Copy`
--> $DIR/std_impls.rs:15:11
|
LL | let arc = Arc::new(42);
| --- this move could be avoided by cloning the original `Arc`, which is inexpensive
LL |
LL | (arc, arc);
| --- ^^^ value used here after move
| |
| value moved here
|
= note: consider using `Arc::clone`
help: clone the value to increment its reference count
|
LL | (arc.clone(), arc);
| ++++++++

error[E0382]: the type `Rc` does not implement `Copy`
--> $DIR/std_impls.rs:22:10
|
LL | let rc = Rc::new(12);
| -- this move could be avoided by cloning the original `Rc`, which is inexpensive
LL |
LL | (rc, rc);
| -- ^^ value used here after move
| |
| value moved here
|
= note: consider using `Rc::clone`
help: clone the value to increment its reference count
|
LL | (rc.clone(), rc);
| ++++++++

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0382`.
Loading