summaryrefslogtreecommitdiffstats
path: root/src/test/ui/span/dropck_direct_cycle_with_drop.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/span/dropck_direct_cycle_with_drop.rs')
-rw-r--r--src/test/ui/span/dropck_direct_cycle_with_drop.rs44
1 files changed, 44 insertions, 0 deletions
diff --git a/src/test/ui/span/dropck_direct_cycle_with_drop.rs b/src/test/ui/span/dropck_direct_cycle_with_drop.rs
new file mode 100644
index 000000000..14d6e6654
--- /dev/null
+++ b/src/test/ui/span/dropck_direct_cycle_with_drop.rs
@@ -0,0 +1,44 @@
+// A simple example of an unsound mixing of cyclic structure and Drop.
+//
+// Each `D` has a name and an optional reference to another `D`
+// sibling, but also implements a drop method that prints out its own
+// name as well as the name of its sibling.
+//
+// By setting up a cyclic structure, the drop code cannot possibly
+// work. Therefore this code must be rejected.
+//
+// (As it turns out, essentially any attempt to install a sibling here
+// will be rejected, regardless of whether it forms a cyclic
+// structure or not. This is because the use of the same lifetime
+// `'a` in `&'a D<'a>` cannot be satisfied when `D<'a>` implements
+// `Drop`.)
+
+use std::cell::Cell;
+
+struct D<'a> {
+ name: String,
+ p: Cell<Option<&'a D<'a>>>,
+}
+
+impl<'a> D<'a> {
+ fn new(name: String) -> D<'a> { D { name: name, p: Cell::new(None) } }
+}
+
+impl<'a> Drop for D<'a> {
+ fn drop(&mut self) {
+ println!("dropping {} whose sibling is {:?}",
+ self.name, self.p.get().map(|d| &d.name));
+ }
+}
+
+fn g() {
+ let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2")));
+ d1.p.set(Some(&d2));
+ //~^ ERROR `d2` does not live long enough
+ d2.p.set(Some(&d1));
+ //~^ ERROR `d1` does not live long enough
+}
+
+fn main() {
+ g();
+}