|
| 1 | +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
| 2 | +// file at the top-level directory of this distribution and at |
| 3 | +// http://rust-lang.org/COPYRIGHT. |
| 4 | +// |
| 5 | +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| 6 | +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| 7 | +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| 8 | +// option. This file may not be copied, modified, or distributed |
| 9 | +// except according to those terms. |
| 10 | + |
| 11 | +// Issue #21486: Make sure that all structures are dropped, even when |
| 12 | +// created via FRU and control-flow breaks in the middle of |
| 13 | +// construction. |
| 14 | + |
| 15 | + |
| 16 | +use std::sync::atomic::{Ordering, AtomicUsize, ATOMIC_USIZE_INIT}; |
| 17 | + |
| 18 | +#[derive(Debug)] |
| 19 | +struct Noisy(u8); |
| 20 | +impl Drop for Noisy { |
| 21 | + fn drop(&mut self) { |
| 22 | + // println!("splat #{}", self.0); |
| 23 | + event(self.0); |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +#[allow(dead_code)] |
| 28 | +#[derive(Debug)] |
| 29 | +struct Foo { n0: Noisy, n1: Noisy } |
| 30 | +impl Foo { |
| 31 | + fn vals(&self) -> (u8, u8) { (self.n0.0, self.n1.0) } |
| 32 | +} |
| 33 | + |
| 34 | +fn leak_1_ret() -> Foo { |
| 35 | + let _old_foo = Foo { n0: Noisy(1), n1: Noisy(2) }; |
| 36 | + Foo { n0: { return Foo { n0: Noisy(3), n1: Noisy(4) } }, |
| 37 | + .._old_foo |
| 38 | + }; |
| 39 | +} |
| 40 | + |
| 41 | +fn leak_2_ret() -> Foo { |
| 42 | + let _old_foo = Foo { n0: Noisy(1), n1: Noisy(2) }; |
| 43 | + Foo { n1: { return Foo { n0: Noisy(3), n1: Noisy(4) } }, |
| 44 | + .._old_foo |
| 45 | + }; |
| 46 | +} |
| 47 | + |
| 48 | +// In this case, the control flow break happens *before* we construct |
| 49 | +// `Foo(Noisy(1),Noisy(2))`, so there should be no record of it in the |
| 50 | +// event log. |
| 51 | +fn leak_3_ret() -> Foo { |
| 52 | + let _old_foo = || Foo { n0: Noisy(1), n1: Noisy(2) }; |
| 53 | + Foo { n1: { return Foo { n0: Noisy(3), n1: Noisy(4) } }, |
| 54 | + .._old_foo() |
| 55 | + }; |
| 56 | +} |
| 57 | + |
| 58 | +pub fn main() { |
| 59 | + reset_log(); |
| 60 | + assert_eq!(leak_1_ret().vals(), (3,4)); |
| 61 | + assert_eq!(0x01_02_03_04, event_log()); |
| 62 | + |
| 63 | + reset_log(); |
| 64 | + assert_eq!(leak_2_ret().vals(), (3,4)); |
| 65 | + assert_eq!(0x01_02_03_04, event_log()); |
| 66 | + |
| 67 | + reset_log(); |
| 68 | + assert_eq!(leak_3_ret().vals(), (3,4)); |
| 69 | + assert_eq!(0x03_04, event_log()); |
| 70 | +} |
| 71 | + |
| 72 | +static LOG: AtomicUsize = ATOMIC_USIZE_INIT; |
| 73 | + |
| 74 | +fn reset_log() { |
| 75 | + LOG.store(0, Ordering::SeqCst); |
| 76 | +} |
| 77 | + |
| 78 | +fn event_log() -> usize { |
| 79 | + LOG.load(Ordering::SeqCst) |
| 80 | +} |
| 81 | + |
| 82 | +fn event(tag: u8) { |
| 83 | + let old_log = LOG.load(Ordering::SeqCst); |
| 84 | + let new_log = (old_log << 8) + tag as usize; |
| 85 | + LOG.store(new_log, Ordering::SeqCst); |
| 86 | +} |
0 commit comments