summaryrefslogtreecommitdiffstats
path: root/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs')
-rw-r--r--tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs114
1 files changed, 114 insertions, 0 deletions
diff --git a/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs b/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
new file mode 100644
index 000000000..b3f655628
--- /dev/null
+++ b/tests/ui/nll/issue-45696-long-live-borrows-in-boxes.rs
@@ -0,0 +1,114 @@
+// rust-lang/rust#45696: This test is checking that we can return
+// mutable borrows owned by boxes even when the boxes are dropped.
+
+// run-pass
+
+// This function shows quite directly what is going on: We have a
+// reborrow of contents within the box.
+fn return_borrow_from_dropped_box_1(x: Box<&mut u32>) -> &mut u32 { &mut **x }
+
+// This function is the way you'll probably see this in practice (the
+// reborrow is now implicit).
+fn return_borrow_from_dropped_box_2(x: Box<&mut u32>) -> &mut u32 { *x }
+
+// For the remaining tests we just add some fields or other
+// indirection to ensure that the compiler isn't just special-casing
+// the above `Box<&mut T>` as the only type that would work.
+
+// Here we add a tuple of indirection between the box and the
+// reference.
+type BoxedTup<'a, 'b> = Box<(&'a mut u32, &'b mut u32)>;
+
+fn return_borrow_of_field_from_dropped_box_1<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ &mut *x.0
+}
+
+fn return_borrow_of_field_from_dropped_box_2<'a>(x: BoxedTup<'a, '_>) -> &'a mut u32 {
+ x.0
+}
+
+fn return_borrow_from_dropped_tupled_box_1<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ &mut *(x.0).0
+}
+
+fn return_borrow_from_dropped_tupled_box_2<'a>(x: (BoxedTup<'a, '_>, &mut u32)) -> &'a mut u32 {
+ (x.0).0
+}
+
+fn basic_tests() {
+ let mut x = 2;
+ let mut y = 3;
+ let mut z = 4;
+ *return_borrow_from_dropped_box_1(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (12, 3, 4));
+ *return_borrow_from_dropped_box_2(Box::new(&mut x)) += 10;
+ assert_eq!((x, y, z), (22, 3, 4));
+ *return_borrow_of_field_from_dropped_box_1(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (32, 3, 4));
+ *return_borrow_of_field_from_dropped_box_2(Box::new((&mut x, &mut y))) += 10;
+ assert_eq!((x, y, z), (42, 3, 4));
+ *return_borrow_from_dropped_tupled_box_1((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (52, 3, 4));
+ *return_borrow_from_dropped_tupled_box_2((Box::new((&mut x, &mut y)), &mut z)) += 10;
+ assert_eq!((x, y, z), (62, 3, 4));
+}
+
+// These scribbling tests have been transcribed from
+// issue-45696-scribble-on-boxed-borrow.rs
+//
+// In the context of that file, these tests are meant to show cases
+// that should be *accepted* by the compiler, so here we are actually
+// checking that the code we get when they are compiled matches our
+// expectations.
+
+struct Scribble<'a>(&'a mut u32);
+
+impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
+
+// this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
+// to strictly outlive `'a`
+fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
+ &mut *s.0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
+ &mut *(*s).0
+}
+
+// this, by analogy to previous case, is also okay.
+fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
+ &mut *(**s).0
+}
+
+fn scribbling_tests() {
+ let mut x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *borrowed_scribble(&mut long_lived) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+ x = 1;
+ {
+ let mut long_lived = Scribble(&mut x);
+ *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
+ assert_eq!(*long_lived.0, 11);
+ // (Scribble dtor runs here, after `&mut`-borrow above ends)
+ }
+ assert_eq!(x, 42);
+}
+
+fn main() {
+ basic_tests();
+ scribbling_tests();
+}