implement drop elaboration

Fixes #30380
This commit is contained in:
Ariel Ben-Yehuda 2016-05-17 02:26:18 +03:00
parent de7cb0fdd6
commit a091cfd4f3
10 changed files with 1431 additions and 2 deletions

View file

@ -0,0 +1,44 @@
// 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.
// check that panics in destructors during assignment do not leave
// destroyed values lying around for other destructors to observe.
// error-pattern:panicking destructors ftw!
struct Observer<'a>(&'a mut FilledOnDrop);
struct FilledOnDrop(u32);
impl Drop for FilledOnDrop {
fn drop(&mut self) {
if self.0 == 0 {
// this is only set during the destructor - safe
// code should not be able to observe this.
self.0 = 0x1c1c1c1c;
panic!("panicking destructors ftw!");
}
}
}
impl<'a> Drop for Observer<'a> {
fn drop(&mut self) {
assert_eq!(self.0 .0, 1);
}
}
fn foo(b: &mut Observer) {
*b.0 = FilledOnDrop(1);
}
fn main() {
let mut bomb = FilledOnDrop(0);
let mut observer = Observer(&mut bomb);
foo(&mut observer);
}

View file

@ -0,0 +1,100 @@
// 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.
use std::cell::RefCell;
struct Allocator {
data: RefCell<Vec<bool>>,
}
impl Drop for Allocator {
fn drop(&mut self) {
let data = self.data.borrow();
if data.iter().any(|d| *d) {
panic!("missing free: {:?}", data);
}
}
}
impl Allocator {
fn new() -> Self { Allocator { data: RefCell::new(vec![]) } }
fn alloc(&self) -> Ptr {
let mut data = self.data.borrow_mut();
let addr = data.len();
data.push(true);
Ptr(addr, self)
}
}
struct Ptr<'a>(usize, &'a Allocator);
impl<'a> Drop for Ptr<'a> {
fn drop(&mut self) {
match self.1.data.borrow_mut()[self.0] {
false => {
panic!("double free at index {:?}", self.0)
}
ref mut d => *d = false
}
}
}
fn dynamic_init(a: &Allocator, c: bool) {
let _x;
if c {
_x = Some(a.alloc());
}
}
fn dynamic_drop(a: &Allocator, c: bool) -> Option<Ptr> {
let x = a.alloc();
if c {
Some(x)
} else {
None
}
}
fn assignment2(a: &Allocator, c0: bool, c1: bool) {
let mut _v = a.alloc();
let mut _w = a.alloc();
if c0 {
drop(_v);
}
_v = _w;
if c1 {
_w = a.alloc();
}
}
fn assignment1(a: &Allocator, c0: bool) {
let mut _v = a.alloc();
let mut _w = a.alloc();
if c0 {
drop(_v);
}
_v = _w;
}
fn main() {
let a = Allocator::new();
dynamic_init(&a, false);
dynamic_init(&a, true);
dynamic_drop(&a, false);
dynamic_drop(&a, true);
assignment2(&a, false, false);
assignment2(&a, false, true);
assignment2(&a, true, false);
assignment2(&a, true, true);
assignment1(&a, false);
assignment1(&a, true);
}