diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 1d016f6db26..f3a8a39d9ec 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -250,8 +250,9 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>, let args = vec!(self_arg); // Add all the fields as a value which needs to be cleaned at the end of - // this scope. - for (i, ty) in st.fields.iter().enumerate() { + // this scope. Iterate in reverse order so a Drop impl doesn't reverse + // the order in which fields get dropped. + for (i, ty) in st.fields.iter().enumerate().rev() { let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false); variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope), llfld_a, *ty); diff --git a/src/test/run-pass/issue-16492.rs b/src/test/run-pass/issue-16492.rs new file mode 100644 index 00000000000..67af19b8517 --- /dev/null +++ b/src/test/run-pass/issue-16492.rs @@ -0,0 +1,80 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-pretty + +#![feature(unsafe_destructor)] + +use std::rc::Rc; +use std::cell::Cell; + +struct Field { + number: uint, + state: Rc> +} + +impl Field { + fn new(number: uint, state: Rc>) -> Field { + Field { + number: number, + state: state + } + } +} + +#[unsafe_destructor] // because Field isn't Send +impl Drop for Field { + fn drop(&mut self) { + println!("Dropping field {}", self.number); + assert_eq!(self.state.get(), self.number); + self.state.set(self.state.get()+1); + } +} + +struct NoDropImpl { + _one: Field, + _two: Field, + _three: Field +} + +struct HasDropImpl { + _one: Field, + _two: Field, + _three: Field +} + +#[unsafe_destructor] // because HasDropImpl isn't Send +impl Drop for HasDropImpl { + fn drop(&mut self) { + println!("HasDropImpl.drop()"); + assert_eq!(self._one.state.get(), 0); + self._one.state.set(1); + } +} + +pub fn main() { + let state = Rc::new(Cell::new(1)); + let noImpl = NoDropImpl { + _one: Field::new(1, state.clone()), + _two: Field::new(2, state.clone()), + _three: Field::new(3, state.clone()) + }; + drop(noImpl); + assert_eq!(state.get(), 4); + + state.set(0); + let hasImpl = HasDropImpl { + _one: Field::new(1, state.clone()), + _two: Field::new(2, state.clone()), + _three: Field::new(3, state.clone()) + }; + drop(hasImpl); + assert_eq!(state.get(), 4); +}