Fix #1941: inlining of items that themselves contain nested items
The fix is to drop nested items from the encoded AST. Nested items may themselves be inlined, but that is an independent question.
This commit is contained in:
parent
c9375fed8d
commit
2bfed908e3
@ -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<B: copy>() -> alist<int, B> {
|
||||
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<B: copy>() -> alist<int, B> {
|
||||
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; }
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
29
src/test/auxiliary/cci_nested_lib.rs
Normal file
29
src/test/auxiliary/cci_nested_lib.rs
Normal file
@ -0,0 +1,29 @@
|
||||
type alist<A,B> = { eq_fn: fn@(A,A) -> bool, mut data: [(A,B)] };
|
||||
|
||||
fn alist_add<A: copy, B: copy>(lst: alist<A,B>, k: A, v: B) {
|
||||
lst.data += [(k, v)];
|
||||
}
|
||||
|
||||
fn alist_get<A: copy, B: copy>(lst: alist<A,B>, 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<B: copy>() -> alist<int, B> {
|
||||
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
|
||||
ret {eq_fn: eq_int,
|
||||
mut data: []};
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn new_int_alist_2<B: copy>() -> alist<int, B> {
|
||||
#[inline]
|
||||
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
|
||||
ret {eq_fn: eq_int,
|
||||
mut data: []};
|
||||
}
|
21
src/test/run-pass/cci_nested_exe.rs
Normal file
21
src/test/run-pass/cci_nested_exe.rs
Normal file
@ -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";
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user