Merge pull request #20295 from eddyb/poly-const

Allow paths in constants to refer to polymorphic items.

Reviewed-by: nikomatsakis
This commit is contained in:
bors 2015-01-04 21:36:33 +00:00
commit e9818564bd
14 changed files with 323 additions and 272 deletions

View File

@ -14,9 +14,7 @@ use middle::ty;
use util::ppaux; use util::ppaux;
use syntax::ast; use syntax::ast;
use syntax::ast_util; use syntax::visit::{self, Visitor};
use syntax::visit::Visitor;
use syntax::visit;
struct CheckCrateVisitor<'a, 'tcx: 'a> { struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>, tcx: &'a ty::ctxt<'tcx>,
@ -37,24 +35,39 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
{ {
self.with_const(true, f); self.with_const(true, f);
} }
fn outside_const<F>(&mut self, f: F) where
F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>),
{
self.with_const(false, f);
}
} }
impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
fn visit_item(&mut self, i: &ast::Item) { fn visit_item(&mut self, i: &ast::Item) {
check_item(self, i); match i.node {
ast::ItemStatic(_, _, ref ex) |
ast::ItemConst(_, ref ex) => {
self.inside_const(|v| v.visit_expr(&**ex));
}
ast::ItemEnum(ref enum_definition, _) => {
self.inside_const(|v| {
for var in enum_definition.variants.iter() {
if let Some(ref ex) = var.node.disr_expr {
v.visit_expr(&**ex);
}
}
});
}
_ => self.with_const(false, |v| visit::walk_item(v, i))
}
} }
fn visit_pat(&mut self, p: &ast::Pat) { fn visit_pat(&mut self, p: &ast::Pat) {
check_pat(self, p); let is_const = match p.node {
ast::PatLit(_) | ast::PatRange(..) => true,
_ => false
};
self.with_const(is_const, |v| visit::walk_pat(v, p))
} }
fn visit_expr(&mut self, ex: &ast::Expr) { fn visit_expr(&mut self, ex: &ast::Expr) {
if check_expr(self, ex) { if self.in_const {
visit::walk_expr(self, ex); check_expr(self, ex);
} }
visit::walk_expr(self, ex);
} }
} }
@ -64,57 +77,13 @@ pub fn check_crate(tcx: &ty::ctxt) {
tcx.sess.abort_if_errors(); tcx.sess.abort_if_errors();
} }
fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) { fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
match it.node {
ast::ItemStatic(_, _, ref ex) |
ast::ItemConst(_, ref ex) => {
v.inside_const(|v| v.visit_expr(&**ex));
}
ast::ItemEnum(ref enum_definition, _) => {
for var in (*enum_definition).variants.iter() {
for ex in var.node.disr_expr.iter() {
v.inside_const(|v| v.visit_expr(&**ex));
}
}
}
_ => v.outside_const(|v| visit::walk_item(v, it))
}
}
fn check_pat(v: &mut CheckCrateVisitor, p: &ast::Pat) {
fn is_str(e: &ast::Expr) -> bool {
match e.node {
ast::ExprBox(_, ref expr) => {
match expr.node {
ast::ExprLit(ref lit) => ast_util::lit_is_str(&**lit),
_ => false,
}
}
_ => false,
}
}
match p.node {
// Let through plain ~-string literals here
ast::PatLit(ref a) => if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); },
ast::PatRange(ref a, ref b) => {
if !is_str(&**a) { v.inside_const(|v| v.visit_expr(&**a)); }
if !is_str(&**b) { v.inside_const(|v| v.visit_expr(&**b)); }
}
_ => v.outside_const(|v| visit::walk_pat(v, p))
}
}
fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
if !v.in_const { return true }
match e.node { match e.node {
ast::ExprUnary(ast::UnDeref, _) => {} ast::ExprUnary(ast::UnDeref, _) => {}
ast::ExprUnary(ast::UnUniq, _) => { ast::ExprUnary(ast::UnUniq, _) => {
span_err!(v.tcx.sess, e.span, E0010, span_err!(v.tcx.sess, e.span, E0010,
"cannot do allocations in constant expressions"); "cannot do allocations in constant expressions");
return false;
} }
ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {}
ast::ExprBinary(..) | ast::ExprUnary(..) => { ast::ExprBinary(..) | ast::ExprUnary(..) => {
let method_call = ty::MethodCall::expr(e.id); let method_call = ty::MethodCall::expr(e.id);
if v.tcx.method_map.borrow().contains_key(&method_call) { if v.tcx.method_map.borrow().contains_key(&method_call) {
@ -123,7 +92,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
expressions"); expressions");
} }
} }
ast::ExprLit(_) => (), ast::ExprLit(_) => {}
ast::ExprCast(ref from, _) => { ast::ExprCast(ref from, _) => {
let toty = ty::expr_ty(v.tcx, e); let toty = ty::expr_ty(v.tcx, e);
let fromty = ty::expr_ty(v.tcx, &**from); let fromty = ty::expr_ty(v.tcx, &**from);
@ -142,39 +111,23 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
expression"); expression");
} }
} }
ast::ExprPath(ref pth) => { ast::ExprPath(_) => {
// NB: In the future you might wish to relax this slightly match v.tcx.def_map.borrow()[e.id] {
// to handle on-demand instantiation of functions via DefStatic(..) | DefConst(..) |
// foo::<bar> in a const. Currently that is only done on DefFn(..) | DefStaticMethod(..) | DefMethod(..) |
// a path in trans::callee that only works in block contexts. DefStruct(_) | DefVariant(_, _, _) => {}
if !pth.segments.iter().all(|segment| segment.parameters.is_empty()) {
span_err!(v.tcx.sess, e.span, E0013,
"paths in constants may only refer to items without \
type parameters");
}
match v.tcx.def_map.borrow().get(&e.id) {
Some(&DefStatic(..)) |
Some(&DefConst(..)) |
Some(&DefFn(..)) |
Some(&DefVariant(_, _, _)) |
Some(&DefStruct(_)) => { }
Some(&def) => { def => {
debug!("(checking const) found bad def: {}", def); debug!("(checking const) found bad def: {}", def);
span_err!(v.tcx.sess, e.span, E0014, span_err!(v.tcx.sess, e.span, E0014,
"paths in constants may only refer to constants \ "paths in constants may only refer to constants \
or functions"); or functions");
} }
None => {
v.tcx.sess.span_bug(e.span, "unbound path in const?!");
}
} }
} }
ast::ExprCall(ref callee, _) => { ast::ExprCall(ref callee, _) => {
match v.tcx.def_map.borrow().get(&callee.id) { match v.tcx.def_map.borrow()[callee.id] {
Some(&DefStruct(..)) | DefStruct(..) | DefVariant(..) => {} // OK.
Some(&DefVariant(..)) => {} // OK.
_ => { _ => {
span_err!(v.tcx.sess, e.span, E0015, span_err!(v.tcx.sess, e.span, E0015,
"function calls in constants are limited to \ "function calls in constants are limited to \
@ -190,9 +143,9 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
"blocks in constants are limited to items and \ "blocks in constants are limited to items and \
tail expressions"); tail expressions");
match stmt.node { match stmt.node {
ast::StmtDecl(ref span, _) => { ast::StmtDecl(ref decl, _) => {
match span.node { match decl.node {
ast::DeclLocal(_) => block_span_err(span.span), ast::DeclLocal(_) => block_span_err(decl.span),
// Item statements are allowed // Item statements are allowed
ast::DeclItem(_) => {} ast::DeclItem(_) => {}
@ -206,10 +159,6 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
} }
} }
} }
match block.expr {
Some(ref expr) => { check_expr(v, &**expr); }
None => {}
}
} }
ast::ExprVec(_) | ast::ExprVec(_) |
ast::ExprAddrOf(ast::MutImmutable, _) | ast::ExprAddrOf(ast::MutImmutable, _) |
@ -232,11 +181,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
} }
} }
_ => { _ => span_err!(v.tcx.sess, e.span, E0019,
span_err!(v.tcx.sess, e.span, E0019, "constant contains unimplemented expression type")
"constant contains unimplemented expression type");
return false;
}
} }
true
} }

View File

@ -559,14 +559,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
id, expr_ty.repr(self.tcx()), def); id, expr_ty.repr(self.tcx()), def);
match def { match def {
def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) | def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
def::DefStaticMethod(..) | def::DefConst(..) => { def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
Ok(self.cat_rvalue_node(id, span, expr_ty)) Ok(self.cat_rvalue_node(id, span, expr_ty))
} }
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) | def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) | def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) | def::DefLabel(_) | def::DefSelfTy(..) |
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> { def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
Ok(Rc::new(cmt_ { Ok(Rc::new(cmt_ {
id:id, id:id,

View File

@ -511,7 +511,7 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Since we're in trans we don't care for any region parameters // Since we're in trans we don't care for any region parameters
let substs = subst::Substs::erased(substs.types.clone()); let substs = subst::Substs::erased(substs.types.clone());
let (val, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None); let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, &substs, None);
val val
} else if did.krate == ast::LOCAL_CRATE { } else if did.krate == ast::LOCAL_CRATE {

View File

@ -38,6 +38,7 @@ use trans::cleanup::CleanupMethods;
use trans::closure; use trans::closure;
use trans::common; use trans::common;
use trans::common::*; use trans::common::*;
use trans::consts;
use trans::datum::*; use trans::datum::*;
use trans::expr; use trans::expr;
use trans::glue; use trans::glue;
@ -152,7 +153,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
_ => false _ => false
} }
} => { } => {
let substs = node_id_substs(bcx, ExprId(ref_expr.id)); let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
Callee { Callee {
bcx: bcx, bcx: bcx,
data: NamedTupleConstructor(substs, 0) data: NamedTupleConstructor(substs, 0)
@ -162,23 +164,28 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic, ty::ty_bare_fn(_, ref f) => f.abi == synabi::RustIntrinsic,
_ => false _ => false
} => { } => {
let substs = node_id_substs(bcx, ExprId(ref_expr.id)); let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did); let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) } Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
} }
def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) | def::DefFn(did, _) | def::DefMethod(did, _, def::FromImpl(_)) |
def::DefStaticMethod(did, def::FromImpl(_)) => { def::DefStaticMethod(did, def::FromImpl(_)) => {
fn_callee(bcx, trans_fn_ref(bcx, did, ExprId(ref_expr.id))) fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
bcx.fcx.param_substs).val)
} }
def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) | def::DefStaticMethod(meth_did, def::FromTrait(trait_did)) |
def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => { def::DefMethod(meth_did, _, def::FromTrait(trait_did)) => {
fn_callee(bcx, meth::trans_static_method_callee(bcx, meth_did, fn_callee(bcx, meth::trans_static_method_callee(bcx.ccx(),
meth_did,
trait_did, trait_did,
ref_expr.id)) ref_expr.id,
bcx.fcx.param_substs).val)
} }
def::DefVariant(tid, vid, _) => { def::DefVariant(tid, vid, _) => {
let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid); let vinfo = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
let substs = node_id_substs(bcx, ExprId(ref_expr.id)); let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
// Nullary variants are not callable // Nullary variants are not callable
assert!(vinfo.args.len() > 0u); assert!(vinfo.args.len() > 0u);
@ -189,7 +196,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
} }
} }
def::DefStruct(_) => { def::DefStruct(_) => {
let substs = node_id_substs(bcx, ExprId(ref_expr.id)); let substs = node_id_substs(bcx.ccx(), ExprId(ref_expr.id),
bcx.fcx.param_substs);
Callee { Callee {
bcx: bcx, bcx: bcx,
data: NamedTupleConstructor(substs, 0) data: NamedTupleConstructor(substs, 0)
@ -217,15 +225,19 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
/// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function /// Translates a reference (with id `ref_id`) to the fn/method with id `def_id` into a function
/// pointer. This may require monomorphization or inlining. /// pointer. This may require monomorphization or inlining.
pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> ValueRef { pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
def_id: ast::DefId,
node: ExprOrMethodCall,
param_substs: &subst::Substs<'tcx>)
-> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_fn_ref"); let _icx = push_ctxt("trans_fn_ref");
let substs = node_id_substs(bcx, node); let substs = node_id_substs(ccx, node, param_substs);
debug!("trans_fn_ref(def_id={}, node={}, substs={})", debug!("trans_fn_ref(def_id={}, node={}, substs={})",
def_id.repr(bcx.tcx()), def_id.repr(ccx.tcx()),
node, node,
substs.repr(bcx.tcx())); substs.repr(ccx.tcx()));
trans_fn_ref_with_substs(bcx, def_id, node, substs) trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
} }
fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@ -235,10 +247,11 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> Callee<'blk, 'tcx> { -> Callee<'blk, 'tcx> {
Callee { Callee {
bcx: bcx, bcx: bcx,
data: Fn(trans_fn_ref_with_substs(bcx, data: Fn(trans_fn_ref_with_substs(bcx.ccx(),
def_id, def_id,
ExprId(ref_id), ExprId(ref_id),
substs)), bcx.fcx.param_substs,
substs).val),
} }
} }
@ -364,28 +377,30 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
/// ///
/// # Parameters /// # Parameters
/// ///
/// - `bcx`: the current block where the reference to the fn occurs /// - `ccx`: the crate context
/// - `def_id`: def id of the fn or method item being referenced /// - `def_id`: def id of the fn or method item being referenced
/// - `node`: node id of the reference to the fn/method, if applicable. /// - `node`: node id of the reference to the fn/method, if applicable.
/// This parameter may be zero; but, if so, the resulting value may not /// This parameter may be zero; but, if so, the resulting value may not
/// have the right type, so it must be cast before being used. /// have the right type, so it must be cast before being used.
/// - `param_substs`: if the `node` is in a polymorphic function, these
/// are the substitutions required to monomorphize its type
/// - `substs`: values for each of the fn/method's parameters /// - `substs`: values for each of the fn/method's parameters
pub fn trans_fn_ref_with_substs<'blk, 'tcx>( pub fn trans_fn_ref_with_substs<'a, 'tcx>(
bcx: Block<'blk, 'tcx>, // ccx: &CrateContext<'a, 'tcx>,
def_id: ast::DefId, // def id of fn def_id: ast::DefId,
node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A node: ExprOrMethodCall,
substs: subst::Substs<'tcx>) // vtables for the call param_substs: &subst::Substs<'tcx>,
-> ValueRef substs: subst::Substs<'tcx>)
-> Datum<'tcx, Rvalue>
{ {
let _icx = push_ctxt("trans_fn_ref_with_substs"); let _icx = push_ctxt("trans_fn_ref_with_substs");
let ccx = bcx.ccx(); let tcx = ccx.tcx();
let tcx = bcx.tcx();
debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={}, \ debug!("trans_fn_ref_with_substs(def_id={}, node={}, \
substs={})", param_substs={}, substs={})",
bcx.to_str(),
def_id.repr(tcx), def_id.repr(tcx),
node, node,
param_substs.repr(tcx),
substs.repr(tcx)); substs.repr(tcx));
assert!(substs.types.all(|t| !ty::type_needs_infer(*t))); assert!(substs.types.all(|t| !ty::type_needs_infer(*t)));
@ -443,15 +458,15 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
(true, source_id, new_substs) (true, source_id, new_substs)
} }
ty::TypeTraitItem(_) => { ty::TypeTraitItem(_) => {
bcx.tcx().sess.bug("trans_fn_ref_with_vtables() tried \ tcx.sess.bug("trans_fn_ref_with_vtables() tried \
to translate an associated type?!") to translate an associated type?!")
} }
} }
} }
}; };
// If this is an unboxed closure, redirect to it. // If this is an unboxed closure, redirect to it.
match closure::get_or_create_declaration_if_unboxed_closure(bcx, match closure::get_or_create_declaration_if_unboxed_closure(ccx,
def_id, def_id,
&substs) { &substs) {
None => {} None => {}
@ -494,24 +509,27 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
MethodCallKey(_) => None, MethodCallKey(_) => None,
}; };
let (val, must_cast) = let (val, fn_ty, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id); monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id);
let mut val = val;
if must_cast && node != ExprId(0) { if must_cast && node != ExprId(0) {
// Monotype of the REFERENCE to the function (type params // Monotype of the REFERENCE to the function (type params
// are subst'd) // are subst'd)
let ref_ty = match node { let ref_ty = match node {
ExprId(id) => node_id_type(bcx, id), ExprId(id) => ty::node_id_to_type(tcx, id),
MethodCallKey(method_call) => { MethodCallKey(method_call) => {
let t = (*bcx.tcx().method_map.borrow())[method_call].ty; (*tcx.method_map.borrow())[method_call].ty
monomorphize_type(bcx, t)
} }
}; };
let ref_ty = monomorphize::apply_param_substs(tcx,
val = PointerCast( param_substs,
bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to()); &ref_ty);
let llptrty = type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to();
if llptrty != val_ty(val) {
let val = consts::ptrcast(val, llptrty);
return Datum::new(val, ref_ty, Rvalue::new(ByValue));
}
} }
return val; return Datum::new(val, fn_ty, Rvalue::new(ByValue));
} }
// Type scheme of the function item (may have type params) // Type scheme of the function item (may have type params)
@ -556,12 +574,12 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
let llptrty = llty.ptr_to(); let llptrty = llty.ptr_to();
if val_ty(val) != llptrty { if val_ty(val) != llptrty {
debug!("trans_fn_ref_with_vtables(): casting pointer!"); debug!("trans_fn_ref_with_vtables(): casting pointer!");
val = BitCast(bcx, val, llptrty); val = consts::ptrcast(val, llptrty);
} else { } else {
debug!("trans_fn_ref_with_vtables(): not casting pointer!"); debug!("trans_fn_ref_with_vtables(): not casting pointer!");
} }
val Datum::new(val, fn_type, Rvalue::new(ByValue))
} }
// ______________________________________________________________________ // ______________________________________________________________________

View File

@ -726,7 +726,10 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
// specify any of the types for the function, we just make it a symbol // specify any of the types for the function, we just make it a symbol
// that LLVM can later use. // that LLVM can later use.
let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() { let llpersonality = match pad_bcx.tcx().lang_items.eh_personality() {
Some(def_id) => callee::trans_fn_ref(pad_bcx, def_id, ExprId(0)), Some(def_id) => {
callee::trans_fn_ref(pad_bcx.ccx(), def_id, ExprId(0),
pad_bcx.fcx.param_substs).val
}
None => { None => {
let mut personality = self.ccx.eh_personality().borrow_mut(); let mut personality = self.ccx.eh_personality().borrow_mut();
match *personality { match *personality {

View File

@ -20,6 +20,7 @@ use trans::build::*;
use trans::cleanup::{CleanupMethods, ScopeId}; use trans::cleanup::{CleanupMethods, ScopeId};
use trans::common::*; use trans::common::*;
use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum}; use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
use trans::datum::{Rvalue, ByValue};
use trans::debuginfo; use trans::debuginfo;
use trans::expr; use trans::expr;
use trans::monomorphize::{self, MonoId}; use trans::monomorphize::{self, MonoId};
@ -453,22 +454,21 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
/// Returns the LLVM function declaration for an unboxed closure, creating it /// Returns the LLVM function declaration for an unboxed closure, creating it
/// if necessary. If the ID does not correspond to a closure ID, returns None. /// if necessary. If the ID does not correspond to a closure ID, returns None.
pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
closure_id: ast::DefId, closure_id: ast::DefId,
substs: &Substs<'tcx>) substs: &Substs<'tcx>)
-> Option<ValueRef> { -> Option<Datum<'tcx, Rvalue>> {
let ccx = bcx.ccx();
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) { if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
// Not an unboxed closure. // Not an unboxed closure.
return None return None
} }
let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node); let function_type = ty::node_id_to_type(ccx.tcx(), closure_id.node);
let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type); let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type);
// Normalize type so differences in regions and typedefs don't cause // Normalize type so differences in regions and typedefs don't cause
// duplicate declarations // duplicate declarations
let function_type = ty::normalize_ty(bcx.tcx(), function_type); let function_type = ty::normalize_ty(ccx.tcx(), function_type);
let params = match function_type.sty { let params = match function_type.sty {
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(), ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
_ => unreachable!() _ => unreachable!()
@ -479,10 +479,10 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk,
}; };
match ccx.unboxed_closure_vals().borrow().get(&mono_id) { match ccx.unboxed_closure_vals().borrow().get(&mono_id) {
Some(llfn) => { Some(&llfn) => {
debug!("get_or_create_declaration_if_unboxed_closure(): found \ debug!("get_or_create_declaration_if_unboxed_closure(): found \
closure"); closure");
return Some(*llfn) return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
} }
None => {} None => {}
} }
@ -502,7 +502,7 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk,
ccx.tn().type_to_string(val_ty(llfn))); ccx.tn().type_to_string(val_ty(llfn)));
ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn); ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn);
Some(llfn) Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
} }
pub fn trans_unboxed_closure<'blk, 'tcx>( pub fn trans_unboxed_closure<'blk, 'tcx>(
@ -519,7 +519,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
let closure_id = ast_util::local_def(id); let closure_id = ast_util::local_def(id);
let llfn = get_or_create_declaration_if_unboxed_closure( let llfn = get_or_create_declaration_if_unboxed_closure(
bcx, bcx.ccx(),
closure_id, closure_id,
bcx.fcx.param_substs).unwrap(); bcx.fcx.param_substs).unwrap();
@ -539,7 +539,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
trans_closure(bcx.ccx(), trans_closure(bcx.ccx(),
decl, decl,
body, body,
llfn, llfn.val,
bcx.fcx.param_substs, bcx.fcx.param_substs,
id, id,
&[], &[],

View File

@ -28,6 +28,7 @@ use middle::subst::{self, Subst, Substs};
use trans::base; use trans::base;
use trans::build; use trans::build;
use trans::cleanup; use trans::cleanup;
use trans::consts;
use trans::datum; use trans::datum;
use trans::debuginfo; use trans::debuginfo;
use trans::machine; use trans::machine;
@ -803,12 +804,9 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
// NB: Do not use `do_spill_noroot` to make this into a constant string, or // NB: Do not use `do_spill_noroot` to make this into a constant string, or
// you will be kicked off fast isel. See issue #4352 for an example of this. // you will be kicked off fast isel. See issue #4352 for an example of this.
pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef { pub fn C_str_slice(cx: &CrateContext, s: InternedString) -> ValueRef {
unsafe { let len = s.get().len();
let len = s.get().len(); let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx));
let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s, false), C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)])
Type::i8p(cx).to_ref());
C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)])
}
} }
pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef { pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef {
@ -824,7 +822,7 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef {
llvm::LLVMSetGlobalConstant(g, True); llvm::LLVMSetGlobalConstant(g, True);
llvm::SetLinkage(g, llvm::InternalLinkage); llvm::SetLinkage(g, llvm::InternalLinkage);
let cs = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); let cs = consts::ptrcast(g, Type::i8p(cx));
C_struct(cx, &[cs, C_uint(cx, len)], false) C_struct(cx, &[cs, C_uint(cx, len)], false)
} }
} }
@ -1095,11 +1093,11 @@ pub enum ExprOrMethodCall {
MethodCallKey(ty::MethodCall) MethodCallKey(ty::MethodCall)
} }
pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
node: ExprOrMethodCall) node: ExprOrMethodCall,
-> subst::Substs<'tcx> param_substs: &subst::Substs<'tcx>)
{ -> subst::Substs<'tcx> {
let tcx = bcx.tcx(); let tcx = ccx.tcx();
let substs = match node { let substs = match node {
ExprId(id) => { ExprId(id) => {
@ -1111,15 +1109,13 @@ pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}; };
if substs.types.any(|t| ty::type_needs_infer(*t)) { if substs.types.any(|t| ty::type_needs_infer(*t)) {
bcx.sess().bug( tcx.sess.bug(format!("type parameters for node {} include inference types: {}",
format!("type parameters for node {} include inference types: \ node, substs.repr(tcx))[]);
{}",
node,
substs.repr(bcx.tcx()))[]);
} }
let substs = substs.erase_regions(); monomorphize::apply_param_substs(tcx,
bcx.monomorphize(&substs) param_substs,
&substs.erase_regions())
} }
pub fn langcall(bcx: Block, pub fn langcall(bcx: Block,

View File

@ -14,13 +14,13 @@ use llvm;
use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False}; use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False};
use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE, use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE}; RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
use metadata::csearch;
use middle::{const_eval, def}; use middle::{const_eval, def};
use trans::{adt, closure, consts, debuginfo, expr, inline, machine}; use trans::{adt, closure, consts, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt}; use trans::base::{self, push_ctxt};
use trans::common::*; use trans::common::*;
use trans::type_::Type; use trans::type_::Type;
use trans::type_of; use trans::type_of;
use middle::subst::Substs;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use util::ppaux::{Repr, ty_to_string}; use util::ppaux::{Repr, ty_to_string};
@ -79,11 +79,9 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
} }
} }
pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef { pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
unsafe { unsafe {
let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref()); llvm::LLVMConstPointerCast(val, ty.to_ref())
assert!(cx.const_globals().borrow_mut().insert(b as int, a).is_none());
b
} }
} }
@ -258,7 +256,9 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr)
match ty.sty { match ty.sty {
ty::ty_vec(unit_ty, Some(len)) => { ty::ty_vec(unit_ty, Some(len)) => {
let llunitty = type_of::type_of(cx, unit_ty); let llunitty = type_of::type_of(cx, unit_ty);
let llptr = const_ptrcast(cx, llconst, llunitty); let llptr = ptrcast(llconst, llunitty.ptr_to());
assert!(cx.const_globals().borrow_mut()
.insert(llptr as int, llconst).is_none());
assert_eq!(abi::FAT_PTR_ADDR, 0); assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1); assert_eq!(abi::FAT_PTR_EXTRA, 1);
llconst = C_struct(cx, &[ llconst = C_struct(cx, &[
@ -523,7 +523,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
} }
} }
(expr::cast_pointer, expr::cast_pointer) => { (expr::cast_pointer, expr::cast_pointer) => {
llvm::LLVMConstPointerCast(v, llty.to_ref()) ptrcast(v, llty)
} }
(expr::cast_integral, expr::cast_pointer) => { (expr::cast_integral, expr::cast_pointer) => {
llvm::LLVMConstIntToPtr(v, llty.to_ref()) llvm::LLVMConstIntToPtr(v, llty.to_ref())
@ -616,36 +616,38 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
C_array(llunitty, vs[]) C_array(llunitty, vs[])
} }
} }
ast::ExprPath(ref pth) => { ast::ExprPath(_) => {
// Assert that there are no type parameters in this path. let def = cx.tcx().def_map.borrow()[e.id];
assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types())); match def {
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
let opt_def = cx.tcx().def_map.borrow().get(&e.id).cloned(); expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
match opt_def {
Some(def::DefFn(def_id, _)) => {
if !ast_util::is_local(def_id) {
let ty = csearch::get_type(cx.tcx(), def_id).ty;
base::trans_external_path(cx, def_id, ty)
} else {
assert!(ast_util::is_local(def_id));
base::get_item_val(cx, def_id.node)
}
} }
Some(def::DefConst(def_id)) => { def::DefConst(def_id) => {
get_const_val(cx, def_id) get_const_val(cx, def_id)
} }
Some(def::DefVariant(enum_did, variant_did, _)) => { def::DefVariant(enum_did, variant_did, _) => {
let ety = ty::expr_ty(cx.tcx(), e);
let repr = adt::represent_type(cx, ety);
let vinfo = ty::enum_variant_with_id(cx.tcx(), let vinfo = ty::enum_variant_with_id(cx.tcx(),
enum_did, enum_did,
variant_did); variant_did);
adt::trans_const(cx, &*repr, vinfo.disr_val, &[]) if vinfo.args.len() > 0 {
// N-ary variant.
expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
} else {
// Nullary variant.
let ety = ty::expr_ty(cx.tcx(), e);
let repr = adt::represent_type(cx, ety);
adt::trans_const(cx, &*repr, vinfo.disr_val, &[])
}
} }
Some(def::DefStruct(_)) => { def::DefStruct(_) => {
let ety = ty::expr_ty(cx.tcx(), e); let ety = ty::expr_ty(cx.tcx(), e);
let llty = type_of::type_of(cx, ety); if let ty::ty_bare_fn(..) = ety.sty {
C_null(llty) // Tuple struct.
expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
} else {
// Unit struct.
C_null(type_of::type_of(cx, ety))
}
} }
_ => { _ => {
cx.sess().span_bug(e.span, "expected a const, fn, struct, \ cx.sess().span_bug(e.span, "expected a const, fn, struct, \

View File

@ -853,7 +853,9 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
match def { match def {
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) | def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) |
def::DefStruct(_) | def::DefVariant(..) => { def::DefStruct(_) | def::DefVariant(..) => {
trans_def_fn_unadjusted(bcx, ref_expr, def) let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
bcx.fcx.param_substs);
DatumBlock::new(bcx, datum.to_expr_datum())
} }
def::DefStatic(did, _) => { def::DefStatic(did, _) => {
// There are two things that may happen here: // There are two things that may happen here:
@ -1250,7 +1252,9 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid); let variant_info = ty::enum_variant_with_id(bcx.tcx(), tid, vid);
if variant_info.args.len() > 0u { if variant_info.args.len() > 0u {
// N-ary variant. // N-ary variant.
let llfn = callee::trans_fn_ref(bcx, vid, ExprId(ref_expr.id)); let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
ExprId(ref_expr.id),
bcx.fcx.param_substs).val;
Store(bcx, llfn, lldest); Store(bcx, llfn, lldest);
return bcx; return bcx;
} else { } else {
@ -1281,34 +1285,33 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
} }
fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ref_expr: &ast::Expr, ref_expr: &ast::Expr,
def: def::Def) def: def::Def,
-> DatumBlock<'blk, 'tcx, Expr> { param_substs: &subst::Substs<'tcx>)
-> Datum<'tcx, Rvalue> {
let _icx = push_ctxt("trans_def_datum_unadjusted"); let _icx = push_ctxt("trans_def_datum_unadjusted");
let llfn = match def { match def {
def::DefFn(did, _) | def::DefFn(did, _) |
def::DefStruct(did) | def::DefVariant(_, did, _) | def::DefStruct(did) | def::DefVariant(_, did, _) |
def::DefStaticMethod(did, def::FromImpl(_)) | def::DefStaticMethod(did, def::FromImpl(_)) |
def::DefMethod(did, _, def::FromImpl(_)) => { def::DefMethod(did, _, def::FromImpl(_)) => {
callee::trans_fn_ref(bcx, did, ExprId(ref_expr.id)) callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
} }
def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) | def::DefStaticMethod(impl_did, def::FromTrait(trait_did)) |
def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => { def::DefMethod(impl_did, _, def::FromTrait(trait_did)) => {
meth::trans_static_method_callee(bcx, impl_did, meth::trans_static_method_callee(ccx, impl_did,
trait_did, ref_expr.id) trait_did, ref_expr.id,
param_substs)
} }
_ => { _ => {
bcx.tcx().sess.span_bug(ref_expr.span, format!( ccx.tcx().sess.span_bug(ref_expr.span, format!(
"trans_def_fn_unadjusted invoked on: {} for {}", "trans_def_fn_unadjusted invoked on: {} for {}",
def, def,
ref_expr.repr(bcx.tcx()))[]); ref_expr.repr(ccx.tcx()))[]);
} }
}; }
let fn_ty = expr_ty(bcx, ref_expr);
DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue))))
} }
/// Translates a reference to a local variable or argument. This always results in an lvalue datum. /// Translates a reference to a local variable or argument. This always results in an lvalue datum.

View File

@ -26,6 +26,7 @@ use trans::build::*;
use trans::callee; use trans::callee;
use trans::cleanup; use trans::cleanup;
use trans::cleanup::CleanupMethods; use trans::cleanup::CleanupMethods;
use trans::consts;
use trans::common::*; use trans::common::*;
use trans::datum; use trans::datum;
use trans::debuginfo; use trans::debuginfo;
@ -577,9 +578,7 @@ pub fn emit_tydescs(ccx: &CrateContext) {
// before being put into the tydesc because we only have a singleton // before being put into the tydesc because we only have a singleton
// tydesc type. Then we'll recast each function to its real type when // tydesc type. Then we'll recast each function to its real type when
// calling it. // calling it.
let drop_glue = unsafe { let drop_glue = consts::ptrcast(get_drop_glue(ccx, ti.ty), glue_fn_ty);
llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
};
ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1); ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1);
let tydesc = C_named_struct(ccx.tydesc_type(), let tydesc = C_named_struct(ccx.tydesc_type(),

View File

@ -122,9 +122,10 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
ty::MethodStaticUnboxedClosure(did) => { ty::MethodStaticUnboxedClosure(did) => {
Callee { Callee {
bcx: bcx, bcx: bcx,
data: Fn(callee::trans_fn_ref(bcx, data: Fn(callee::trans_fn_ref(bcx.ccx(),
did, did,
MethodCallKey(method_call))), MethodCallKey(method_call),
bcx.fcx.param_substs).val),
} }
} }
@ -166,30 +167,31 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
} }
pub fn trans_static_method_callee(bcx: Block, pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
method_id: ast::DefId, method_id: ast::DefId,
trait_id: ast::DefId, trait_id: ast::DefId,
expr_id: ast::NodeId) expr_id: ast::NodeId,
-> ValueRef param_substs: &subst::Substs<'tcx>)
-> Datum<'tcx, Rvalue>
{ {
let _icx = push_ctxt("meth::trans_static_method_callee"); let _icx = push_ctxt("meth::trans_static_method_callee");
let ccx = bcx.ccx(); let tcx = ccx.tcx();
debug!("trans_static_method_callee(method_id={}, trait_id={}, \ debug!("trans_static_method_callee(method_id={}, trait_id={}, \
expr_id={})", expr_id={})",
method_id, method_id,
ty::item_path_str(bcx.tcx(), trait_id), ty::item_path_str(tcx, trait_id),
expr_id); expr_id);
let mname = if method_id.krate == ast::LOCAL_CRATE { let mname = if method_id.krate == ast::LOCAL_CRATE {
match bcx.tcx().map.get(method_id.node) { match tcx.map.get(method_id.node) {
ast_map::NodeTraitItem(method) => { ast_map::NodeTraitItem(method) => {
let ident = match *method { let ident = match *method {
ast::RequiredMethod(ref m) => m.ident, ast::RequiredMethod(ref m) => m.ident,
ast::ProvidedMethod(ref m) => m.pe_ident(), ast::ProvidedMethod(ref m) => m.pe_ident(),
ast::TypeTraitItem(_) => { ast::TypeTraitItem(_) => {
bcx.tcx().sess.bug("trans_static_method_callee() on \ tcx.sess.bug("trans_static_method_callee() on \
an associated type?!") an associated type?!")
} }
}; };
ident.name ident.name
@ -197,7 +199,7 @@ pub fn trans_static_method_callee(bcx: Block,
_ => panic!("callee is not a trait method") _ => panic!("callee is not a trait method")
} }
} else { } else {
csearch::get_item_path(bcx.tcx(), method_id).last().unwrap().name() csearch::get_item_path(tcx, method_id).last().unwrap().name()
}; };
debug!("trans_static_method_callee: method_id={}, expr_id={}, \ debug!("trans_static_method_callee: method_id={}, expr_id={}, \
name={}", method_id, expr_id, token::get_name(mname)); name={}", method_id, expr_id, token::get_name(mname));
@ -205,7 +207,7 @@ pub fn trans_static_method_callee(bcx: Block,
// Find the substitutions for the fn itself. This includes // Find the substitutions for the fn itself. This includes
// type parameters that belong to the trait but also some that // type parameters that belong to the trait but also some that
// belong to the method: // belong to the method:
let rcvr_substs = node_id_substs(bcx, ExprId(expr_id)); let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
let subst::SeparateVecsPerParamSpace { let subst::SeparateVecsPerParamSpace {
types: rcvr_type, types: rcvr_type,
selfs: rcvr_self, selfs: rcvr_self,
@ -238,11 +240,11 @@ pub fn trans_static_method_callee(bcx: Block,
Substs::erased(VecPerParamSpace::new(rcvr_type, Substs::erased(VecPerParamSpace::new(rcvr_type,
rcvr_self, rcvr_self,
Vec::new())); Vec::new()));
let trait_substs = bcx.tcx().mk_substs(trait_substs); let trait_substs = tcx.mk_substs(trait_substs);
debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); debug!("trait_substs={}", trait_substs.repr(tcx));
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id, let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
substs: trait_substs })); substs: trait_substs }));
let vtbl = fulfill_obligation(bcx.ccx(), let vtbl = fulfill_obligation(ccx,
DUMMY_SP, DUMMY_SP,
trait_ref); trait_ref);
@ -282,17 +284,13 @@ pub fn trans_static_method_callee(bcx: Block,
rcvr_method)); rcvr_method));
let mth_id = method_with_name(ccx, impl_did, mname); let mth_id = method_with_name(ccx, impl_did, mname);
let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id), trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id),
callee_substs); param_substs,
callee_substs)
let callee_ty = node_id_type(bcx, expr_id);
let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
PointerCast(bcx, llfn, llty)
} }
_ => { _ => {
bcx.tcx().sess.bug( tcx.sess.bug(format!("static call to invalid vtable: {}",
format!("static call to invalid vtable: {}", vtbl.repr(tcx))[]);
vtbl.repr(bcx.tcx()))[]);
} }
} }
} }
@ -346,20 +344,22 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
bcx, MethodCallKey(method_call), vtable_impl.substs); bcx, MethodCallKey(method_call), vtable_impl.substs);
// translate the function // translate the function
let llfn = trans_fn_ref_with_substs(bcx, let llfn = trans_fn_ref_with_substs(bcx.ccx(),
mth_id, mth_id,
MethodCallKey(method_call), MethodCallKey(method_call),
callee_substs); bcx.fcx.param_substs,
callee_substs).val;
Callee { bcx: bcx, data: Fn(llfn) } Callee { bcx: bcx, data: Fn(llfn) }
} }
traits::VtableUnboxedClosure(closure_def_id, substs) => { traits::VtableUnboxedClosure(closure_def_id, substs) => {
// The substitutions should have no type parameters remaining // The substitutions should have no type parameters remaining
// after passing through fulfill_obligation // after passing through fulfill_obligation
let llfn = trans_fn_ref_with_substs(bcx, let llfn = trans_fn_ref_with_substs(bcx.ccx(),
closure_def_id, closure_def_id,
MethodCallKey(method_call), MethodCallKey(method_call),
substs); bcx.fcx.param_substs,
substs).val;
Callee { Callee {
bcx: bcx, bcx: bcx,
@ -400,7 +400,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
{ {
let ccx = bcx.ccx(); let ccx = bcx.ccx();
let node_substs = node_id_substs(bcx, node); let node_substs = node_id_substs(ccx, node, bcx.fcx.param_substs);
debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx())); debug!("rcvr_substs={}", rcvr_substs.repr(ccx.tcx()));
debug!("node_substs={}", node_substs.repr(ccx.tcx())); debug!("node_substs={}", node_substs.repr(ccx.tcx()));
@ -684,10 +684,11 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
traits::VtableUnboxedClosure(closure_def_id, substs) => { traits::VtableUnboxedClosure(closure_def_id, substs) => {
let llfn = trans_fn_ref_with_substs( let llfn = trans_fn_ref_with_substs(
bcx, bcx.ccx(),
closure_def_id, closure_def_id,
ExprId(0), ExprId(0),
substs.clone()); bcx.fcx.param_substs,
substs.clone()).val;
(vec!(llfn)).into_iter() (vec!(llfn)).into_iter()
} }
@ -788,10 +789,11 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Some(C_null(Type::nil(ccx).ptr_to())).into_iter() Some(C_null(Type::nil(ccx).ptr_to())).into_iter()
} else { } else {
let fn_ref = trans_fn_ref_with_substs( let fn_ref = trans_fn_ref_with_substs(
bcx, ccx,
m_id, m_id,
ExprId(0), ExprId(0),
substs.clone()); bcx.fcx.param_substs,
substs.clone()).val;
// currently, at least, by-value self is not object safe // currently, at least, by-value self is not object safe
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory); assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);

View File

@ -38,7 +38,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_id: ast::DefId, fn_id: ast::DefId,
psubsts: &subst::Substs<'tcx>, psubsts: &subst::Substs<'tcx>,
ref_id: Option<ast::NodeId>) ref_id: Option<ast::NodeId>)
-> (ValueRef, bool) { -> (ValueRef, Ty<'tcx>, bool) {
debug!("monomorphic_fn(\ debug!("monomorphic_fn(\
fn_id={}, \ fn_id={}, \
real_substs={}, \ real_substs={}, \
@ -58,11 +58,14 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
params: psubsts.types.clone() params: psubsts.types.clone()
}; };
let item_ty = ty::lookup_item_type(ccx.tcx(), fn_id).ty;
let mono_ty = item_ty.subst(ccx.tcx(), psubsts);
match ccx.monomorphized().borrow().get(&hash_id) { match ccx.monomorphized().borrow().get(&hash_id) {
Some(&val) => { Some(&val) => {
debug!("leaving monomorphic fn {}", debug!("leaving monomorphic fn {}",
ty::item_path_str(ccx.tcx(), fn_id)); ty::item_path_str(ccx.tcx(), fn_id));
return (val, false); return (val, mono_ty, false);
} }
None => () None => ()
} }
@ -75,8 +78,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
psubsts.repr(ccx.tcx()), psubsts.repr(ccx.tcx()),
hash_id); hash_id);
let tpt = ty::lookup_item_type(ccx.tcx(), fn_id);
let llitem_ty = tpt.ty;
let map_node = session::expect( let map_node = session::expect(
ccx.sess(), ccx.sess(),
@ -91,13 +92,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if let ast_map::NodeForeignItem(_) = map_node { if let ast_map::NodeForeignItem(_) = map_node {
if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic { if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
// Foreign externs don't have to be monomorphized. // Foreign externs don't have to be monomorphized.
return (get_item_val(ccx, fn_id.node), true); return (get_item_val(ccx, fn_id.node), mono_ty, true);
} }
} }
debug!("monomorphic_fn about to subst into {}", llitem_ty.repr(ccx.tcx())); debug!("monomorphic_fn about to subst into {}", item_ty.repr(ccx.tcx()));
let mono_ty = llitem_ty.subst(ccx.tcx(), psubsts);
debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx())); debug!("mono_ty = {} (post-substitution)", mono_ty.repr(ccx.tcx()));
let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty); let mono_ty = normalize_associated_type(ccx.tcx(), &mono_ty);
@ -283,7 +283,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.monomorphizing().borrow_mut().insert(fn_id, depth); ccx.monomorphizing().borrow_mut().insert(fn_id, depth);
debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id)); debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
(lldecl, true) (lldecl, mono_ty, true)
} }
#[derive(PartialEq, Eq, Hash, Show)] #[derive(PartialEq, Eq, Hash, Show)]

View File

@ -19,6 +19,7 @@ use trans::build::*;
use trans::cleanup; use trans::cleanup;
use trans::cleanup::CleanupMethods; use trans::cleanup::CleanupMethods;
use trans::common::*; use trans::common::*;
use trans::consts;
use trans::datum::*; use trans::datum::*;
use trans::expr::{Dest, Ignore, SaveIn}; use trans::expr::{Dest, Ignore, SaveIn};
use trans::expr; use trans::expr;
@ -213,15 +214,13 @@ pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
match dest { match dest {
Ignore => bcx, Ignore => bcx,
SaveIn(lldest) => { SaveIn(lldest) => {
unsafe { let bytes = str_lit.get().len();
let bytes = str_lit.get().len(); let llbytes = C_uint(bcx.ccx(), bytes);
let llbytes = C_uint(bcx.ccx(), bytes); let llcstr = C_cstr(bcx.ccx(), str_lit, false);
let llcstr = C_cstr(bcx.ccx(), str_lit, false); let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref()); Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR]));
Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR])); Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA]));
Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA])); bcx
bcx
}
} }
} }
} }

View File

@ -0,0 +1,84 @@
// 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 <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.
#![feature(macro_rules)]
use std::collections::Bitv;
use std::default::Default;
use std::iter::FromIterator;
use std::option::IntoIter as OptionIter;
use std::rand::Rand;
use std::rand::XorShiftRng as DummyRng;
// FIXME the glob std::prelude::*; import of Vec is missing non-static inherent methods.
use std::vec::Vec;
#[derive(PartialEq, Eq)]
struct Newt<T>(T);
fn id<T>(x: T) -> T { x }
fn eq<T: Eq>(a: T, b: T) -> bool { a == b }
fn u8_as_i8(x: u8) -> i8 { x as i8 }
fn odd(x: uint) -> bool { x % 2 == 1 }
fn dummy_rng() -> DummyRng { DummyRng::new_unseeded() }
macro_rules! tests {
($($expr:expr: $ty:ty /($($test:expr),*);)+) => (pub fn main() {$({
const C: $ty = $expr;
static S: $ty = $expr;
assert!(eq(C($($test),*), $expr($($test),*)));
assert!(eq(S($($test),*), $expr($($test),*)));
assert!(eq(C($($test),*), S($($test),*)));
})+})
}
tests! {
// Free function.
id: fn(int) -> int /(5);
id::<int>: fn(int) -> int /(5);
// Enum variant constructor.
Some: fn(int) -> Option<int> /(5);
Some::<int>: fn(int) -> Option<int> /(5);
// Tuple struct constructor.
Newt: fn(int) -> Newt<int> /(5);
Newt::<int>: fn(int) -> Newt<int> /(5);
// Inherent static methods.
Vec::new: fn() -> Vec<()> /();
Vec::<()>::new: fn() -> Vec<()> /();
Vec::with_capacity: fn(uint) -> Vec<()> /(5);
Vec::<()>::with_capacity: fn(uint) -> Vec<()> /(5);
Bitv::from_fn: fn(uint, fn(uint) -> bool) -> Bitv /(5, odd);
Bitv::from_fn::<fn(uint) -> bool>: fn(uint, fn(uint) -> bool) -> Bitv /(5, odd);
// Inherent non-static method.
Vec::map_in_place: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
/(vec![b'f', b'o', b'o'], u8_as_i8);
Vec::map_in_place::<i8, fn(u8) -> i8>: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
/(vec![b'f', b'o', b'o'], u8_as_i8);
// FIXME these break with "type parameter might not appear here pointing at `<u8>`.
// Vec::<u8>::map_in_place: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
// /(vec![b'f', b'o', b'o'], u8_as_i8);
// Vec::<u8>::map_in_place::<i8, fn(u8) -> i8>: fn(Vec<u8>, fn(u8) -> i8) -> Vec<i8>
// /(vec![b'f', b'o', b'o'], u8_as_i8);
// Trait static methods.
// FIXME qualified path expressions aka UFCS i.e. <T as Trait>::method.
Default::default: fn() -> int /();
Rand::rand: fn(&mut DummyRng) -> int /(&mut dummy_rng());
Rand::rand::<DummyRng>: fn(&mut DummyRng) -> int /(&mut dummy_rng());
// Trait non-static methods.
Clone::clone: fn(&int) -> int /(&5);
FromIterator::from_iter: fn(OptionIter<int>) -> Vec<int> /(Some(5).into_iter());
FromIterator::from_iter::<OptionIter<int>>: fn(OptionIter<int>) -> Vec<int>
/(Some(5).into_iter());
}