diff --git a/src/rustc/metadata/astencode.rs b/src/rustc/metadata/astencode.rs index d3d8593b654c..d7215fbfcab3 100644 --- a/src/rustc/metadata/astencode.rs +++ b/src/rustc/metadata/astencode.rs @@ -63,7 +63,7 @@ fn encode_inlined_item(ecx: @e::encode_ctxt, let id_range = compute_id_range(ii); ebml_w.wr_tag(c::tag_ast as uint) {|| encode_id_range(ebml_w, id_range); - encode_ast(ebml_w, ii); + encode_ast(ebml_w, simplify_ast(ii)); encode_side_tables_for_ii(ecx, ebml_w, ii); } @@ -326,6 +326,44 @@ fn encode_ast(ebml_w: ebml::writer, item: ast::inlined_item) { } } +// Produces a simplified copy of the AST which does not include things +// that we do not need to or do not want to export. For example, we +// do not include any nested items: if these nested items are to be +// inlined, their AST will be exported separately (this only makes +// sense because, in Rust, nested items are independent except for +// their visibility). +// +// As it happens, trans relies on the fact that we do not export +// nested items, as otherwise it would get confused when translating +// inlined items. +fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item { + fn drop_nested_items(blk: ast::blk_, fld: fold::ast_fold) -> ast::blk_ { + let stmts_sans_items = vec::filter(blk.stmts) {|stmt| + alt stmt.node { + ast::stmt_expr(_, _) | ast::stmt_semi(_, _) | + ast::stmt_decl(@{node: ast::decl_local(_), span: _}, _) { true } + ast::stmt_decl(@{node: ast::decl_item(_), span: _}, _) { false } + } + }; + let blk_sans_items = { stmts: stmts_sans_items with blk }; + fold::noop_fold_block(blk_sans_items, fld) + } + + let fld = fold::make_fold({ + fold_block: fold::wrap(drop_nested_items) + with *fold::default_ast_fold() + }); + + alt ii { + ast::ii_item(i) { + ast::ii_item(fld.fold_item(i)) + } + ast::ii_method(d, m) { + ast::ii_method(d, fld.fold_method(m)) + } + } +} + fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item { let chi_doc = par_doc[c::tag_tree]; let d = serialization::mk_ebml_deserializer(chi_doc); @@ -923,3 +961,26 @@ fn test_more() { } }); } + +#[test] +fn test_simplification() { + let ext_cx = mk_ctxt(); + let item_in = ast::ii_item(#ast(item) { + fn new_int_alist() -> alist { + fn eq_int(&&a: int, &&b: int) -> bool { a == b } + ret {eq_fn: eq_int, mut data: []}; + } + }); + let item_out = simplify_ast(item_in); + let item_exp = ast::ii_item(#ast(item) { + fn new_int_alist() -> alist { + ret {eq_fn: eq_int, mut data: []}; + } + }); + alt (item_out, item_exp) { + (ast::ii_item(item_out), ast::ii_item(item_exp)) { + assert pprust::item_to_str(item_out) == pprust::item_to_str(item_exp); + } + _ { fail; } + } +} \ No newline at end of file diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index b6703a8fe83e..910c6c93ac59 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -2146,18 +2146,31 @@ fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t], fn maybe_instantiate_inline(ccx: crate_ctxt, fn_id: ast::def_id) -> ast::def_id { alt ccx.external.find(fn_id) { - some(some(node_id)) { local_def(node_id) } // Already inline + some(some(node_id)) { + // Already inline + #debug["maybe_instantiate_inline(%s): already inline as node id %d", + ty::item_path_str(ccx.tcx, fn_id), node_id]; + local_def(node_id) + } some(none) { fn_id } // Not inlinable none { // Not seen yet alt csearch::maybe_get_item_ast(ccx.tcx, ccx.maps, fn_id) { none { ccx.external.insert(fn_id, none); fn_id } some(ast::ii_item(item)) { + #debug["maybe_instantiate_inline(%s): inlining to local id %d", + ty::item_path_str(ccx.tcx, fn_id), + item.id]; ccx.external.insert(fn_id, some(item.id)); collect_item(ccx, @mutable none, item); trans_item(ccx, *item); local_def(item.id) } some(ast::ii_method(impl_did, mth)) { + #debug["maybe_instantiate_inline(%s): \ + inlining method of %s to %d", + ty::item_path_str(ccx.tcx, fn_id), + ty::item_path_str(ccx.tcx, impl_did), + mth.id]; ccx.external.insert(fn_id, some(mth.id)); compute_ii_method_info(ccx, impl_did, mth) {|ty, bounds, path| let mth_ty = ty::node_id_to_type(ccx.tcx, mth.id); @@ -3586,7 +3599,7 @@ fn zero_alloca(cx: block, llptr: ValueRef, t: ty::t) } fn trans_stmt(cx: block, s: ast::stmt) -> block { - #debug["trans_expr(%s)", stmt_to_str(s)]; + #debug["trans_stmt(%s)", stmt_to_str(s)]; if (!cx.sess().opts.no_asm_comments) { add_span_comment(cx, s.span, stmt_to_str(s)); @@ -4330,8 +4343,10 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) { let llfndecl = alt ccx.item_ids.find(item.id) { some(llfndecl) { llfndecl } _ { - ccx.sess.span_bug(item.span, - "unbound function item in trans_item"); + ccx.sess.span_bug( + item.span, + #fmt["unbound function item %s in trans_item", + ast_map::path_to_str(*path)]); } }; if decl.purity != ast::crust_fn { diff --git a/src/rustc/syntax/fold.rs b/src/rustc/syntax/fold.rs index d8088e39cb6d..42ac5ca7da62 100644 --- a/src/rustc/syntax/fold.rs +++ b/src/rustc/syntax/fold.rs @@ -11,6 +11,7 @@ export noop_fold_expr; export noop_fold_pat; export noop_fold_mod; export noop_fold_ty; +export noop_fold_block; export wrap; type ast_fold = @mutable a_f; diff --git a/src/test/auxiliary/cci_nested_lib.rs b/src/test/auxiliary/cci_nested_lib.rs new file mode 100644 index 000000000000..9e3169119bcd --- /dev/null +++ b/src/test/auxiliary/cci_nested_lib.rs @@ -0,0 +1,29 @@ +type alist = { eq_fn: fn@(A,A) -> bool, mut data: [(A,B)] }; + +fn alist_add(lst: alist, k: A, v: B) { + lst.data += [(k, v)]; +} + +fn alist_get(lst: alist, k: A) -> B { + let eq_fn = lst.eq_fn; + for pair in lst.data { + let (ki, vi) = pair; // copy req'd for alias analysis + if eq_fn(k, ki) { ret vi; } + } + fail; +} + +#[inline] +fn new_int_alist() -> alist { + fn eq_int(&&a: int, &&b: int) -> bool { a == b } + ret {eq_fn: eq_int, + mut data: []}; +} + +#[inline] +fn new_int_alist_2() -> alist { + #[inline] + fn eq_int(&&a: int, &&b: int) -> bool { a == b } + ret {eq_fn: eq_int, + mut data: []}; +} \ No newline at end of file diff --git a/src/test/run-pass/cci_nested_exe.rs b/src/test/run-pass/cci_nested_exe.rs new file mode 100644 index 000000000000..c258d2d15b67 --- /dev/null +++ b/src/test/run-pass/cci_nested_exe.rs @@ -0,0 +1,21 @@ +// xfail-fast - check-fast doesn't understand aux-build +// aux-build:cci_nested_lib.rs + +use std; +use cci_nested_lib; +import std::io; +import cci_nested_lib::*; + +fn main() { + let lst = new_int_alist(); + alist_add(lst, 22, "hi"); + alist_add(lst, 44, "ho"); + assert alist_get(lst, 22) == "hi"; + assert alist_get(lst, 44) == "ho"; + + let lst = new_int_alist_2(); + alist_add(lst, 22, "hi"); + alist_add(lst, 44, "ho"); + assert alist_get(lst, 22) == "hi"; + assert alist_get(lst, 44) == "ho"; +}