Skip to content

Commit 911ed33

Browse files
committed
compile-fail tests.
Some compile-fail tests illustrated cases to be rejected by dropck, including ones that check cyclic data cases designed to exposed bugs if they are actually tricked into running by an unsound analysis. E.g. these exposed bugs in earlier broken ways of handling `Vec<T>`.
1 parent 33028e5 commit 911ed33

8 files changed

+647
-0
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Tests the new destructor semantics.
12+
13+
use std::cell::RefCell;
14+
15+
fn main() {
16+
let b = {
17+
let a = Box::new(RefCell::new(4i8));
18+
*a.borrow() + 1i8 //~ ERROR `*a` does not live long enough
19+
};
20+
println!("{}", b);
21+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Reject mixing cyclic structure and Drop when using fixed length
12+
// arrays.
13+
//
14+
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
15+
16+
use std::cell::Cell;
17+
use id::Id;
18+
19+
mod s {
20+
#![allow(unstable)]
21+
use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
22+
23+
static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
24+
25+
pub fn next_count() -> usize {
26+
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
27+
}
28+
}
29+
30+
mod id {
31+
use s;
32+
#[derive(Debug)]
33+
pub struct Id {
34+
orig_count: usize,
35+
count: usize,
36+
}
37+
38+
impl Id {
39+
pub fn new() -> Id {
40+
let c = s::next_count();
41+
println!("building Id {}", c);
42+
Id { orig_count: c, count: c }
43+
}
44+
pub fn count(&self) -> usize {
45+
println!("Id::count on {} returns {}", self.orig_count, self.count);
46+
self.count
47+
}
48+
}
49+
50+
impl Drop for Id {
51+
fn drop(&mut self) {
52+
println!("dropping Id {}", self.count);
53+
self.count = 0;
54+
}
55+
}
56+
}
57+
58+
trait HasId {
59+
fn count(&self) -> usize;
60+
}
61+
62+
#[derive(Debug)]
63+
struct CheckId<T:HasId> {
64+
v: T
65+
}
66+
67+
#[allow(non_snake_case)]
68+
fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
69+
70+
impl<T:HasId> Drop for CheckId<T> {
71+
fn drop(&mut self) {
72+
assert!(self.v.count() > 0);
73+
}
74+
}
75+
76+
#[derive(Debug)]
77+
struct B<'a> {
78+
id: Id,
79+
a: [CheckId<Cell<Option<&'a B<'a>>>>; 2]
80+
}
81+
82+
impl<'a> HasId for Cell<Option<&'a B<'a>>> {
83+
fn count(&self) -> usize {
84+
match self.get() {
85+
None => 1,
86+
Some(b) => b.id.count(),
87+
}
88+
}
89+
}
90+
91+
impl<'a> B<'a> {
92+
fn new() -> B<'a> {
93+
B { id: Id::new(), a: [CheckId(Cell::new(None)), CheckId(Cell::new(None))] }
94+
}
95+
}
96+
97+
fn f() {
98+
let (b1, b2, b3);
99+
b1 = B::new();
100+
b2 = B::new();
101+
b3 = B::new();
102+
b1.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
103+
b1.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough
104+
b2.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
105+
b2.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough
106+
b3.a[0].v.set(Some(&b1)); //~ ERROR `b1` does not live long enough
107+
b3.a[1].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
108+
}
109+
110+
fn main() {
111+
f();
112+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// A simple example of an unsound mixing of cyclic structure and Drop.
12+
//
13+
// Each `D` has a name and an optional reference to another `D`
14+
// sibling, but also implements a drop method that prints out its own
15+
// name as well as the name of its sibling.
16+
//
17+
// By setting up a cyclic structure, the drop code cannot possibly
18+
// work. Therefore this code must be rejected.
19+
//
20+
// (As it turns out, essentially any attempt to install a sibling here
21+
// will be rejected, regardless of whether it forms a cyclic
22+
// structure or not. This is because the use of the same lifetime
23+
// `'a` in `&'a D<'a>` cannot be satisfied when `D<'a>` implements
24+
// `Drop`.)
25+
26+
use std::cell::Cell;
27+
28+
struct D<'a> {
29+
name: String,
30+
p: Cell<Option<&'a D<'a>>>,
31+
}
32+
33+
impl<'a> D<'a> {
34+
fn new(name: String) -> D<'a> { D { name: name, p: Cell::new(None) } }
35+
}
36+
37+
impl<'a> Drop for D<'a> {
38+
fn drop(&mut self) {
39+
println!("dropping {} whose sibling is {:?}",
40+
self.name, self.p.get().map(|d| &d.name));
41+
}
42+
}
43+
44+
fn g() {
45+
let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2")));
46+
d1.p.set(Some(&d2)); //~ ERROR `d2` does not live long enough
47+
d2.p.set(Some(&d1)); //~ ERROR `d1` does not live long enough
48+
}
49+
50+
fn main() {
51+
g();
52+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Reject mixing cyclic structure and Drop when using TypedArena.
12+
//
13+
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
14+
//
15+
// (Also compare against compile-fail/dropck_tarena_unsound_drop.rs,
16+
// which is a reduction of this code to more directly show the reason
17+
// for the error message we see here.)
18+
19+
#![allow(unstable)]
20+
21+
extern crate arena;
22+
23+
use arena::TypedArena;
24+
use std::cell::Cell;
25+
use id::Id;
26+
27+
mod s {
28+
#![allow(unstable)]
29+
use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
30+
31+
static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
32+
33+
pub fn next_count() -> usize {
34+
S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
35+
}
36+
}
37+
38+
mod id {
39+
use s;
40+
#[derive(Debug)]
41+
pub struct Id {
42+
orig_count: usize,
43+
count: usize,
44+
}
45+
46+
impl Id {
47+
pub fn new() -> Id {
48+
let c = s::next_count();
49+
println!("building Id {}", c);
50+
Id { orig_count: c, count: c }
51+
}
52+
pub fn count(&self) -> usize {
53+
println!("Id::count on {} returns {}", self.orig_count, self.count);
54+
self.count
55+
}
56+
}
57+
58+
impl Drop for Id {
59+
fn drop(&mut self) {
60+
println!("dropping Id {}", self.count);
61+
self.count = 0;
62+
}
63+
}
64+
}
65+
66+
trait HasId {
67+
fn count(&self) -> usize;
68+
}
69+
70+
#[derive(Debug)]
71+
struct CheckId<T:HasId> {
72+
v: T
73+
}
74+
75+
#[allow(non_snake_case)]
76+
fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
77+
78+
impl<T:HasId> Drop for CheckId<T> {
79+
fn drop(&mut self) {
80+
assert!(self.v.count() > 0);
81+
}
82+
}
83+
84+
#[derive(Debug)]
85+
struct C<'a> {
86+
id: Id,
87+
v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
88+
}
89+
90+
impl<'a> HasId for Cell<Option<&'a C<'a>>> {
91+
fn count(&self) -> usize {
92+
match self.get() {
93+
None => 1,
94+
Some(c) => c.id.count(),
95+
}
96+
}
97+
}
98+
99+
impl<'a> C<'a> {
100+
fn new() -> C<'a> {
101+
C { id: Id::new(), v: Vec::new() }
102+
}
103+
}
104+
105+
fn f<'a>(arena: &'a TypedArena<C<'a>>) {
106+
let c1 = arena.alloc(C::new());
107+
let c2 = arena.alloc(C::new());
108+
let c3 = arena.alloc(C::new());
109+
110+
c1.v.push(CheckId(Cell::new(None)));
111+
c1.v.push(CheckId(Cell::new(None)));
112+
c2.v.push(CheckId(Cell::new(None)));
113+
c2.v.push(CheckId(Cell::new(None)));
114+
c3.v.push(CheckId(Cell::new(None)));
115+
c3.v.push(CheckId(Cell::new(None)));
116+
117+
c1.v[0].v.set(Some(c2));
118+
c1.v[1].v.set(Some(c3));
119+
c2.v[0].v.set(Some(c2));
120+
c2.v[1].v.set(Some(c3));
121+
c3.v[0].v.set(Some(c1));
122+
c3.v[1].v.set(Some(c2));
123+
}
124+
125+
fn main() {
126+
let arena = TypedArena::new();
127+
f(&arena); //~ ERROR `arena` does not live long enough
128+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Check that a arena (TypedArena) cannot carry elements whose drop
12+
// methods might access borrowed data of lifetime that does not
13+
// strictly outlive the arena itself.
14+
//
15+
// Compare against run-pass/dropck_tarena_sound_drop.rs, which shows a
16+
// similar setup, but loosens `f` so that the struct `C<'a>` can be
17+
// fed a lifetime longer than that of the arena.
18+
//
19+
// (Also compare against dropck_tarena_cycle_checked.rs, from which
20+
// this was reduced to better understand its error message.)
21+
22+
#![allow(unstable)]
23+
24+
extern crate arena;
25+
26+
use arena::TypedArena;
27+
28+
trait HasId { fn count(&self) -> usize; }
29+
30+
struct CheckId<T:HasId> { v: T }
31+
32+
// In the code below, the impl of HasId for `&'a usize` does not
33+
// actually access the borrowed data, but the point is that the
34+
// interface to CheckId does not (and cannot) know that, and therefore
35+
// when encountering the a value V of type CheckId<S>, we must
36+
// conservatively force the type S to strictly outlive V.
37+
impl<T:HasId> Drop for CheckId<T> {
38+
fn drop(&mut self) {
39+
assert!(self.v.count() > 0);
40+
}
41+
}
42+
43+
struct C<'a> { v: CheckId<&'a usize>, }
44+
45+
impl<'a> HasId for &'a usize { fn count(&self) -> usize { 1 } }
46+
47+
fn f<'a>(_arena: &'a TypedArena<C<'a>>) {}
48+
49+
fn main() {
50+
let arena: TypedArena<C> = TypedArena::new();
51+
f(&arena); //~ ERROR `arena` does not live long enough
52+
}

0 commit comments

Comments
 (0)