]> git.lizzy.rs Git - rust.git/blob - src/test/ui/span/vec-must-not-hide-type-from-dropck.rs
Rollup merge of #87922 - Manishearth:c-enum-target-spec, r=nagisa,eddyb
[rust.git] / src / test / ui / span / vec-must-not-hide-type-from-dropck.rs
1 // Checking that `Vec<T>` cannot hide lifetimes within `T` when `T`
2 // implements `Drop` and might access methods of values that have
3 // since been deallocated.
4 //
5 // In this case, the values in question hold (non-zero) unique-ids
6 // that zero themselves out when dropped, and are wrapped in another
7 // type with a destructor that asserts that the ids it references are
8 // indeed non-zero (i.e., effectively checking that the id's are not
9 // dropped while there are still any outstanding references).
10 //
11 // However, the values in question are also formed into a
12 // cyclic-structure, ensuring that there is no way for all of the
13 // conditions above to be satisfied, meaning that if the dropck is
14 // sound, it should reject this code.
15
16
17
18 use std::cell::Cell;
19 use id::Id;
20
21 mod s {
22     use std::sync::atomic::{AtomicUsize, Ordering};
23
24     static S_COUNT: AtomicUsize = AtomicUsize::new(0);
25
26     /// generates globally unique count (global across the current
27     /// process, that is)
28     pub fn next_count() -> usize {
29         S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
30     }
31 }
32
33 mod id {
34     use s;
35
36     /// Id represents a globally unique identifier (global across the
37     /// current process, that is). When dropped, it automatically
38     /// clears its `count` field, but leaves `orig_count` untouched,
39     /// so that if there are subsequent (erroneous) invocations of its
40     /// method (which is unsound), we can observe it by seeing that
41     /// the `count` is 0 while the `orig_count` is non-zero.
42     #[derive(Debug)]
43     pub struct Id {
44         orig_count: usize,
45         count: usize,
46     }
47
48     impl Id {
49         /// Creates an `Id` with a globally unique count.
50         pub fn new() -> Id {
51             let c = s::next_count();
52             println!("building Id {}", c);
53             Id { orig_count: c, count: c }
54         }
55         /// returns the `count` of self; should be non-zero if
56         /// everything is working.
57         pub fn count(&self) -> usize {
58             println!("Id::count on {} returns {}", self.orig_count, self.count);
59             self.count
60         }
61     }
62
63     impl Drop for Id {
64         fn drop(&mut self) {
65             println!("dropping Id {}", self.count);
66             self.count = 0;
67         }
68     }
69 }
70
71 trait HasId {
72     fn count(&self) -> usize;
73 }
74
75 #[derive(Debug)]
76 struct CheckId<T:HasId> {
77     v: T
78 }
79
80 #[allow(non_snake_case)]
81 fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
82
83 impl<T:HasId> Drop for CheckId<T> {
84     fn drop(&mut self) {
85         assert!(self.v.count() > 0);
86     }
87 }
88
89 #[derive(Debug)]
90 struct C<'a> {
91     id: Id,
92     v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
93 }
94
95 impl<'a> HasId for Cell<Option<&'a C<'a>>> {
96     fn count(&self) -> usize {
97         match self.get() {
98             None => 1,
99             Some(c) => c.id.count(),
100         }
101     }
102 }
103
104 impl<'a> C<'a> {
105     fn new() -> C<'a> {
106         C { id: Id::new(), v: Vec::new() }
107     }
108 }
109
110 fn f() {
111     let (mut c1, mut c2);
112     c1 = C::new();
113     c2 = C::new();
114
115     c1.v.push(CheckId(Cell::new(None)));
116     c2.v.push(CheckId(Cell::new(None)));
117     c1.v[0].v.set(Some(&c2));
118     //~^ ERROR `c2` does not live long enough
119     c2.v[0].v.set(Some(&c1));
120     //~^ ERROR `c1` does not live long enough
121 }
122
123 fn main() {
124     f();
125 }