]> git.lizzy.rs Git - rust.git/commitdiff
compile-fail tests.
authorFelix S. Klock II <pnkfelix@pnkfx.org>
Mon, 27 Oct 2014 11:58:30 +0000 (12:58 +0100)
committerFelix S. Klock II <pnkfelix@pnkfx.org>
Wed, 11 Feb 2015 12:51:21 +0000 (13:51 +0100)
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>`.

(Note that all the uses of `unsafe_destructor` are just placating the
simple analysis used for that feature, which will eventually go away
once we have put the dropck through its paces.)

src/test/compile-fail/destructor-restrictions.rs [new file with mode: 0644]
src/test/compile-fail/dropck_arr_cycle_checked.rs [new file with mode: 0644]
src/test/compile-fail/dropck_direct_cycle_with_drop.rs [new file with mode: 0644]
src/test/compile-fail/dropck_tarena_cycle_checked.rs [new file with mode: 0644]
src/test/compile-fail/dropck_tarena_unsound_drop.rs [new file with mode: 0644]
src/test/compile-fail/dropck_vec_cycle_checked.rs [new file with mode: 0644]
src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs [new file with mode: 0644]
src/test/compile-fail/vec_refs_data_with_early_death.rs [new file with mode: 0644]

diff --git a/src/test/compile-fail/destructor-restrictions.rs b/src/test/compile-fail/destructor-restrictions.rs
new file mode 100644 (file)
index 0000000..0836cd1
--- /dev/null
@@ -0,0 +1,21 @@
+// 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);
+}
diff --git a/src/test/compile-fail/dropck_arr_cycle_checked.rs b/src/test/compile-fail/dropck_arr_cycle_checked.rs
new file mode 100644 (file)
index 0000000..3aa2fae
--- /dev/null
@@ -0,0 +1,115 @@
+// 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();
+}
diff --git a/src/test/compile-fail/dropck_direct_cycle_with_drop.rs b/src/test/compile-fail/dropck_direct_cycle_with_drop.rs
new file mode 100644 (file)
index 0000000..b9df713
--- /dev/null
@@ -0,0 +1,55 @@
+// 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();
+}
diff --git a/src/test/compile-fail/dropck_tarena_cycle_checked.rs b/src/test/compile-fail/dropck_tarena_cycle_checked.rs
new file mode 100644 (file)
index 0000000..74e3c72
--- /dev/null
@@ -0,0 +1,130 @@
+// 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
+}
diff --git a/src/test/compile-fail/dropck_tarena_unsound_drop.rs b/src/test/compile-fail/dropck_tarena_unsound_drop.rs
new file mode 100644 (file)
index 0000000..64d77e9
--- /dev/null
@@ -0,0 +1,54 @@
+// 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
+}
diff --git a/src/test/compile-fail/dropck_vec_cycle_checked.rs b/src/test/compile-fail/dropck_vec_cycle_checked.rs
new file mode 100644 (file)
index 0000000..3f69c7d
--- /dev/null
@@ -0,0 +1,122 @@
+// 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();
+}
diff --git a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs
new file mode 100644 (file)
index 0000000..6aaf512
--- /dev/null
@@ -0,0 +1,135 @@
+// 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();
+}
diff --git a/src/test/compile-fail/vec_refs_data_with_early_death.rs b/src/test/compile-fail/vec_refs_data_with_early_death.rs
new file mode 100644 (file)
index 0000000..a191b3e
--- /dev/null
@@ -0,0 +1,31 @@
+// 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]);
+}