Skip to content

Commit 38cb37d

Browse files
committed
auto merge of #16493 : kballard/rust/fix_drop_field_order, r=pnkfelix
When a struct implements Drop, its fields should still drop in declaration order (just as they do when the struct does not implement Drop). Fixes #16492.
2 parents 2da5018 + b517b42 commit 38cb37d

File tree

2 files changed

+83
-2
lines changed

2 files changed

+83
-2
lines changed

src/librustc/middle/trans/glue.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,9 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
250250
let args = vec!(self_arg);
251251

252252
// Add all the fields as a value which needs to be cleaned at the end of
253-
// this scope.
254-
for (i, ty) in st.fields.iter().enumerate() {
253+
// this scope. Iterate in reverse order so a Drop impl doesn't reverse
254+
// the order in which fields get dropped.
255+
for (i, ty) in st.fields.iter().enumerate().rev() {
255256
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
256257
variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
257258
llfld_a, *ty);

src/test/run-pass/issue-16492.rs

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright 2014 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+
// ignore-pretty
12+
13+
#![feature(unsafe_destructor)]
14+
15+
use std::rc::Rc;
16+
use std::cell::Cell;
17+
18+
struct Field {
19+
number: uint,
20+
state: Rc<Cell<uint>>
21+
}
22+
23+
impl Field {
24+
fn new(number: uint, state: Rc<Cell<uint>>) -> Field {
25+
Field {
26+
number: number,
27+
state: state
28+
}
29+
}
30+
}
31+
32+
#[unsafe_destructor] // because Field isn't Send
33+
impl Drop for Field {
34+
fn drop(&mut self) {
35+
println!("Dropping field {}", self.number);
36+
assert_eq!(self.state.get(), self.number);
37+
self.state.set(self.state.get()+1);
38+
}
39+
}
40+
41+
struct NoDropImpl {
42+
_one: Field,
43+
_two: Field,
44+
_three: Field
45+
}
46+
47+
struct HasDropImpl {
48+
_one: Field,
49+
_two: Field,
50+
_three: Field
51+
}
52+
53+
#[unsafe_destructor] // because HasDropImpl isn't Send
54+
impl Drop for HasDropImpl {
55+
fn drop(&mut self) {
56+
println!("HasDropImpl.drop()");
57+
assert_eq!(self._one.state.get(), 0);
58+
self._one.state.set(1);
59+
}
60+
}
61+
62+
pub fn main() {
63+
let state = Rc::new(Cell::new(1));
64+
let noImpl = NoDropImpl {
65+
_one: Field::new(1, state.clone()),
66+
_two: Field::new(2, state.clone()),
67+
_three: Field::new(3, state.clone())
68+
};
69+
drop(noImpl);
70+
assert_eq!(state.get(), 4);
71+
72+
state.set(0);
73+
let hasImpl = HasDropImpl {
74+
_one: Field::new(1, state.clone()),
75+
_two: Field::new(2, state.clone()),
76+
_three: Field::new(3, state.clone())
77+
};
78+
drop(hasImpl);
79+
assert_eq!(state.get(), 4);
80+
}

0 commit comments

Comments
 (0)