--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests the new destructor semantics.
+
+use std::cell::RefCell;
+
+fn main() {
+ let b = {
+ let a = Box::new(RefCell::new(4i8));
+ *a.borrow() + 1i8 //~ ERROR `*a` does not live long enough
+ };
+ println!("{}", b);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Reject mixing cyclic structure and Drop when using fixed length
+// arrays.
+//
+// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+ #![allow(unstable)]
+ use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+ static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+ pub fn next_count() -> usize {
+ S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+ }
+}
+
+mod id {
+ use s;
+ #[derive(Debug)]
+ pub struct Id {
+ orig_count: usize,
+ count: usize,
+ }
+
+ impl Id {
+ pub fn new() -> Id {
+ let c = s::next_count();
+ println!("building Id {}", c);
+ Id { orig_count: c, count: c }
+ }
+ pub fn count(&self) -> usize {
+ println!("Id::count on {} returns {}", self.orig_count, self.count);
+ self.count
+ }
+ }
+
+ impl Drop for Id {
+ fn drop(&mut self) {
+ println!("dropping Id {}", self.count);
+ self.count = 0;
+ }
+ }
+}
+
+trait HasId {
+ fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+ v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+ fn drop(&mut self) {
+ assert!(self.v.count() > 0);
+ }
+}
+
+#[derive(Debug)]
+struct B<'a> {
+ id: Id,
+ a: [CheckId<Cell<Option<&'a B<'a>>>>; 2]
+}
+
+impl<'a> HasId for Cell<Option<&'a B<'a>>> {
+ fn count(&self) -> usize {
+ match self.get() {
+ None => 1,
+ Some(b) => b.id.count(),
+ }
+ }
+}
+
+impl<'a> B<'a> {
+ fn new() -> B<'a> {
+ B { id: Id::new(), a: [CheckId(Cell::new(None)), CheckId(Cell::new(None))] }
+ }
+}
+
+fn f() {
+ let (b1, b2, b3);
+ b1 = B::new();
+ b2 = B::new();
+ b3 = B::new();
+ b1.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
+ b1.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough
+ b2.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
+ b2.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough
+ b3.a[0].v.set(Some(&b1)); //~ ERROR `b1` does not live long enough
+ b3.a[1].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
+}
+
+fn main() {
+ f();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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`.)
+
+#![feature(unsafe_destructor)]
+
+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) } }
+}
+
+#[unsafe_destructor]
+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();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Reject mixing cyclic structure and Drop when using TypedArena.
+//
+// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+//
+// (Also compare against compile-fail/dropck_tarena_unsound_drop.rs,
+// which is a reduction of this code to more directly show the reason
+// for the error message we see here.)
+
+#![allow(unstable)]
+#![feature(unsafe_destructor)]
+
+extern crate arena;
+
+use arena::TypedArena;
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+ #![allow(unstable)]
+ use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+ static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+ pub fn next_count() -> usize {
+ S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+ }
+}
+
+mod id {
+ use s;
+ #[derive(Debug)]
+ pub struct Id {
+ orig_count: usize,
+ count: usize,
+ }
+
+ impl Id {
+ pub fn new() -> Id {
+ let c = s::next_count();
+ println!("building Id {}", c);
+ Id { orig_count: c, count: c }
+ }
+ pub fn count(&self) -> usize {
+ println!("Id::count on {} returns {}", self.orig_count, self.count);
+ self.count
+ }
+ }
+
+ impl Drop for Id {
+ fn drop(&mut self) {
+ println!("dropping Id {}", self.count);
+ self.count = 0;
+ }
+ }
+}
+
+trait HasId {
+ fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+ v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+ fn drop(&mut self) {
+ assert!(self.v.count() > 0);
+ }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+ id: Id,
+ v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
+}
+
+impl<'a> HasId for Cell<Option<&'a C<'a>>> {
+ fn count(&self) -> usize {
+ match self.get() {
+ None => 1,
+ Some(c) => c.id.count(),
+ }
+ }
+}
+
+impl<'a> C<'a> {
+ fn new() -> C<'a> {
+ C { id: Id::new(), v: Vec::new() }
+ }
+}
+
+fn f<'a>(arena: &'a TypedArena<C<'a>>) {
+ let c1 = arena.alloc(C::new());
+ let c2 = arena.alloc(C::new());
+ let c3 = arena.alloc(C::new());
+
+ c1.v.push(CheckId(Cell::new(None)));
+ c1.v.push(CheckId(Cell::new(None)));
+ c2.v.push(CheckId(Cell::new(None)));
+ c2.v.push(CheckId(Cell::new(None)));
+ c3.v.push(CheckId(Cell::new(None)));
+ c3.v.push(CheckId(Cell::new(None)));
+
+ c1.v[0].v.set(Some(c2));
+ c1.v[1].v.set(Some(c3));
+ c2.v[0].v.set(Some(c2));
+ c2.v[1].v.set(Some(c3));
+ c3.v[0].v.set(Some(c1));
+ c3.v[1].v.set(Some(c2));
+}
+
+fn main() {
+ let arena = TypedArena::new();
+ f(&arena); //~ ERROR `arena` does not live long enough
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that a arena (TypedArena) cannot carry elements whose drop
+// methods might access borrowed data of lifetime that does not
+// strictly outlive the arena itself.
+//
+// Compare against run-pass/dropck_tarena_sound_drop.rs, which shows a
+// similar setup, but loosens `f` so that the struct `C<'a>` can be
+// fed a lifetime longer than that of the arena.
+//
+// (Also compare against dropck_tarena_cycle_checked.rs, from which
+// this was reduced to better understand its error message.)
+
+#![allow(unstable)]
+#![feature(unsafe_destructor)]
+
+extern crate arena;
+
+use arena::TypedArena;
+
+trait HasId { fn count(&self) -> usize; }
+
+struct CheckId<T:HasId> { v: T }
+
+// In the code below, the impl of HasId for `&'a usize` does not
+// actually access the borrowed data, but the point is that the
+// interface to CheckId does not (and cannot) know that, and therefore
+// when encountering the a value V of type CheckId<S>, we must
+// conservatively force the type S to strictly outlive V.
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+ fn drop(&mut self) {
+ assert!(self.v.count() > 0);
+ }
+}
+
+struct C<'a> { v: CheckId<&'a usize>, }
+
+impl<'a> HasId for &'a usize { fn count(&self) -> usize { 1 } }
+
+fn f<'a>(_arena: &'a TypedArena<C<'a>>) {}
+
+fn main() {
+ let arena: TypedArena<C> = TypedArena::new();
+ f(&arena); //~ ERROR `arena` does not live long enough
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Reject mixing cyclic structure and Drop when using Vec.
+//
+// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+ #![allow(unstable)]
+ use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+ static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+ pub fn next_count() -> usize {
+ S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+ }
+}
+
+mod id {
+ use s;
+ #[derive(Debug)]
+ pub struct Id {
+ orig_count: usize,
+ count: usize,
+ }
+
+ impl Id {
+ pub fn new() -> Id {
+ let c = s::next_count();
+ println!("building Id {}", c);
+ Id { orig_count: c, count: c }
+ }
+ pub fn count(&self) -> usize {
+ println!("Id::count on {} returns {}", self.orig_count, self.count);
+ self.count
+ }
+ }
+
+ impl Drop for Id {
+ fn drop(&mut self) {
+ println!("dropping Id {}", self.count);
+ self.count = 0;
+ }
+ }
+}
+
+trait HasId {
+ fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+ v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+ fn drop(&mut self) {
+ assert!(self.v.count() > 0);
+ }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+ id: Id,
+ v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
+}
+
+impl<'a> HasId for Cell<Option<&'a C<'a>>> {
+ fn count(&self) -> usize {
+ match self.get() {
+ None => 1,
+ Some(c) => c.id.count(),
+ }
+ }
+}
+
+impl<'a> C<'a> {
+ fn new() -> C<'a> {
+ C { id: Id::new(), v: Vec::new() }
+ }
+}
+
+fn f() {
+ let (mut c1, mut c2, mut c3);
+ c1 = C::new();
+ c2 = C::new();
+ c3 = C::new();
+
+ c1.v.push(CheckId(Cell::new(None)));
+ c1.v.push(CheckId(Cell::new(None)));
+ c2.v.push(CheckId(Cell::new(None)));
+ c2.v.push(CheckId(Cell::new(None)));
+ c3.v.push(CheckId(Cell::new(None)));
+ c3.v.push(CheckId(Cell::new(None)));
+
+ c1.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+ c1.v[1].v.set(Some(&c3)); //~ ERROR `c3` does not live long enough
+ c2.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+ c2.v[1].v.set(Some(&c3)); //~ ERROR `c3` does not live long enough
+ c3.v[0].v.set(Some(&c1)); //~ ERROR `c1` does not live long enough
+ c3.v[1].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+}
+
+fn main() {
+ f();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Checking that `Vec<T>` cannot hide lifetimes within `T` when `T`
+// implements `Drop` and might access methods of values that have
+// since been deallocated.
+//
+// In this case, the values in question hold (non-zero) unique-ids
+// that zero themselves out when dropped, and are wrapped in another
+// type with a destructor that asserts that the ids it references are
+// indeed non-zero (i.e., effectively checking that the id's are not
+// dropped while there are still any outstanding references).
+//
+// However, the values in question are also formed into a
+// cyclic-structure, ensuring that there is no way for all of the
+// conditions above to be satisfied, meaning that if the dropck is
+// sound, it should reject this code.
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+ #![allow(unstable)]
+ use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+ static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+ /// generates globally unique count (global across the current
+ /// process, that is)
+ pub fn next_count() -> usize {
+ S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+ }
+}
+
+mod id {
+ use s;
+
+ /// Id represents a globally unique identifier (global across the
+ /// current process, that is). When dropped, it automatically
+ /// clears its `count` field, but leaves `orig_count` untouched,
+ /// so that if there are subsequent (erroneous) invocations of its
+ /// method (which is unsound), we can observe it by seeing that
+ /// the `count` is 0 while the `orig_count` is non-zero.
+ #[derive(Debug)]
+ pub struct Id {
+ orig_count: usize,
+ count: usize,
+ }
+
+ impl Id {
+ /// Creates an `Id` with a globally unique count.
+ pub fn new() -> Id {
+ let c = s::next_count();
+ println!("building Id {}", c);
+ Id { orig_count: c, count: c }
+ }
+ /// returns the `count` of self; should be non-zero if
+ /// everything is working.
+ pub fn count(&self) -> usize {
+ println!("Id::count on {} returns {}", self.orig_count, self.count);
+ self.count
+ }
+ }
+
+ impl Drop for Id {
+ fn drop(&mut self) {
+ println!("dropping Id {}", self.count);
+ self.count = 0;
+ }
+ }
+}
+
+trait HasId {
+ fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+ v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+ fn drop(&mut self) {
+ assert!(self.v.count() > 0);
+ }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+ id: Id,
+ v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
+}
+
+impl<'a> HasId for Cell<Option<&'a C<'a>>> {
+ fn count(&self) -> usize {
+ match self.get() {
+ None => 1,
+ Some(c) => c.id.count(),
+ }
+ }
+}
+
+impl<'a> C<'a> {
+ fn new() -> C<'a> {
+ C { id: Id::new(), v: Vec::new() }
+ }
+}
+
+fn f() {
+ let (mut c1, mut c2);
+ c1 = C::new();
+ c2 = C::new();
+
+ c1.v.push(CheckId(Cell::new(None)));
+ c2.v.push(CheckId(Cell::new(None)));
+ c1.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+ c2.v[0].v.set(Some(&c1)); //~ ERROR `c1` does not live long enough
+}
+
+fn main() {
+ f();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test is a simple example of code that violates the dropck
+// rules: it pushes `&x` and `&y` into `v`, but the referenced data
+// will be dropped before the vector itself is.
+
+// (In principle we know that `Vec` does not reference the data it
+// owns from within its drop code, apart from calling drop on each
+// element it owns; thus, for data like this, it seems like we could
+// loosen the restrictions here if we wanted. But it also is not
+// clear whether such loosening is terribly important.)
+
+fn main() {
+ let mut v = Vec::new();
+
+ let x: i8 = 3;
+ let y: i8 = 4;
+
+ v.push(&x); //~ ERROR `x` does not live long enough
+ v.push(&y); //~ ERROR `y` does not live long enough
+
+ assert_eq!(v.as_slice(), [&3, &4]);
+}