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:
commit
e9818564bd
@ -14,9 +14,7 @@ use middle::ty;
|
||||
use util::ppaux;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::visit;
|
||||
use syntax::visit::{self, Visitor};
|
||||
|
||||
struct CheckCrateVisitor<'a, 'tcx: 'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
@ -37,24 +35,39 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
|
||||
{
|
||||
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> {
|
||||
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) {
|
||||
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) {
|
||||
if check_expr(self, ex) {
|
||||
visit::walk_expr(self, ex);
|
||||
if self.in_const {
|
||||
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();
|
||||
}
|
||||
|
||||
fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
|
||||
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 }
|
||||
|
||||
fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) {
|
||||
match e.node {
|
||||
ast::ExprUnary(ast::UnDeref, _) => {}
|
||||
ast::ExprUnary(ast::UnUniq, _) => {
|
||||
span_err!(v.tcx.sess, e.span, E0010,
|
||||
"cannot do allocations in constant expressions");
|
||||
return false;
|
||||
}
|
||||
ast::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {}
|
||||
ast::ExprBinary(..) | ast::ExprUnary(..) => {
|
||||
let method_call = ty::MethodCall::expr(e.id);
|
||||
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");
|
||||
}
|
||||
}
|
||||
ast::ExprLit(_) => (),
|
||||
ast::ExprLit(_) => {}
|
||||
ast::ExprCast(ref from, _) => {
|
||||
let toty = ty::expr_ty(v.tcx, e);
|
||||
let fromty = ty::expr_ty(v.tcx, &**from);
|
||||
@ -142,39 +111,23 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) -> bool {
|
||||
expression");
|
||||
}
|
||||
}
|
||||
ast::ExprPath(ref pth) => {
|
||||
// NB: In the future you might wish to relax this slightly
|
||||
// to handle on-demand instantiation of functions via
|
||||
// foo::<bar> in a const. Currently that is only done on
|
||||
// a path in trans::callee that only works in block contexts.
|
||||
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(_)) => { }
|
||||
ast::ExprPath(_) => {
|
||||
match v.tcx.def_map.borrow()[e.id] {
|
||||
DefStatic(..) | DefConst(..) |
|
||||
DefFn(..) | DefStaticMethod(..) | DefMethod(..) |
|
||||
DefStruct(_) | DefVariant(_, _, _) => {}
|
||||
|
||||
Some(&def) => {
|
||||
def => {
|
||||
debug!("(checking const) found bad def: {}", def);
|
||||
span_err!(v.tcx.sess, e.span, E0014,
|
||||
"paths in constants may only refer to constants \
|
||||
or functions");
|
||||
}
|
||||
None => {
|
||||
v.tcx.sess.span_bug(e.span, "unbound path in const?!");
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprCall(ref callee, _) => {
|
||||
match v.tcx.def_map.borrow().get(&callee.id) {
|
||||
Some(&DefStruct(..)) |
|
||||
Some(&DefVariant(..)) => {} // OK.
|
||||
|
||||
match v.tcx.def_map.borrow()[callee.id] {
|
||||
DefStruct(..) | DefVariant(..) => {} // OK.
|
||||
_ => {
|
||||
span_err!(v.tcx.sess, e.span, E0015,
|
||||
"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 \
|
||||
tail expressions");
|
||||
match stmt.node {
|
||||
ast::StmtDecl(ref span, _) => {
|
||||
match span.node {
|
||||
ast::DeclLocal(_) => block_span_err(span.span),
|
||||
ast::StmtDecl(ref decl, _) => {
|
||||
match decl.node {
|
||||
ast::DeclLocal(_) => block_span_err(decl.span),
|
||||
|
||||
// Item statements are allowed
|
||||
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::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,
|
||||
"constant contains unimplemented expression type");
|
||||
return false;
|
||||
}
|
||||
_ => span_err!(v.tcx.sess, e.span, E0019,
|
||||
"constant contains unimplemented expression type")
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -559,14 +559,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
||||
id, expr_ty.repr(self.tcx()), def);
|
||||
|
||||
match def {
|
||||
def::DefStruct(..) | def::DefVariant(..) | def::DefFn(..) |
|
||||
def::DefStaticMethod(..) | def::DefConst(..) => {
|
||||
def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
|
||||
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
|
||||
Ok(self.cat_rvalue_node(id, span, expr_ty))
|
||||
}
|
||||
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
|
||||
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
|
||||
def::DefTyParam(..) | def::DefTyParamBinder(..) | def::DefRegion(_) |
|
||||
def::DefLabel(_) | def::DefSelfTy(..) | def::DefMethod(..) |
|
||||
def::DefLabel(_) | def::DefSelfTy(..) |
|
||||
def::DefAssociatedTy(..) | def::DefAssociatedPath(..)=> {
|
||||
Ok(Rc::new(cmt_ {
|
||||
id:id,
|
||||
|
@ -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
|
||||
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
|
||||
} else if did.krate == ast::LOCAL_CRATE {
|
||||
|
@ -38,6 +38,7 @@ use trans::cleanup::CleanupMethods;
|
||||
use trans::closure;
|
||||
use trans::common;
|
||||
use trans::common::*;
|
||||
use trans::consts;
|
||||
use trans::datum::*;
|
||||
use trans::expr;
|
||||
use trans::glue;
|
||||
@ -152,7 +153,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
||||
_ => 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 {
|
||||
bcx: bcx,
|
||||
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,
|
||||
_ => 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);
|
||||
Callee { bcx: bcx, data: Intrinsic(def_id.node, substs) }
|
||||
}
|
||||
def::DefFn(did, _) | def::DefMethod(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::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,
|
||||
ref_expr.id))
|
||||
ref_expr.id,
|
||||
bcx.fcx.param_substs).val)
|
||||
}
|
||||
def::DefVariant(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
|
||||
assert!(vinfo.args.len() > 0u);
|
||||
@ -189,7 +196,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
||||
}
|
||||
}
|
||||
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 {
|
||||
bcx: bcx,
|
||||
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
|
||||
/// 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 substs = node_id_substs(bcx, node);
|
||||
let substs = node_id_substs(ccx, node, param_substs);
|
||||
debug!("trans_fn_ref(def_id={}, node={}, substs={})",
|
||||
def_id.repr(bcx.tcx()),
|
||||
def_id.repr(ccx.tcx()),
|
||||
node,
|
||||
substs.repr(bcx.tcx()));
|
||||
trans_fn_ref_with_substs(bcx, def_id, node, substs)
|
||||
substs.repr(ccx.tcx()));
|
||||
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>,
|
||||
@ -235,10 +247,11 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
-> Callee<'blk, 'tcx> {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(trans_fn_ref_with_substs(bcx,
|
||||
data: Fn(trans_fn_ref_with_substs(bcx.ccx(),
|
||||
def_id,
|
||||
ExprId(ref_id),
|
||||
substs)),
|
||||
bcx.fcx.param_substs,
|
||||
substs).val),
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,28 +377,30 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||
///
|
||||
/// # 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
|
||||
/// - `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
|
||||
/// 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
|
||||
pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
||||
bcx: Block<'blk, 'tcx>, //
|
||||
def_id: ast::DefId, // def id of fn
|
||||
node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A
|
||||
substs: subst::Substs<'tcx>) // vtables for the call
|
||||
-> ValueRef
|
||||
pub fn trans_fn_ref_with_substs<'a, 'tcx>(
|
||||
ccx: &CrateContext<'a, 'tcx>,
|
||||
def_id: ast::DefId,
|
||||
node: ExprOrMethodCall,
|
||||
param_substs: &subst::Substs<'tcx>,
|
||||
substs: subst::Substs<'tcx>)
|
||||
-> Datum<'tcx, Rvalue>
|
||||
{
|
||||
let _icx = push_ctxt("trans_fn_ref_with_substs");
|
||||
let ccx = bcx.ccx();
|
||||
let tcx = bcx.tcx();
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
debug!("trans_fn_ref_with_substs(bcx={}, def_id={}, node={}, \
|
||||
substs={})",
|
||||
bcx.to_str(),
|
||||
debug!("trans_fn_ref_with_substs(def_id={}, node={}, \
|
||||
param_substs={}, substs={})",
|
||||
def_id.repr(tcx),
|
||||
node,
|
||||
param_substs.repr(tcx),
|
||||
substs.repr(tcx));
|
||||
|
||||
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)
|
||||
}
|
||||
ty::TypeTraitItem(_) => {
|
||||
bcx.tcx().sess.bug("trans_fn_ref_with_vtables() tried \
|
||||
to translate an associated type?!")
|
||||
tcx.sess.bug("trans_fn_ref_with_vtables() tried \
|
||||
to translate an associated type?!")
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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,
|
||||
&substs) {
|
||||
None => {}
|
||||
@ -494,24 +509,27 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
||||
MethodCallKey(_) => None,
|
||||
};
|
||||
|
||||
let (val, must_cast) =
|
||||
let (val, fn_ty, must_cast) =
|
||||
monomorphize::monomorphic_fn(ccx, def_id, &substs, opt_ref_id);
|
||||
let mut val = val;
|
||||
if must_cast && node != ExprId(0) {
|
||||
// Monotype of the REFERENCE to the function (type params
|
||||
// are subst'd)
|
||||
let ref_ty = match node {
|
||||
ExprId(id) => node_id_type(bcx, id),
|
||||
ExprId(id) => ty::node_id_to_type(tcx, id),
|
||||
MethodCallKey(method_call) => {
|
||||
let t = (*bcx.tcx().method_map.borrow())[method_call].ty;
|
||||
monomorphize_type(bcx, t)
|
||||
(*tcx.method_map.borrow())[method_call].ty
|
||||
}
|
||||
};
|
||||
|
||||
val = PointerCast(
|
||||
bcx, val, type_of::type_of_fn_from_ty(ccx, ref_ty).ptr_to());
|
||||
let ref_ty = monomorphize::apply_param_substs(tcx,
|
||||
param_substs,
|
||||
&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)
|
||||
@ -556,12 +574,12 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>(
|
||||
let llptrty = llty.ptr_to();
|
||||
if val_ty(val) != llptrty {
|
||||
debug!("trans_fn_ref_with_vtables(): casting pointer!");
|
||||
val = BitCast(bcx, val, llptrty);
|
||||
val = consts::ptrcast(val, llptrty);
|
||||
} else {
|
||||
debug!("trans_fn_ref_with_vtables(): not casting pointer!");
|
||||
}
|
||||
|
||||
val
|
||||
Datum::new(val, fn_type, Rvalue::new(ByValue))
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
|
@ -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
|
||||
// that LLVM can later use.
|
||||
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 => {
|
||||
let mut personality = self.ccx.eh_personality().borrow_mut();
|
||||
match *personality {
|
||||
|
@ -20,6 +20,7 @@ use trans::build::*;
|
||||
use trans::cleanup::{CleanupMethods, ScopeId};
|
||||
use trans::common::*;
|
||||
use trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
|
||||
use trans::datum::{Rvalue, ByValue};
|
||||
use trans::debuginfo;
|
||||
use trans::expr;
|
||||
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
|
||||
/// 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>,
|
||||
closure_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<ValueRef> {
|
||||
let ccx = bcx.ccx();
|
||||
pub fn get_or_create_declaration_if_unboxed_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
closure_id: ast::DefId,
|
||||
substs: &Substs<'tcx>)
|
||||
-> Option<Datum<'tcx, Rvalue>> {
|
||||
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
|
||||
// Not an unboxed closure.
|
||||
return None
|
||||
}
|
||||
|
||||
let function_type = ty::node_id_to_type(bcx.tcx(), closure_id.node);
|
||||
let function_type = monomorphize::apply_param_substs(bcx.tcx(), substs, &function_type);
|
||||
let function_type = ty::node_id_to_type(ccx.tcx(), closure_id.node);
|
||||
let function_type = monomorphize::apply_param_substs(ccx.tcx(), substs, &function_type);
|
||||
|
||||
// Normalize type so differences in regions and typedefs don't cause
|
||||
// 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 {
|
||||
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
|
||||
_ => 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) {
|
||||
Some(llfn) => {
|
||||
Some(&llfn) => {
|
||||
debug!("get_or_create_declaration_if_unboxed_closure(): found \
|
||||
closure");
|
||||
return Some(*llfn)
|
||||
return Some(Datum::new(llfn, function_type, Rvalue::new(ByValue)))
|
||||
}
|
||||
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.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>(
|
||||
@ -519,7 +519,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
|
||||
|
||||
let closure_id = ast_util::local_def(id);
|
||||
let llfn = get_or_create_declaration_if_unboxed_closure(
|
||||
bcx,
|
||||
bcx.ccx(),
|
||||
closure_id,
|
||||
bcx.fcx.param_substs).unwrap();
|
||||
|
||||
@ -539,7 +539,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(
|
||||
trans_closure(bcx.ccx(),
|
||||
decl,
|
||||
body,
|
||||
llfn,
|
||||
llfn.val,
|
||||
bcx.fcx.param_substs,
|
||||
id,
|
||||
&[],
|
||||
|
@ -28,6 +28,7 @@ use middle::subst::{self, Subst, Substs};
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::cleanup;
|
||||
use trans::consts;
|
||||
use trans::datum;
|
||||
use trans::debuginfo;
|
||||
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
|
||||
// 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 {
|
||||
unsafe {
|
||||
let len = s.get().len();
|
||||
let cs = llvm::LLVMConstPointerCast(C_cstr(cx, s, false),
|
||||
Type::i8p(cx).to_ref());
|
||||
C_named_struct(cx.tn().find_type("str_slice").unwrap(), &[cs, C_uint(cx, len)])
|
||||
}
|
||||
let len = s.get().len();
|
||||
let cs = consts::ptrcast(C_cstr(cx, s, false), Type::i8p(cx));
|
||||
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 {
|
||||
@ -824,7 +822,7 @@ pub fn C_binary_slice(cx: &CrateContext, data: &[u8]) -> ValueRef {
|
||||
llvm::LLVMSetGlobalConstant(g, True);
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -1095,11 +1093,11 @@ pub enum ExprOrMethodCall {
|
||||
MethodCallKey(ty::MethodCall)
|
||||
}
|
||||
|
||||
pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
node: ExprOrMethodCall)
|
||||
-> subst::Substs<'tcx>
|
||||
{
|
||||
let tcx = bcx.tcx();
|
||||
pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
node: ExprOrMethodCall,
|
||||
param_substs: &subst::Substs<'tcx>)
|
||||
-> subst::Substs<'tcx> {
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
let substs = match node {
|
||||
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)) {
|
||||
bcx.sess().bug(
|
||||
format!("type parameters for node {} include inference types: \
|
||||
{}",
|
||||
node,
|
||||
substs.repr(bcx.tcx()))[]);
|
||||
tcx.sess.bug(format!("type parameters for node {} include inference types: {}",
|
||||
node, substs.repr(tcx))[]);
|
||||
}
|
||||
|
||||
let substs = substs.erase_regions();
|
||||
bcx.monomorphize(&substs)
|
||||
monomorphize::apply_param_substs(tcx,
|
||||
param_substs,
|
||||
&substs.erase_regions())
|
||||
}
|
||||
|
||||
pub fn langcall(bcx: Block,
|
||||
|
@ -14,13 +14,13 @@ use llvm;
|
||||
use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False};
|
||||
use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
|
||||
RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
|
||||
use metadata::csearch;
|
||||
use middle::{const_eval, def};
|
||||
use trans::{adt, closure, consts, debuginfo, expr, inline, machine};
|
||||
use trans::base::{self, push_ctxt};
|
||||
use trans::common::*;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, Ty};
|
||||
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 {
|
||||
let b = llvm::LLVMConstPointerCast(a, t.ptr_to().to_ref());
|
||||
assert!(cx.const_globals().borrow_mut().insert(b as int, a).is_none());
|
||||
b
|
||||
llvm::LLVMConstPointerCast(val, ty.to_ref())
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +256,9 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, e: &ast::Expr)
|
||||
match ty.sty {
|
||||
ty::ty_vec(unit_ty, Some(len)) => {
|
||||
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_EXTRA, 1);
|
||||
llconst = C_struct(cx, &[
|
||||
@ -523,7 +523,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
|
||||
}
|
||||
}
|
||||
(expr::cast_pointer, expr::cast_pointer) => {
|
||||
llvm::LLVMConstPointerCast(v, llty.to_ref())
|
||||
ptrcast(v, llty)
|
||||
}
|
||||
(expr::cast_integral, expr::cast_pointer) => {
|
||||
llvm::LLVMConstIntToPtr(v, llty.to_ref())
|
||||
@ -616,36 +616,38 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr) -> ValueRef {
|
||||
C_array(llunitty, vs[])
|
||||
}
|
||||
}
|
||||
ast::ExprPath(ref pth) => {
|
||||
// Assert that there are no type parameters in this path.
|
||||
assert!(pth.segments.iter().all(|seg| !seg.parameters.has_types()));
|
||||
|
||||
let opt_def = cx.tcx().def_map.borrow().get(&e.id).cloned();
|
||||
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)
|
||||
}
|
||||
ast::ExprPath(_) => {
|
||||
let def = cx.tcx().def_map.borrow()[e.id];
|
||||
match def {
|
||||
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) => {
|
||||
expr::trans_def_fn_unadjusted(cx, e, def, &Substs::trans_empty()).val
|
||||
}
|
||||
Some(def::DefConst(def_id)) => {
|
||||
def::DefConst(def_id) => {
|
||||
get_const_val(cx, def_id)
|
||||
}
|
||||
Some(def::DefVariant(enum_did, variant_did, _)) => {
|
||||
let ety = ty::expr_ty(cx.tcx(), e);
|
||||
let repr = adt::represent_type(cx, ety);
|
||||
def::DefVariant(enum_did, variant_did, _) => {
|
||||
let vinfo = ty::enum_variant_with_id(cx.tcx(),
|
||||
enum_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 llty = type_of::type_of(cx, ety);
|
||||
C_null(llty)
|
||||
if let ty::ty_bare_fn(..) = ety.sty {
|
||||
// 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, \
|
||||
|
@ -853,7 +853,9 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
match def {
|
||||
def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) |
|
||||
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, _) => {
|
||||
// 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);
|
||||
if variant_info.args.len() > 0u {
|
||||
// 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);
|
||||
return bcx;
|
||||
} 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>,
|
||||
ref_expr: &ast::Expr,
|
||||
def: def::Def)
|
||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
||||
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ref_expr: &ast::Expr,
|
||||
def: def::Def,
|
||||
param_substs: &subst::Substs<'tcx>)
|
||||
-> Datum<'tcx, Rvalue> {
|
||||
let _icx = push_ctxt("trans_def_datum_unadjusted");
|
||||
|
||||
let llfn = match def {
|
||||
match def {
|
||||
def::DefFn(did, _) |
|
||||
def::DefStruct(did) | def::DefVariant(_, did, _) |
|
||||
def::DefStaticMethod(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::DefMethod(impl_did, _, def::FromTrait(trait_did)) => {
|
||||
meth::trans_static_method_callee(bcx, impl_did,
|
||||
trait_did, ref_expr.id)
|
||||
meth::trans_static_method_callee(ccx, impl_did,
|
||||
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 {}",
|
||||
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.
|
||||
|
@ -26,6 +26,7 @@ use trans::build::*;
|
||||
use trans::callee;
|
||||
use trans::cleanup;
|
||||
use trans::cleanup::CleanupMethods;
|
||||
use trans::consts;
|
||||
use trans::common::*;
|
||||
use trans::datum;
|
||||
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
|
||||
// tydesc type. Then we'll recast each function to its real type when
|
||||
// calling it.
|
||||
let drop_glue = unsafe {
|
||||
llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
|
||||
};
|
||||
let drop_glue = consts::ptrcast(get_drop_glue(ccx, ti.ty), glue_fn_ty);
|
||||
ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1);
|
||||
|
||||
let tydesc = C_named_struct(ccx.tydesc_type(),
|
||||
|
@ -122,9 +122,10 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
ty::MethodStaticUnboxedClosure(did) => {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(callee::trans_fn_ref(bcx,
|
||||
data: Fn(callee::trans_fn_ref(bcx.ccx(),
|
||||
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,
|
||||
method_id: ast::DefId,
|
||||
trait_id: ast::DefId,
|
||||
expr_id: ast::NodeId)
|
||||
-> ValueRef
|
||||
pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
method_id: ast::DefId,
|
||||
trait_id: ast::DefId,
|
||||
expr_id: ast::NodeId,
|
||||
param_substs: &subst::Substs<'tcx>)
|
||||
-> Datum<'tcx, Rvalue>
|
||||
{
|
||||
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={}, \
|
||||
expr_id={})",
|
||||
method_id,
|
||||
ty::item_path_str(bcx.tcx(), trait_id),
|
||||
ty::item_path_str(tcx, trait_id),
|
||||
expr_id);
|
||||
|
||||
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) => {
|
||||
let ident = match *method {
|
||||
ast::RequiredMethod(ref m) => m.ident,
|
||||
ast::ProvidedMethod(ref m) => m.pe_ident(),
|
||||
ast::TypeTraitItem(_) => {
|
||||
bcx.tcx().sess.bug("trans_static_method_callee() on \
|
||||
an associated type?!")
|
||||
tcx.sess.bug("trans_static_method_callee() on \
|
||||
an associated type?!")
|
||||
}
|
||||
};
|
||||
ident.name
|
||||
@ -197,7 +199,7 @@ pub fn trans_static_method_callee(bcx: Block,
|
||||
_ => panic!("callee is not a trait method")
|
||||
}
|
||||
} 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={}, \
|
||||
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
|
||||
// type parameters that belong to the trait but also some that
|
||||
// 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 {
|
||||
types: rcvr_type,
|
||||
selfs: rcvr_self,
|
||||
@ -238,11 +240,11 @@ pub fn trans_static_method_callee(bcx: Block,
|
||||
Substs::erased(VecPerParamSpace::new(rcvr_type,
|
||||
rcvr_self,
|
||||
Vec::new()));
|
||||
let trait_substs = bcx.tcx().mk_substs(trait_substs);
|
||||
debug!("trait_substs={}", trait_substs.repr(bcx.tcx()));
|
||||
let trait_substs = tcx.mk_substs(trait_substs);
|
||||
debug!("trait_substs={}", trait_substs.repr(tcx));
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
|
||||
substs: trait_substs }));
|
||||
let vtbl = fulfill_obligation(bcx.ccx(),
|
||||
let vtbl = fulfill_obligation(ccx,
|
||||
DUMMY_SP,
|
||||
trait_ref);
|
||||
|
||||
@ -282,17 +284,13 @@ pub fn trans_static_method_callee(bcx: Block,
|
||||
rcvr_method));
|
||||
|
||||
let mth_id = method_with_name(ccx, impl_did, mname);
|
||||
let llfn = trans_fn_ref_with_substs(bcx, mth_id, ExprId(expr_id),
|
||||
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)
|
||||
trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id),
|
||||
param_substs,
|
||||
callee_substs)
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.bug(
|
||||
format!("static call to invalid vtable: {}",
|
||||
vtbl.repr(bcx.tcx()))[]);
|
||||
tcx.sess.bug(format!("static call to invalid vtable: {}",
|
||||
vtbl.repr(tcx))[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -346,20 +344,22 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
bcx, MethodCallKey(method_call), vtable_impl.substs);
|
||||
|
||||
// translate the function
|
||||
let llfn = trans_fn_ref_with_substs(bcx,
|
||||
let llfn = trans_fn_ref_with_substs(bcx.ccx(),
|
||||
mth_id,
|
||||
MethodCallKey(method_call),
|
||||
callee_substs);
|
||||
bcx.fcx.param_substs,
|
||||
callee_substs).val;
|
||||
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
}
|
||||
traits::VtableUnboxedClosure(closure_def_id, substs) => {
|
||||
// The substitutions should have no type parameters remaining
|
||||
// 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,
|
||||
MethodCallKey(method_call),
|
||||
substs);
|
||||
bcx.fcx.param_substs,
|
||||
substs).val;
|
||||
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
@ -400,7 +400,7 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
{
|
||||
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!("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) => {
|
||||
let llfn = trans_fn_ref_with_substs(
|
||||
bcx,
|
||||
bcx.ccx(),
|
||||
closure_def_id,
|
||||
ExprId(0),
|
||||
substs.clone());
|
||||
bcx.fcx.param_substs,
|
||||
substs.clone()).val;
|
||||
|
||||
(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()
|
||||
} else {
|
||||
let fn_ref = trans_fn_ref_with_substs(
|
||||
bcx,
|
||||
ccx,
|
||||
m_id,
|
||||
ExprId(0),
|
||||
substs.clone());
|
||||
bcx.fcx.param_substs,
|
||||
substs.clone()).val;
|
||||
|
||||
// currently, at least, by-value self is not object safe
|
||||
assert!(m.explicit_self != ty::ByValueExplicitSelfCategory);
|
||||
|
@ -38,7 +38,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_id: ast::DefId,
|
||||
psubsts: &subst::Substs<'tcx>,
|
||||
ref_id: Option<ast::NodeId>)
|
||||
-> (ValueRef, bool) {
|
||||
-> (ValueRef, Ty<'tcx>, bool) {
|
||||
debug!("monomorphic_fn(\
|
||||
fn_id={}, \
|
||||
real_substs={}, \
|
||||
@ -58,11 +58,14 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
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) {
|
||||
Some(&val) => {
|
||||
debug!("leaving monomorphic fn {}",
|
||||
ty::item_path_str(ccx.tcx(), fn_id));
|
||||
return (val, false);
|
||||
return (val, mono_ty, false);
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
@ -75,8 +78,6 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
psubsts.repr(ccx.tcx()),
|
||||
hash_id);
|
||||
|
||||
let tpt = ty::lookup_item_type(ccx.tcx(), fn_id);
|
||||
let llitem_ty = tpt.ty;
|
||||
|
||||
let map_node = session::expect(
|
||||
ccx.sess(),
|
||||
@ -91,13 +92,12 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
if let ast_map::NodeForeignItem(_) = map_node {
|
||||
if ccx.tcx().map.get_foreign_abi(fn_id.node) != abi::RustIntrinsic {
|
||||
// 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()));
|
||||
|
||||
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);
|
||||
|
||||
debug!("leaving monomorphic fn {}", ty::item_path_str(ccx.tcx(), fn_id));
|
||||
(lldecl, true)
|
||||
(lldecl, mono_ty, true)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Show)]
|
||||
|
@ -19,6 +19,7 @@ use trans::build::*;
|
||||
use trans::cleanup;
|
||||
use trans::cleanup::CleanupMethods;
|
||||
use trans::common::*;
|
||||
use trans::consts;
|
||||
use trans::datum::*;
|
||||
use trans::expr::{Dest, Ignore, SaveIn};
|
||||
use trans::expr;
|
||||
@ -213,15 +214,13 @@ pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
match dest {
|
||||
Ignore => bcx,
|
||||
SaveIn(lldest) => {
|
||||
unsafe {
|
||||
let bytes = str_lit.get().len();
|
||||
let llbytes = C_uint(bcx.ccx(), bytes);
|
||||
let llcstr = C_cstr(bcx.ccx(), str_lit, false);
|
||||
let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
|
||||
Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR]));
|
||||
Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA]));
|
||||
bcx
|
||||
}
|
||||
let bytes = str_lit.get().len();
|
||||
let llbytes = C_uint(bcx.ccx(), bytes);
|
||||
let llcstr = C_cstr(bcx.ccx(), str_lit, false);
|
||||
let llcstr = consts::ptrcast(llcstr, Type::i8p(bcx.ccx()));
|
||||
Store(bcx, llcstr, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_ADDR]));
|
||||
Store(bcx, llbytes, GEPi(bcx, lldest, &[0u, abi::FAT_PTR_EXTRA]));
|
||||
bcx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
84
src/test/run-pass/const-polymorphic-paths.rs
Normal file
84
src/test/run-pass/const-polymorphic-paths.rs
Normal 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());
|
||||
}
|
Loading…
Reference in New Issue
Block a user