output_type: ty::t,
param_substs: &'a param_substs,
sp: Option<Span>,
- block_arena: &'a TypedArena<Block<'a>>)
+ block_arena: &'a TypedArena<Block<'a>>,
+ handle_items: HandleItemsFlag)
-> FunctionContext<'a> {
param_substs.validate();
block_arena: block_arena,
ccx: ccx,
debug_context: debug_context,
- scopes: RefCell::new(Vec::new())
+ scopes: RefCell::new(Vec::new()),
+ handle_items: handle_items,
};
if has_env {
abi: Abi,
has_env: bool,
is_unboxed_closure: IsUnboxedClosureFlag,
- maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>) {
+ maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>,
+ handle_items: HandleItemsFlag) {
ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
let _icx = push_ctxt("trans_closure");
output_type,
param_substs,
Some(body.span),
- &arena);
+ &arena,
+ handle_items);
let mut bcx = init_function(&fcx, false, output_type);
// cleanup scope for the incoming arguments
llfndecl: ValueRef,
param_substs: ¶m_substs,
id: ast::NodeId,
- attrs: &[ast::Attribute]) {
+ attrs: &[ast::Attribute],
+ handle_items: HandleItemsFlag) {
let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_string(id).to_string());
debug!("trans_fn(param_substs={})", param_substs.repr(ccx.tcx()));
let _icx = push_ctxt("trans_fn");
abi,
false,
NotUnboxedClosure,
- |bcx| bcx);
+ |bcx| bcx,
+ handle_items);
}
pub fn trans_enum_variant(ccx: &CrateContext,
let arena = TypedArena::new();
let fcx = new_fn_ctxt(ccx, llfndecl, ctor_id, false, result_ty,
- param_substs, None, &arena);
+ param_substs, None, &arena, TranslateItems);
let bcx = init_function(&fcx, false, result_ty);
let arg_tys = ty::ty_fn_args(ctor_ty);
llfn,
¶m_substs::empty(),
item.id,
- item.attrs.as_slice());
+ item.attrs.as_slice(),
+ TranslateItems);
} else {
// Be sure to travel more than just one layer deep to catch nested
// items in blocks and such.
return_type,
&empty_param_substs,
None,
- &block_arena);
+ &block_arena,
+ TranslateItems);
let mut bcx = init_function(&fcx, false, return_type);
// Create the substituted versions of the self type.
ty::ty_fn_abi(fty),
true,
NotUnboxedClosure,
- |bcx| load_environment(bcx, cdata_ty, &freevars, store));
+ |bcx| load_environment(bcx, cdata_ty, &freevars, store),
+ bcx.fcx.handle_items);
fill_fn_pair(bcx, dest_addr, llfn, llbox);
bcx
}
ty::ty_fn_abi(function_type),
true,
IsUnboxedClosure,
- |bcx| load_unboxed_closure_environment(bcx, freevars_ptr));
+ |bcx| load_unboxed_closure_environment(bcx, freevars_ptr),
+ bcx.fcx.handle_items);
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size unboxed closure (in which case dest will be
let arena = TypedArena::new();
let empty_param_substs = param_substs::empty();
let fcx = new_fn_ctxt(ccx, llfn, -1, true, f.sig.output,
- &empty_param_substs, None, &arena);
+ &empty_param_substs, None, &arena, TranslateItems);
let bcx = init_function(&fcx, true, f.sig.output);
let args = create_datums_for_fn_args(&fcx,
pub type RvalueDatum = datum::Datum<datum::Rvalue>;
pub type LvalueDatum = datum::Datum<datum::Lvalue>;
+#[deriving(Clone, Eq, PartialEq)]
+pub enum HandleItemsFlag {
+ IgnoreItems,
+ TranslateItems,
+}
+
// Function context. Every LLVM function we create will have one of
// these.
pub struct FunctionContext<'a> {
// Cleanup scopes.
pub scopes: RefCell<Vec<cleanup::CleanupScope<'a>> >,
+
+ // How to handle items encountered during translation of this function.
+ pub handle_items: HandleItemsFlag,
}
impl<'a> FunctionContext<'a> {
debuginfo::create_local_var_metadata(bcx, &**local);
}
}
- ast::DeclItem(ref i) => trans_item(cx.fcx.ccx, &**i)
+ ast::DeclItem(ref i) => {
+ match fcx.handle_items {
+ TranslateItems => trans_item(cx.fcx.ccx, &**i),
+ IgnoreItems => {}
+ }
+ }
}
}
ast::StmtMac(..) => cx.tcx().sess.bug("unexpanded macro")
let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
base::set_llvm_fn_attrs(attrs, llfn);
- base::trans_fn(ccx, decl, body, llfn, ¶m_substs::empty(), id, []);
+ base::trans_fn(ccx, decl, body, llfn, ¶m_substs::empty(), id, [],
+ TranslateItems);
llfn
}
let arena = TypedArena::new();
let empty_param_substs = param_substs::empty();
let fcx = new_fn_ctxt(ccx, llfn, -1, false, ty::mk_nil(),
- &empty_param_substs, None, &arena);
+ &empty_param_substs, None, &arena, TranslateItems);
let bcx = init_function(&fcx, false, ty::mk_nil());
if unparameterized {
let llfn = get_item_val(ccx, mth.id);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), llfn,
- ¶m_substs::empty(), mth.id, []);
+ ¶m_substs::empty(), mth.id, [], TranslateItems);
}
local_def(mth.id)
}
llfn,
¶m_substs::empty(),
method.id,
- []);
+ [],
+ TranslateItems);
} else {
let mut v = TransItemVisitor{ ccx: ccx };
visit::walk_method_helper(&mut v, &**method, ());
} => {
let d = mk_lldecl();
set_llvm_fn_attrs(i.attrs.as_slice(), d);
- trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, []);
+ trans_fn(ccx, &**decl, &**body, d, &psubsts, fn_id.node, [],
+ IgnoreItems);
d
}
_ => {
ast_map::NodeMethod(mth) => {
let d = mk_lldecl();
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
- trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, &psubsts, mth.id, []);
+ trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d, &psubsts, mth.id, [],
+ IgnoreItems);
d
}
ast_map::NodeTraitMethod(method) => {
let d = mk_lldecl();
set_llvm_fn_attrs(mth.attrs.as_slice(), d);
trans_fn(ccx, &*mth.pe_fn_decl(), &*mth.pe_body(), d,
- &psubsts, mth.id, []);
+ &psubsts, mth.id, [], IgnoreItems);
d
}
_ => {
let empty_param_substs = param_substs::empty();
let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
ty::mk_u64(), &empty_param_substs,
- None, &arena);
+ None, &arena, TranslateItems);
let bcx = init_function(&fcx, false, ty::mk_u64());
// we know the return type of llfdecl is an int here, so
--- /dev/null
+-include ../tools.mk
+
+# Test to make sure that inner functions within a polymorphic outer function
+# don't get re-translated when the outer function is monomorphized. The test
+# code monomorphizes the outer function several times, but the magic constant
+# `8675309` used in the inner function should appear only once in the generated
+# IR.
+
+all:
+ $(RUSTC) foo.rs --emit=ir
+ [ "$$(grep -c 8675309 "$(TMPDIR)/foo.ll")" -eq "1" ]
--- /dev/null
+// 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.
+
+fn outer<T>() {
+ #[allow(dead_code)]
+ fn inner() -> uint {
+ 8675309
+ }
+}
+
+fn main() {
+ outer::<int>();
+ outer::<uint>();
+}