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:
commit
a6fa57291b
48 changed files with 711 additions and 98 deletions
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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.
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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() }
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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]);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue