about summary refs log tree commit diff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs36
-rw-r--r--src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr22
-rw-r--r--src/test/ui/closures/2229_closure_analysis/repr_packed.rs103
-rw-r--r--src/test/ui/closures/2229_closure_analysis/repr_packed.stderr165
4 files changed, 326 insertions, 0 deletions
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs
new file mode 100644
index 00000000000..6fce2951505
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.rs
@@ -0,0 +1,36 @@
+// check-pass
+
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+
+// Given how the closure desugaring is implemented (at least at the time of writing this test),
+// we don't need to truncate the captured path to a reference into a packed-struct if the field
+// being referenced will be moved into the closure, since it's safe to move out a field from a
+// packed-struct.
+//
+// However to avoid surprises for the user, or issues when the closure is
+// inlined we will truncate the capture to access just the struct regardless of if the field
+// might get moved into the closure.
+//
+// It is possible for someone to try writing the code that relies on the desugaring to access a ref
+// into a packed-struct without explicity using unsafe. Here we test that the compiler warns the
+// user that such an access is still unsafe.
+fn test_missing_unsafe_warning_on_repr_packed() {
+    #[repr(packed)]
+    struct Foo { x: String }
+
+    let foo = Foo { x: String::new() };
+
+    let c = || {
+        println!("{}", foo.x);
+        //~^ WARNING: borrow of packed field is unsafe and requires unsafe function or block
+        //~| WARNING: this was previously accepted by the compiler but is being phased out
+        let _z = foo.x;
+    };
+
+    c();
+}
+
+fn main() {
+    test_missing_unsafe_warning_on_repr_packed();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
new file mode 100644
index 00000000000..440b2c54c0a
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
@@ -0,0 +1,22 @@
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/repr_packed.rs:3:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
+  --> $DIR/repr_packed.rs:25:24
+   |
+LL |         println!("{}", foo.x);
+   |                        ^^^^^
+   |
+   = note: `#[warn(safe_packed_borrows)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+
+warning: 2 warnings emitted
+
diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.rs b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs
new file mode 100644
index 00000000000..2b9ef2a76bb
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.rs
@@ -0,0 +1,103 @@
+#![feature(capture_disjoint_fields)]
+//~^ WARNING: the feature `capture_disjoint_fields` is incomplete
+//~| `#[warn(incomplete_features)]` on by default
+//~| see issue #53488 <https://github.com/rust-lang/rust/issues/53488>
+
+#![feature(rustc_attrs)]
+
+// `u8` aligned at a byte and are unaffected by repr(packed).
+// Therefore we can precisely (and safely) capture references to both the fields.
+fn test_alignment_not_affected() {
+    #[repr(packed)]
+    struct Foo { x: u8, y: u8 }
+
+    let mut foo = Foo { x: 0, y: 0 };
+
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let z1: &u8 = &foo.x;
+        //~^ NOTE: Capturing foo[(0, 0)] -> ImmBorrow
+        //~| NOTE: Min Capture foo[(0, 0)] -> ImmBorrow
+        let z2: &mut u8 = &mut foo.y;
+        //~^ NOTE: Capturing foo[(1, 0)] -> MutBorrow
+        //~| NOTE: Min Capture foo[(1, 0)] -> MutBorrow
+
+        *z2 = 42;
+
+        println!("({}, {})", z1, z2);
+    };
+
+    c();
+}
+
+// `String`, `u16` are not aligned at a one byte boundry and are thus affected by repr(packed).
+//
+// Here we test that the closure doesn't capture a reference point to `foo.x` but
+// rather capture `foo` entirely.
+fn test_alignment_affected() {
+    #[repr(packed)]
+    struct Foo { x: String, y: u16 }
+
+    let mut foo = Foo { x: String::new(), y: 0 };
+
+    let mut c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        let z1: &String = &foo.x;
+        let z2: &mut u16 = &mut foo.y;
+        //~^ NOTE: Capturing foo[] -> MutBorrow
+        //~| NOTE: Min Capture foo[] -> MutBorrow
+
+
+        *z2 = 42;
+
+        println!("({}, {})", z1, z2);
+    };
+
+    c();
+}
+
+// Given how the closure desugaring is implemented (at least at the time of writing this test),
+// we don't need to truncate the captured path to a reference into a packed-struct if the field
+// being referenced will be moved into the closure, since it's safe to move out a field from a
+// packed-struct.
+//
+// However to avoid surprises for the user, or issues when the closure is
+// inlined we will truncate the capture to access just the struct regardless of if the field
+// might get moved into the closure.
+fn test_truncation_when_ref_and_move() {
+    #[repr(packed)]
+    struct Foo { x: String }
+
+    let mut foo = Foo { x: String::new() };
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+    //~^ ERROR: First Pass analysis includes:
+    //~| ERROR: Min Capture analysis includes:
+        println!("{}", foo.x);
+        //~^ NOTE: Capturing foo[] -> ImmBorrow
+        //~| NOTE: Min Capture foo[] -> ByValue
+        //~| NOTE: foo[] used here
+        let _z = foo.x;
+        //~^ NOTE: Capturing foo[(0, 0)] -> ByValue
+        //~| NOTE: foo[] captured as ByValue here
+    };
+
+    c();
+}
+
+fn main() {
+    test_truncation_when_ref_and_move();
+    test_alignment_affected();
+    test_alignment_not_affected();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr
new file mode 100644
index 00000000000..0517dd04b6f
--- /dev/null
+++ b/src/test/ui/closures/2229_closure_analysis/repr_packed.stderr
@@ -0,0 +1,165 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/repr_packed.rs:16:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/repr_packed.rs:47:17
+   |
+LL |     let mut c = #[rustc_capture_analysis]
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/repr_packed.rs:81:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+warning: the feature `capture_disjoint_fields` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/repr_packed.rs:1:12
+   |
+LL | #![feature(capture_disjoint_fields)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #53488 <https://github.com/rust-lang/rust/issues/53488> for more information
+
+error: First Pass analysis includes:
+  --> $DIR/repr_packed.rs:19:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let z1: &u8 = &foo.x;
+...  |
+LL | |         println!("({}, {})", z1, z2);
+LL | |     };
+   | |_____^
+   |
+note: Capturing foo[(0, 0)] -> ImmBorrow
+  --> $DIR/repr_packed.rs:22:24
+   |
+LL |         let z1: &u8 = &foo.x;
+   |                        ^^^^^
+note: Capturing foo[(1, 0)] -> MutBorrow
+  --> $DIR/repr_packed.rs:25:32
+   |
+LL |         let z2: &mut u8 = &mut foo.y;
+   |                                ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/repr_packed.rs:19:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let z1: &u8 = &foo.x;
+...  |
+LL | |         println!("({}, {})", z1, z2);
+LL | |     };
+   | |_____^
+   |
+note: Min Capture foo[(0, 0)] -> ImmBorrow
+  --> $DIR/repr_packed.rs:22:24
+   |
+LL |         let z1: &u8 = &foo.x;
+   |                        ^^^^^
+note: Min Capture foo[(1, 0)] -> MutBorrow
+  --> $DIR/repr_packed.rs:25:32
+   |
+LL |         let z2: &mut u8 = &mut foo.y;
+   |                                ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/repr_packed.rs:50:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let z1: &String = &foo.x;
+...  |
+LL | |         println!("({}, {})", z1, z2);
+LL | |     };
+   | |_____^
+   |
+note: Capturing foo[] -> MutBorrow
+  --> $DIR/repr_packed.rs:54:33
+   |
+LL |         let z2: &mut u16 = &mut foo.y;
+   |                                 ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/repr_packed.rs:50:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         let z1: &String = &foo.x;
+...  |
+LL | |         println!("({}, {})", z1, z2);
+LL | |     };
+   | |_____^
+   |
+note: Min Capture foo[] -> MutBorrow
+  --> $DIR/repr_packed.rs:54:33
+   |
+LL |         let z2: &mut u16 = &mut foo.y;
+   |                                 ^^^^^
+
+error: First Pass analysis includes:
+  --> $DIR/repr_packed.rs:84:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{}", foo.x);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing foo[] -> ImmBorrow
+  --> $DIR/repr_packed.rs:87:24
+   |
+LL |         println!("{}", foo.x);
+   |                        ^^^^^
+note: Capturing foo[(0, 0)] -> ByValue
+  --> $DIR/repr_packed.rs:91:18
+   |
+LL |         let _z = foo.x;
+   |                  ^^^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/repr_packed.rs:84:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{}", foo.x);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture foo[] -> ByValue
+  --> $DIR/repr_packed.rs:87:24
+   |
+LL |         println!("{}", foo.x);
+   |                        ^^^^^ foo[] used here
+...
+LL |         let _z = foo.x;
+   |                  ^^^^^ foo[] captured as ByValue here
+
+error: aborting due to 9 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0658`.