about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2014-02-20 00:12:09 +0200
committerEduard Burtescu <edy.burt@gmail.com>2014-02-20 00:12:09 +0200
commitefaa1ea979c60dcb6884be12dcb12ceb09dbc5bd (patch)
tree68f7720d6deeab63d5ca7e6dd5b676d44c74052d
parentefef078cfa378378201ab097579992b40751cfb4 (diff)
downloadrust-efaa1ea979c60dcb6884be12dcb12ceb09dbc5bd.tar.gz
rust-efaa1ea979c60dcb6884be12dcb12ceb09dbc5bd.zip
Resolve the vtables for method calls to generic Drop impls with trait bounds.
-rw-r--r--src/librustc/middle/trans/base.rs25
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs22
-rw-r--r--src/test/run-pass/issue-4252.rs20
3 files changed, 43 insertions, 24 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index dc8e786fba2..e76b2a81490 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -65,6 +65,7 @@ use middle::trans::type_of;
 use middle::trans::type_of::*;
 use middle::trans::value::Value;
 use middle::ty;
+use middle::typeck;
 use util::common::indenter;
 use util::ppaux::{Repr, ty_to_str};
 use util::sha2::Sha256;
@@ -535,22 +536,14 @@ pub fn get_res_dtor(ccx: @CrateContext,
     };
     if !substs.is_empty() {
         assert_eq!(did.krate, ast::LOCAL_CRATE);
-        let tsubsts = ty::substs {regions: ty::ErasedRegions,
-                                  self_ty: None,
-                                  tps: /*bad*/ substs.to_owned() };
-
-        // FIXME: #4252: Generic destructors with type bounds are broken.
-        //
-        // Since the vtables aren't passed to `monomorphic_fn` here, generic destructors with type
-        // bounds are broken. Sadly, the `typeck` pass isn't outputting the necessary metadata
-        // because it does so based on method calls present in the AST. Destructor calls are not yet
-        // known about at that stage of compilation, since `trans` handles cleanups.
-        let (val, _) = monomorphize::monomorphic_fn(ccx,
-                                                    did,
-                                                    &tsubsts,
-                                                    None,
-                                                    None,
-                                                    None);
+        let tsubsts = ty::substs {
+            regions: ty::ErasedRegions,
+            self_ty: None,
+            tps: substs.to_owned()
+        };
+
+        let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx, did.node, &tsubsts);
+        let (val, _) = monomorphize::monomorphic_fn(ccx, did, &tsubsts, vtables, None, None);
 
         val
     } else if did.krate == ast::LOCAL_CRATE {
diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs
index 147254f6bf5..ba4300b58a1 100644
--- a/src/librustc/middle/typeck/check/vtable.rs
+++ b/src/librustc/middle/typeck/check/vtable.rs
@@ -812,6 +812,28 @@ pub fn resolve_impl(tcx: ty::ctxt,
     impl_vtables.get().insert(impl_def_id, res);
 }
 
+/// Resolve vtables for a method call after typeck has finished.
+/// Used by trans to monomorphize artificial method callees (e.g. drop).
+pub fn trans_resolve_method(tcx: ty::ctxt, id: ast::NodeId,
+                            substs: &ty::substs) -> Option<vtable_res> {
+    let generics = ty::lookup_item_type(tcx, ast_util::local_def(id)).generics;
+    let type_param_defs = generics.type_param_defs.borrow();
+    if has_trait_bounds(*type_param_defs) {
+        let vcx = VtableContext {
+            infcx: &infer::new_infer_ctxt(tcx),
+            param_env: &ty::construct_parameter_environment(tcx, None, [], [], [], id)
+        };
+        let loc_info = LocationInfo {
+            id: id,
+            span: tcx.map.span(id)
+        };
+
+        Some(lookup_vtables(&vcx, &loc_info, *type_param_defs, substs, false))
+    } else {
+        None
+    }
+}
+
 impl<'a> visit::Visitor<()> for &'a FnCtxt {
     fn visit_expr(&mut self, ex: &ast::Expr, _: ()) {
         early_resolve_expr(ex, *self, false);
diff --git a/src/test/run-pass/issue-4252.rs b/src/test/run-pass/issue-4252.rs
index 86b09f8dcfb..ba080e98183 100644
--- a/src/test/run-pass/issue-4252.rs
+++ b/src/test/run-pass/issue-4252.rs
@@ -8,30 +8,34 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// ignore-test
-
 trait X {
-    fn call(&self);
+    fn call<T>(&self, x: &T);
+    fn default_method<T>(&self, x: &T) {
+        println!("X::default_method {:?} {:?}", self, x);
+    }
 }
 
-struct Y;
+struct Y(int);
 
 struct Z<T> {
     x: T
 }
 
 impl X for Y {
-    fn call(&self) {
+    fn call<T>(&self, x: &T) {
+        println!("X::call {:?} {:?}", self, x);
     }
 }
 
+#[unsafe_destructor]
 impl<T: X> Drop for Z<T> {
     fn drop(&mut self) {
-        self.x.call(); // Adding this statement causes an ICE.
+        // These statements used to cause an ICE.
+        self.x.call(self);
+        self.x.default_method(self);
     }
 }
 
 pub fn main() {
-    let y = Y;
-    let _z = Z{x: y};
+    let _z = Z {x: Y(42)};
 }