Auto merge of #37174 - mikhail-m1:dnlle, r=jonathandturner

improve "Doesn't live long enough" error

I've fixed only with same case

issue #36537 part of  #35233
r? @jonathandturner
This commit is contained in:
bors 2016-10-21 15:57:35 -07:00 committed by GitHub
commit a6fa57291b
48 changed files with 711 additions and 98 deletions

View file

@ -1,61 +0,0 @@
// 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.
fn f() {
let old = ['o']; // statement 0
let mut v1 = Vec::new(); // statement 1
let mut v2 = Vec::new(); // statement 2
let young = ['y']; // statement 3
v2.push(&young[0]); // statement 4
//~^ ERROR `young[..]` does not live long enough
//~| NOTE does not live long enough
//~| NOTE values in a scope are dropped in the opposite order they are created
let mut v3 = Vec::new(); // statement 5
v3.push(&'x'); // statement 6
//~^ ERROR borrowed value does not live long enough
//~| NOTE temporary value created here
//~| NOTE temporary value only lives until here
//~| NOTE consider using a `let` binding to increase its lifetime
{
let mut v4 = Vec::new(); // (sub) statement 0
v4.push(&'y');
//~^ ERROR borrowed value does not live long enough
//~| NOTE temporary value created here
//~| NOTE temporary value only lives until here
//~| NOTE consider using a `let` binding to increase its lifetime
} // (statement 7)
//~^ NOTE temporary value needs to live until here
let mut v5 = Vec::new(); // statement 8
v5.push(&'z');
//~^ ERROR borrowed value does not live long enough
//~| NOTE temporary value created here
//~| NOTE temporary value only lives until here
//~| NOTE consider using a `let` binding to increase its lifetime
v1.push(&old[0]);
}
//~^ NOTE borrowed value dropped before borrower
//~| NOTE temporary value needs to live until here
//~| NOTE temporary value needs to live until here
fn main() {
f();
}

View file

@ -1,57 +0,0 @@
// 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.
// This test used to be part of a run-pass test, but revised outlives
// rule means that it no longer compiles.
#![allow(unused_variables)]
trait Trait<'a> {
fn long(&'a self) -> isize;
fn short<'b>(&'b self) -> isize;
}
fn object_invoke1<'d>(x: &'d Trait<'d>) -> (isize, isize) { loop { } }
trait MakerTrait {
fn mk() -> Self;
}
fn make_val<T:MakerTrait>() -> T {
MakerTrait::mk()
}
impl<'t> MakerTrait for Box<Trait<'t>+'static> {
fn mk() -> Box<Trait<'t>+'static> { loop { } }
}
pub fn main() {
let m : Box<Trait+'static> = make_val();
assert_eq!(object_invoke1(&*m), (4,5));
//~^ ERROR `*m` does not live long enough
// the problem here is that the full type of `m` is
//
// Box<Trait<'m>+'static>
//
// Here `'m` must be exactly the lifetime of the variable `m`.
// This is because of two requirements:
// 1. First, the basic type rules require that the
// type of `m`'s value outlives the lifetime of `m`. This puts a lower
// bound `'m`.
//
// 2. Meanwhile, the signature of `object_invoke1` requires that
// we create a reference of type `&'d Trait<'d>` for some `'d`.
// `'d` cannot outlive `'m`, so that forces the lifetime to be `'m`.
//
// This then conflicts with the dropck rules, which require that
// the type of `m` *strictly outlives* `'m`. Hence we get an
// error.
}

View file

@ -1,113 +0,0 @@
// 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(const_fn)]
use std::cell::Cell;
use id::Id;
mod s {
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
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 } }
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();
}

View file

@ -1,52 +0,0 @@
// 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`.)
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();
}

View file

@ -1,47 +0,0 @@
// 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 dropck does the right thing with misc. Ty variants
use std::fmt;
struct NoisyDrop<T: fmt::Debug>(T);
impl<T: fmt::Debug> Drop for NoisyDrop<T> {
fn drop(&mut self) {
let _ = vec!["0wned"];
println!("dropping {:?}", self.0)
}
}
trait Associator {
type As;
}
impl<T: fmt::Debug> Associator for T {
type As = NoisyDrop<T>;
}
struct Wrap<A: Associator>(<A as Associator>::As);
fn projection() {
let (_w, bomb);
bomb = vec![""];
_w = Wrap::<&[&str]>(NoisyDrop(&bomb));
//~^ ERROR `bomb` does not live long enough
}
fn closure() {
let (_w,v);
v = vec![""];
_w = {
let u = NoisyDrop(&v);
//~^ ERROR `v` does not live long enough
move || u.0.len()
};
}
fn main() { closure(); projection() }

View file

@ -1,120 +0,0 @@
// 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(const_fn)]
use std::cell::Cell;
use id::Id;
mod s {
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
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 } }
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();
}

View file

@ -1,23 +0,0 @@
// Copyright 2016 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.
#![feature(conservative_impl_trait)]
// Helper creating a fake borrow, captured by the impl Trait.
fn borrow<'a, T>(_: &'a mut T) -> impl Copy { () }
fn main() {
let long;
let mut short = 0;
long = borrow(&mut short);
//~^ ERROR `short` does not live long enough
//~| NOTE does not live long enough
//~| NOTE values in a scope are dropped in the opposite order they are created
} //~ borrowed value dropped before borrower

View file

@ -1,36 +0,0 @@
// 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 is just checking that we still reject code where temp values
// are borrowing values for longer than they will be around.
//
// Compare to run-pass/issue-23338-params-outlive-temps-of-body.rs
use std::cell::RefCell;
fn foo(x: RefCell<String>) -> String {
let y = x;
y.borrow().clone() //~ ERROR `y` does not live long enough
}
fn foo2(x: RefCell<String>) -> String {
let ret = {
let y = x;
y.borrow().clone() //~ ERROR `y` does not live long enough
};
ret
}
fn main() {
let r = RefCell::new(format!("data"));
assert_eq!(foo(r), "data");
let r = RefCell::new(format!("data"));
assert_eq!(foo2(r), "data");
}

View file

@ -1,46 +0,0 @@
// 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 child trait who only has items via its *parent* trait
// does cause dropck to inject extra region constraints.
#![allow(non_camel_case_types)]
trait Parent { fn foo(&self); }
trait Child: Parent { }
impl Parent for i32 { fn foo(&self) { } }
impl<'a> Parent for &'a D_Child<i32> {
fn foo(&self) {
println!("accessing child value: {}", self.0);
}
}
impl Child for i32 { }
impl<'a> Child for &'a D_Child<i32> { }
struct D_Child<T:Child>(T);
impl <T:Child> Drop for D_Child<T> { fn drop(&mut self) { self.0.foo() } }
fn f_child() {
// `_d` and `d1` are assigned the *same* lifetime by region inference ...
let (_d, d1);
d1 = D_Child(1);
// ... we store a reference to `d1` within `_d` ...
_d = D_Child(&d1); //~ ERROR `d1` does not live long enough
// ... dropck *should* complain, because Drop of _d could (and
// does) access the already dropped `d1` via the `foo` method.
}
fn main() {
f_child();
}

View file

@ -1,64 +0,0 @@
// 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 traits with various kinds of associated items cause
// dropck to inject extra region constraints.
#![allow(non_camel_case_types)]
trait HasSelfMethod { fn m1(&self) { } }
trait HasMethodWithSelfArg { fn m2(x: &Self) { } }
trait HasType { type Something; }
impl HasSelfMethod for i32 { }
impl HasMethodWithSelfArg for i32 { }
impl HasType for i32 { type Something = (); }
impl<'a,T> HasSelfMethod for &'a T { }
impl<'a,T> HasMethodWithSelfArg for &'a T { }
impl<'a,T> HasType for &'a T { type Something = (); }
// e.g. `impl_drop!(Send, D_Send)` expands to:
// ```rust
// struct D_Send<T:Send>(T);
// impl<T:Send> Drop for D_Send<T> { fn drop(&mut self) { } }
// ```
macro_rules! impl_drop {
($Bound:ident, $Id:ident) => {
struct $Id<T:$Bound>(T);
impl <T:$Bound> Drop for $Id<T> { fn drop(&mut self) { } }
}
}
impl_drop!{HasSelfMethod, D_HasSelfMethod}
impl_drop!{HasMethodWithSelfArg, D_HasMethodWithSelfArg}
impl_drop!{HasType, D_HasType}
fn f_sm() {
let (_d, d1);
d1 = D_HasSelfMethod(1);
_d = D_HasSelfMethod(&d1); //~ ERROR `d1` does not live long enough
}
fn f_mwsa() {
let (_d, d1);
d1 = D_HasMethodWithSelfArg(1);
_d = D_HasMethodWithSelfArg(&d1); //~ ERROR `d1` does not live long enough
}
fn f_t() {
let (_d, d1);
d1 = D_HasType(1);
_d = D_HasType(&d1); //~ ERROR `d1` does not live long enough
}
fn main() {
f_sm();
f_mwsa();
f_t();
}

View file

@ -1,38 +0,0 @@
// 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 one cannot subvert Drop Check rule via a user-defined
// Clone implementation.
#![allow(unused_variables, unused_assignments)]
struct D<T:Copy>(T, &'static str);
#[derive(Copy)]
struct S<'a>(&'a D<i32>, &'static str);
impl<'a> Clone for S<'a> {
fn clone(&self) -> S<'a> {
println!("cloning `S(_, {})` and thus accessing: {}", self.1, (self.0).0);
S(self.0, self.1)
}
}
impl<T:Copy> Drop for D<T> {
fn drop(&mut self) {
println!("calling Drop for {}", self.1);
let _call = self.0.clone();
}
}
fn main() {
let (d2, d1);
d1 = D(34, "d1");
d2 = D(S(&d1, "inner"), "d2"); //~ ERROR `d1` does not live long enough
}

View file

@ -1,83 +0,0 @@
// 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.
// Regression test for Issue 25199: Check that one cannot hide a
// destructor's access to borrowed data behind a boxed trait object.
//
// Prior to fixing Issue 25199, this example was able to be compiled
// with rustc, and thus when you ran it, you would see the `Drop` impl
// for `Test` accessing state that had already been dropping (which is
// marked explicitly here with checking code within the `Drop` impl
// for `VecHolder`, but in the general case could just do unsound
// things like accessing memory that has been freed).
//
// Note that I would have liked to encode my go-to example of cyclic
// structure that accesses its neighbors in drop (and thus is
// fundamentally unsound) via this trick, but the closest I was able
// to come was dropck_trait_cycle_checked.rs, which is not quite as
// "good" as this regression test because the encoding of that example
// was forced to attach a lifetime to the trait definition itself
// (`trait Obj<'a>`) while *this* example is solely
use std::cell::RefCell;
trait Obj { }
struct VecHolder {
v: Vec<(bool, &'static str)>,
}
impl Drop for VecHolder {
fn drop(&mut self) {
println!("Dropping Vec");
self.v[30].0 = false;
self.v[30].1 = "invalid access: VecHolder dropped already";
}
}
struct Container<'a> {
v: VecHolder,
d: RefCell<Vec<Box<Obj+'a>>>,
}
impl<'a> Container<'a> {
fn new() -> Container<'a> {
Container {
d: RefCell::new(Vec::new()),
v: VecHolder {
v: vec![(true, "valid"); 100]
}
}
}
fn store<T: Obj+'a>(&'a self, val: T) {
self.d.borrow_mut().push(Box::new(val));
}
}
struct Test<'a> {
test: &'a Container<'a>,
}
impl<'a> Obj for Test<'a> { }
impl<'a> Drop for Test<'a> {
fn drop(&mut self) {
for e in &self.test.v.v {
assert!(e.0, e.1);
}
}
}
fn main() {
let container = Container::new();
let test = Test{test: &container}; //~ ERROR `container` does not live long enough
println!("container.v[30]: {:?}", container.v.v[30]);
container.store(test); //~ ERROR `container` does not live long enough
}

View file

@ -1,52 +0,0 @@
// 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.
// Issue #26656: Verify that trait objects cannot bypass dropck.
// Using this instead of Fn etc. to take HRTB out of the equation.
trait Trigger<B> { fn fire(&self, b: &mut B); }
impl<B: Button> Trigger<B> for () {
fn fire(&self, b: &mut B) {
b.push();
}
}
// Still unsound Zook
trait Button { fn push(&self); }
struct Zook<B> { button: B, trigger: Box<Trigger<B>+'static> }
impl<B> Drop for Zook<B> {
fn drop(&mut self) {
self.trigger.fire(&mut self.button);
}
}
// AND
struct Bomb { usable: bool }
impl Drop for Bomb { fn drop(&mut self) { self.usable = false; } }
impl Bomb { fn activate(&self) { assert!(self.usable) } }
enum B<'a> { HarmlessButton, BigRedButton(&'a Bomb) }
impl<'a> Button for B<'a> {
fn push(&self) {
if let B::BigRedButton(borrowed) = *self {
borrowed.activate();
}
}
}
fn main() {
let (mut zook, ticking);
zook = Zook { button: B::HarmlessButton,
trigger: Box::new(()) };
ticking = Bomb { usable: true };
zook.button = B::BigRedButton(&ticking);
//~^ ERROR `ticking` does not live long enough
}

View file

@ -1,34 +0,0 @@
// 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.
use std::rc::Rc;
use std::sync::Arc;
struct Foo<'a>(&'a String);
impl<'a> Drop for Foo<'a> {
fn drop(&mut self) {
println!("{:?}", self.0);
}
}
fn main() {
{
let (y, x);
x = "alive".to_string();
y = Arc::new(Foo(&x)); //~ ERROR `x` does not live long enough
}
{
let (y, x);
x = "alive".to_string();
y = Rc::new(Foo(&x)); //~ ERROR `x` does not live long enough
}
}

View file

@ -1,48 +0,0 @@
// 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.
// Example taken from RFC 1238 text
// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
// #examples-of-code-that-will-start-to-be-rejected
// Compare against test/run-pass/issue28498-must-work-ex2.rs
use std::cell::Cell;
struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
struct Foo<T> { data: Vec<T> }
fn potentially_specialized_wrt_t<T>(t: &T) {
// Hypothetical code that does one thing for generic T and then is
// specialized for T == Concrete (and the specialized form can
// then access a reference held in concrete tuple).
//
// (We don't have specialization yet, but we want to allow for it
// in the future.)
}
impl<T> Drop for Foo<T> {
fn drop(&mut self) {
potentially_specialized_wrt_t(&self.data[0])
}
}
fn main() {
let mut foo = Foo { data: Vec::new() };
foo.data.push(Concrete(0, Cell::new(None)));
foo.data.push(Concrete(0, Cell::new(None)));
foo.data[0].1.set(Some(&foo.data[1]));
//~^ ERROR `foo.data` does not live long enough
foo.data[1].1.set(Some(&foo.data[0]));
//~^ ERROR `foo.data` does not live long enough
}

View file

@ -1,48 +0,0 @@
// 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.
// Demonstrate that having a lifetime param causes dropck to reject code
// that might indirectly access previously dropped value.
//
// Compare with run-pass/issue28498-ugeh-with-lifetime-param.rs
#[derive(Debug)]
struct ScribbleOnDrop(String);
impl Drop for ScribbleOnDrop {
fn drop(&mut self) {
self.0 = format!("DROPPED");
}
}
struct Foo<'a>(u32, &'a ScribbleOnDrop);
impl<'a> Drop for Foo<'a> {
fn drop(&mut self) {
// Use of `unsafe_destructor_blind_to_params` is unsound,
// because destructor accesses borrowed data in `self.1`
// and we must force that to strictly outlive `self`.
println!("Dropping Foo({}, {:?})", self.0, self.1);
}
}
fn main() {
let (last_dropped, foo0);
let (foo1, first_dropped);
last_dropped = ScribbleOnDrop(format!("last"));
first_dropped = ScribbleOnDrop(format!("first"));
foo0 = Foo(0, &last_dropped);
//~^ ERROR `last_dropped` does not live long enough
foo1 = Foo(1, &first_dropped);
//~^ ERROR `first_dropped` does not live long enough
println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
}

View file

@ -1,50 +0,0 @@
// 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.
// Demonstrate that a type param in negative position causes dropck to reject code
// that might indirectly access previously dropped value.
//
// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
#[derive(Debug)]
struct ScribbleOnDrop(String);
impl Drop for ScribbleOnDrop {
fn drop(&mut self) {
self.0 = format!("DROPPED");
}
}
struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
impl<T> Drop for Foo<T> {
fn drop(&mut self) {
// Use of `unsafe_destructor_blind_to_params` is unsound,
// because we pass `T` to the callback in `self.2`
// below, and thus potentially read from borrowed data.
println!("Dropping Foo({}, {})", self.0, (self.2)(&self.1));
}
}
fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
fn main() {
let (last_dropped, foo0);
let (foo1, first_dropped);
last_dropped = ScribbleOnDrop(format!("last"));
first_dropped = ScribbleOnDrop(format!("first"));
foo0 = Foo(0, &last_dropped, Box::new(callback));
//~^ ERROR `last_dropped` does not live long enough
foo1 = Foo(1, &first_dropped, Box::new(callback));
//~^ ERROR `first_dropped` does not live long enough
println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
}

View file

@ -1,50 +0,0 @@
// 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.
// Demonstrate that having a trait bound causes dropck to reject code
// that might indirectly access previously dropped value.
//
// Compare with run-pass/issue28498-ugeh-with-trait-bound.rs
use std::fmt;
#[derive(Debug)]
struct ScribbleOnDrop(String);
impl Drop for ScribbleOnDrop {
fn drop(&mut self) {
self.0 = format!("DROPPED");
}
}
struct Foo<T:fmt::Debug>(u32, T);
impl<T:fmt::Debug> Drop for Foo<T> {
fn drop(&mut self) {
// Use of `unsafe_destructor_blind_to_params` is unsound,
// because we access `T` fmt method when we pass `self.1`
// below, and thus potentially read from borrowed data.
println!("Dropping Foo({}, {:?})", self.0, self.1);
}
}
fn main() {
let (last_dropped, foo0);
let (foo1, first_dropped);
last_dropped = ScribbleOnDrop(format!("last"));
first_dropped = ScribbleOnDrop(format!("first"));
foo0 = Foo(0, &last_dropped);
//~^ ERROR `last_dropped` does not live long enough
foo1 = Foo(1, &first_dropped);
//~^ ERROR `first_dropped` does not live long enough
println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
}

View file

@ -1,133 +0,0 @@
// 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(const_fn)]
use std::cell::Cell;
use id::Id;
mod s {
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
/// 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 } }
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();
}

View file

@ -1,31 +0,0 @@
// 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, [&3, &4]);
}