about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/glue.rs57
-rw-r--r--src/test/run-pass/fail-in-dtor-drops-fields.rs42
2 files changed, 59 insertions, 40 deletions
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index 2b0f13d2a7c..02b44907f33 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -395,39 +395,11 @@ pub fn trans_struct_drop_flag(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did:
     let repr = adt::represent_type(bcx.ccx(), t);
     let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0);
     do with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) |cx| {
-        let mut bcx = cx;
-
-        // Find and call the actual destructor
-        let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
-                                     class_did, substs.tps.clone());
-
-        // The second argument is the "self" argument for drop
-        let params = unsafe {
-            let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
-            ty.element_type().func_params()
-        };
-
-        // Class dtors have no explicit args, so the params should
-        // just consist of the environment (self)
-        assert_eq!(params.len(), 1);
-
-        let self_arg = PointerCast(bcx, v0, params[0]);
-        let args = ~[self_arg];
-
-        Call(bcx, dtor_addr, args, []);
-
-        // Drop the fields
-        let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
-        for (i, fld) in field_tys.iter().enumerate() {
-            let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
-            bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
-        }
-
-        bcx
+        trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
     }
 }
 
-pub fn trans_struct_drop(mut bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast::DefId,
+pub fn trans_struct_drop(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast::DefId,
                          class_did: ast::DefId, substs: &ty::substs) -> @mut Block {
     let repr = adt::represent_type(bcx.ccx(), t);
 
@@ -445,19 +417,24 @@ pub fn trans_struct_drop(mut bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did:
     // just consist of the environment (self)
     assert_eq!(params.len(), 1);
 
-    let self_arg = PointerCast(bcx, v0, params[0]);
-    let args = ~[self_arg];
+    // Be sure to put all of the fields into a scope so we can use an invoke
+    // instruction to call the user destructor but still call the field
+    // destructors if the user destructor fails.
+    do with_scope(bcx, None, "field drops") |bcx| {
+        let self_arg = PointerCast(bcx, v0, params[0]);
+        let args = ~[self_arg];
 
-    Call(bcx, dtor_addr, args, []);
+        // Add all the fields as a value which needs to be cleaned at the end of
+        // this scope.
+        let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
+        for (i, fld) in field_tys.iter().enumerate() {
+            let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
+            add_clean(bcx, llfld_a, fld.mt.ty);
+        }
 
-    // Drop the fields
-    let field_tys = ty::struct_fields(bcx.tcx(), class_did, substs);
-    for (i, fld) in field_tys.iter().enumerate() {
-        let llfld_a = adt::trans_field_ptr(bcx, repr, v0, 0, i);
-        bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
+        let (_, bcx) = invoke(bcx, dtor_addr, args, []);
+        bcx
     }
-
-    bcx
 }
 
 pub fn make_drop_glue(bcx: @mut Block, v0: ValueRef, t: ty::t) -> @mut Block {
diff --git a/src/test/run-pass/fail-in-dtor-drops-fields.rs b/src/test/run-pass/fail-in-dtor-drops-fields.rs
new file mode 100644
index 00000000000..7c6bb1fa379
--- /dev/null
+++ b/src/test/run-pass/fail-in-dtor-drops-fields.rs
@@ -0,0 +1,42 @@
+// Copyright 2013 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::task;
+
+static mut dropped: bool = false;
+
+struct A {
+    b: B,
+}
+
+struct B {
+    foo: int,
+}
+
+impl Drop for A {
+    fn drop(&mut self) {
+        fail!()
+    }
+}
+
+impl Drop for B {
+    fn drop(&mut self) {
+        unsafe { dropped = true; }
+    }
+}
+
+pub fn main() {
+    let ret = do task::try {
+        let _a = A { b: B { foo: 3 } };
+    };
+    assert!(ret.is_err());
+    unsafe { assert!(dropped); }
+}
+