Resolve the vtables for method calls to generic Drop impls with trait bounds.
This commit is contained in:
parent
efef078cfa
commit
efaa1ea979
3 changed files with 42 additions and 23 deletions
|
@ -65,6 +65,7 @@ use middle::trans::type_of;
|
||||||
use middle::trans::type_of::*;
|
use middle::trans::type_of::*;
|
||||||
use middle::trans::value::Value;
|
use middle::trans::value::Value;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
use middle::typeck;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
use util::ppaux::{Repr, ty_to_str};
|
use util::ppaux::{Repr, ty_to_str};
|
||||||
use util::sha2::Sha256;
|
use util::sha2::Sha256;
|
||||||
|
@ -535,22 +536,14 @@ pub fn get_res_dtor(ccx: @CrateContext,
|
||||||
};
|
};
|
||||||
if !substs.is_empty() {
|
if !substs.is_empty() {
|
||||||
assert_eq!(did.krate, ast::LOCAL_CRATE);
|
assert_eq!(did.krate, ast::LOCAL_CRATE);
|
||||||
let tsubsts = ty::substs {regions: ty::ErasedRegions,
|
let tsubsts = ty::substs {
|
||||||
self_ty: None,
|
regions: ty::ErasedRegions,
|
||||||
tps: /*bad*/ substs.to_owned() };
|
self_ty: None,
|
||||||
|
tps: substs.to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
// FIXME: #4252: Generic destructors with type bounds are broken.
|
let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx, did.node, &tsubsts);
|
||||||
//
|
let (val, _) = monomorphize::monomorphic_fn(ccx, did, &tsubsts, vtables, None, None);
|
||||||
// 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);
|
|
||||||
|
|
||||||
val
|
val
|
||||||
} else if did.krate == ast::LOCAL_CRATE {
|
} else if did.krate == ast::LOCAL_CRATE {
|
||||||
|
|
|
@ -812,6 +812,28 @@ pub fn resolve_impl(tcx: ty::ctxt,
|
||||||
impl_vtables.get().insert(impl_def_id, res);
|
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 {
|
impl<'a> visit::Visitor<()> for &'a FnCtxt {
|
||||||
fn visit_expr(&mut self, ex: &ast::Expr, _: ()) {
|
fn visit_expr(&mut self, ex: &ast::Expr, _: ()) {
|
||||||
early_resolve_expr(ex, *self, false);
|
early_resolve_expr(ex, *self, false);
|
||||||
|
|
|
@ -8,30 +8,34 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// ignore-test
|
|
||||||
|
|
||||||
trait X {
|
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> {
|
struct Z<T> {
|
||||||
x: T
|
x: T
|
||||||
}
|
}
|
||||||
|
|
||||||
impl X for Y {
|
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> {
|
impl<T: X> Drop for Z<T> {
|
||||||
fn drop(&mut self) {
|
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() {
|
pub fn main() {
|
||||||
let y = Y;
|
let _z = Z {x: Y(42)};
|
||||||
let _z = Z{x: y};
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue