-
Notifications
You must be signed in to change notification settings - Fork 12.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Emit explanatory note for move errors in packed struct derives
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.
- Loading branch information
Showing
4 changed files
with
290 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Check that deriving builtin traits for a packed struct with | ||
// non-Copy fields emits move errors along with an additional | ||
// diagnostic note explaining the reason | ||
// See issue #117406 | ||
|
||
use std::fmt::{Debug, Formatter, Result}; | ||
use std::cmp::Ordering; | ||
|
||
// Packed + derives: additional diagnostic should be emitted | ||
// for each of Debug, PartialEq and PartialOrd | ||
#[repr(packed)] | ||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
struct StructA(String); | ||
//~^ ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
//~| ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
//~| ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
//~| ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `self` which is behind a shared reference | ||
|
||
|
||
// Unrelated impl: additinal diagnostic should NOT be emitted | ||
impl StructA { | ||
fn fmt(&self) -> String { | ||
self.0 //~ ERROR: cannot move out of `self` which is behind a shared reference | ||
} | ||
} | ||
|
||
// Packed + manual impls: additional diagnostic should NOT be emitted | ||
#[repr(packed)] | ||
struct StructB(String); | ||
|
||
impl Debug for StructB { | ||
fn fmt(&self, f: &mut Formatter) -> Result { | ||
let x = &{ self.0 }; //~ ERROR: cannot move out of `self` which is behind a shared reference | ||
write!(f, "{}", x) | ||
} | ||
} | ||
|
||
impl PartialEq for StructB { | ||
fn eq(&self, other: &StructB) -> bool { | ||
({ self.0 }) == ({ other.0 }) | ||
//~^ ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
} | ||
} | ||
|
||
impl PartialOrd for StructB { | ||
fn partial_cmp(&self, other: &StructB) -> Option<Ordering> { | ||
PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ||
//~^ ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
} | ||
} | ||
|
||
// NOT packed + derives: additinal diagnostic should NOT be emitted | ||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
struct StructC(String); | ||
|
||
// NOT packed + manual impls: additinal dignostic should NOT be emitted | ||
struct StructD(String); | ||
|
||
impl Debug for StructD { | ||
fn fmt(&self, f: &mut Formatter) -> Result { | ||
let x = &{ self.0 }; //~ ERROR: cannot move out of `self` which is behind a shared reference | ||
write!(f, "{}", x) | ||
} | ||
} | ||
|
||
impl PartialEq for StructD { | ||
fn eq(&self, other: &StructD) -> bool { | ||
({ self.0 }) == ({ other.0 }) | ||
//~^ ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
} | ||
} | ||
|
||
impl PartialOrd for StructD { | ||
fn partial_cmp(&self, other: &StructD) -> Option<Ordering> { | ||
PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ||
//~^ ERROR: cannot move out of `self` which is behind a shared reference | ||
//~| ERROR: cannot move out of `other` which is behind a shared reference | ||
} | ||
} | ||
|
||
// Packed + derives but the move is outside of a derive | ||
// expansion: additinal diagnostic should NOT be emitted | ||
fn func(arg: &StructA) -> String { | ||
arg.0 //~ ERROR: cannot move out of `arg` which is behind a shared reference | ||
} | ||
|
||
fn main(){ | ||
} |
174 changes: 174 additions & 0 deletions
174
tests/ui/derives/deriving-with-repr-packed-move-errors.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| ----- in this derive macro expansion | ||
LL | 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) | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| --------- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| --------- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| ---------- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| ---------- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| --- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| --- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| ---- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(Hash)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | ||
| | ||
LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ||
| ----- in this derive macro expansion | ||
LL | struct StructA(String); | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
| | ||
= note: `#[derive(Clone)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour | ||
= note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:28:9 | ||
| | ||
LL | self.0 | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:38:20 | ||
| | ||
LL | let x = &{ self.0 }; | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:45:12 | ||
| | ||
LL | ({ self.0 }) == ({ other.0 }) | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:45:28 | ||
| | ||
LL | ({ self.0 }) == ({ other.0 }) | ||
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:53:36 | ||
| | ||
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:53:49 | ||
| | ||
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ||
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:68:20 | ||
| | ||
LL | let x = &{ self.0 }; | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:75:12 | ||
| | ||
LL | ({ self.0 }) == ({ other.0 }) | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:75:28 | ||
| | ||
LL | ({ self.0 }) == ({ other.0 }) | ||
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `self` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:83:36 | ||
| | ||
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ||
| ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `other` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:83:49 | ||
| | ||
LL | PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 }) | ||
| ^^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error[E0507]: cannot move out of `arg` which is behind a shared reference | ||
--> $DIR/deriving-with-repr-packed-move-errors.rs:92:5 | ||
| | ||
LL | arg.0 | ||
| ^^^^^ move occurs because `arg.0` has type `String`, which does not implement the `Copy` trait | ||
|
||
error: aborting due to 21 previous errors | ||
|
||
For more information about this error, try `rustc --explain E0507`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters