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() }; + let tsubsts = ty::substs { + regions: ty::ErasedRegions, + self_ty: None, + tps: 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 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 { + 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(&self, x: &T); + fn default_method(&self, x: &T) { + println!("X::default_method {:?} {:?}", self, x); + } } -struct Y; +struct Y(int); struct Z { x: T } impl X for Y { - fn call(&self) { + fn call(&self, x: &T) { + println!("X::call {:?} {:?}", self, x); } } +#[unsafe_destructor] impl Drop for Z { 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)}; }