Skip to content

Commit 2bfed90

Browse files
committed
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.
1 parent c9375fe commit 2bfed90

File tree

5 files changed

+132
-5
lines changed

5 files changed

+132
-5
lines changed

src/rustc/metadata/astencode.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn encode_inlined_item(ecx: @e::encode_ctxt,
6363
let id_range = compute_id_range(ii);
6464
ebml_w.wr_tag(c::tag_ast as uint) {||
6565
encode_id_range(ebml_w, id_range);
66-
encode_ast(ebml_w, ii);
66+
encode_ast(ebml_w, simplify_ast(ii));
6767
encode_side_tables_for_ii(ecx, ebml_w, ii);
6868
}
6969

@@ -326,6 +326,44 @@ fn encode_ast(ebml_w: ebml::writer, item: ast::inlined_item) {
326326
}
327327
}
328328

329+
// Produces a simplified copy of the AST which does not include things
330+
// that we do not need to or do not want to export. For example, we
331+
// do not include any nested items: if these nested items are to be
332+
// inlined, their AST will be exported separately (this only makes
333+
// sense because, in Rust, nested items are independent except for
334+
// their visibility).
335+
//
336+
// As it happens, trans relies on the fact that we do not export
337+
// nested items, as otherwise it would get confused when translating
338+
// inlined items.
339+
fn simplify_ast(ii: ast::inlined_item) -> ast::inlined_item {
340+
fn drop_nested_items(blk: ast::blk_, fld: fold::ast_fold) -> ast::blk_ {
341+
let stmts_sans_items = vec::filter(blk.stmts) {|stmt|
342+
alt stmt.node {
343+
ast::stmt_expr(_, _) | ast::stmt_semi(_, _) |
344+
ast::stmt_decl(@{node: ast::decl_local(_), span: _}, _) { true }
345+
ast::stmt_decl(@{node: ast::decl_item(_), span: _}, _) { false }
346+
}
347+
};
348+
let blk_sans_items = { stmts: stmts_sans_items with blk };
349+
fold::noop_fold_block(blk_sans_items, fld)
350+
}
351+
352+
let fld = fold::make_fold({
353+
fold_block: fold::wrap(drop_nested_items)
354+
with *fold::default_ast_fold()
355+
});
356+
357+
alt ii {
358+
ast::ii_item(i) {
359+
ast::ii_item(fld.fold_item(i))
360+
}
361+
ast::ii_method(d, m) {
362+
ast::ii_method(d, fld.fold_method(m))
363+
}
364+
}
365+
}
366+
329367
fn decode_ast(par_doc: ebml::doc) -> ast::inlined_item {
330368
let chi_doc = par_doc[c::tag_tree];
331369
let d = serialization::mk_ebml_deserializer(chi_doc);
@@ -923,3 +961,26 @@ fn test_more() {
923961
}
924962
});
925963
}
964+
965+
#[test]
966+
fn test_simplification() {
967+
let ext_cx = mk_ctxt();
968+
let item_in = ast::ii_item(#ast(item) {
969+
fn new_int_alist<B: copy>() -> alist<int, B> {
970+
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
971+
ret {eq_fn: eq_int, mut data: []};
972+
}
973+
});
974+
let item_out = simplify_ast(item_in);
975+
let item_exp = ast::ii_item(#ast(item) {
976+
fn new_int_alist<B: copy>() -> alist<int, B> {
977+
ret {eq_fn: eq_int, mut data: []};
978+
}
979+
});
980+
alt (item_out, item_exp) {
981+
(ast::ii_item(item_out), ast::ii_item(item_exp)) {
982+
assert pprust::item_to_str(item_out) == pprust::item_to_str(item_exp);
983+
}
984+
_ { fail; }
985+
}
986+
}

src/rustc/middle/trans/base.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,18 +2146,31 @@ fn monomorphic_fn(ccx: crate_ctxt, fn_id: ast::def_id, substs: [ty::t],
21462146
fn maybe_instantiate_inline(ccx: crate_ctxt, fn_id: ast::def_id)
21472147
-> ast::def_id {
21482148
alt ccx.external.find(fn_id) {
2149-
some(some(node_id)) { local_def(node_id) } // Already inline
2149+
some(some(node_id)) {
2150+
// Already inline
2151+
#debug["maybe_instantiate_inline(%s): already inline as node id %d",
2152+
ty::item_path_str(ccx.tcx, fn_id), node_id];
2153+
local_def(node_id)
2154+
}
21502155
some(none) { fn_id } // Not inlinable
21512156
none { // Not seen yet
21522157
alt csearch::maybe_get_item_ast(ccx.tcx, ccx.maps, fn_id) {
21532158
none { ccx.external.insert(fn_id, none); fn_id }
21542159
some(ast::ii_item(item)) {
2160+
#debug["maybe_instantiate_inline(%s): inlining to local id %d",
2161+
ty::item_path_str(ccx.tcx, fn_id),
2162+
item.id];
21552163
ccx.external.insert(fn_id, some(item.id));
21562164
collect_item(ccx, @mutable none, item);
21572165
trans_item(ccx, *item);
21582166
local_def(item.id)
21592167
}
21602168
some(ast::ii_method(impl_did, mth)) {
2169+
#debug["maybe_instantiate_inline(%s): \
2170+
inlining method of %s to %d",
2171+
ty::item_path_str(ccx.tcx, fn_id),
2172+
ty::item_path_str(ccx.tcx, impl_did),
2173+
mth.id];
21612174
ccx.external.insert(fn_id, some(mth.id));
21622175
compute_ii_method_info(ccx, impl_did, mth) {|ty, bounds, path|
21632176
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)
35863599
}
35873600

35883601
fn trans_stmt(cx: block, s: ast::stmt) -> block {
3589-
#debug["trans_expr(%s)", stmt_to_str(s)];
3602+
#debug["trans_stmt(%s)", stmt_to_str(s)];
35903603

35913604
if (!cx.sess().opts.no_asm_comments) {
35923605
add_span_comment(cx, s.span, stmt_to_str(s));
@@ -4330,8 +4343,10 @@ fn trans_item(ccx: crate_ctxt, item: ast::item) {
43304343
let llfndecl = alt ccx.item_ids.find(item.id) {
43314344
some(llfndecl) { llfndecl }
43324345
_ {
4333-
ccx.sess.span_bug(item.span,
4334-
"unbound function item in trans_item");
4346+
ccx.sess.span_bug(
4347+
item.span,
4348+
#fmt["unbound function item %s in trans_item",
4349+
ast_map::path_to_str(*path)]);
43354350
}
43364351
};
43374352
if decl.purity != ast::crust_fn {

src/rustc/syntax/fold.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export noop_fold_expr;
1111
export noop_fold_pat;
1212
export noop_fold_mod;
1313
export noop_fold_ty;
14+
export noop_fold_block;
1415
export wrap;
1516

1617
type ast_fold = @mutable a_f;

src/test/auxiliary/cci_nested_lib.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
type alist<A,B> = { eq_fn: fn@(A,A) -> bool, mut data: [(A,B)] };
2+
3+
fn alist_add<A: copy, B: copy>(lst: alist<A,B>, k: A, v: B) {
4+
lst.data += [(k, v)];
5+
}
6+
7+
fn alist_get<A: copy, B: copy>(lst: alist<A,B>, k: A) -> B {
8+
let eq_fn = lst.eq_fn;
9+
for pair in lst.data {
10+
let (ki, vi) = pair; // copy req'd for alias analysis
11+
if eq_fn(k, ki) { ret vi; }
12+
}
13+
fail;
14+
}
15+
16+
#[inline]
17+
fn new_int_alist<B: copy>() -> alist<int, B> {
18+
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
19+
ret {eq_fn: eq_int,
20+
mut data: []};
21+
}
22+
23+
#[inline]
24+
fn new_int_alist_2<B: copy>() -> alist<int, B> {
25+
#[inline]
26+
fn eq_int(&&a: int, &&b: int) -> bool { a == b }
27+
ret {eq_fn: eq_int,
28+
mut data: []};
29+
}

src/test/run-pass/cci_nested_exe.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// xfail-fast - check-fast doesn't understand aux-build
2+
// aux-build:cci_nested_lib.rs
3+
4+
use std;
5+
use cci_nested_lib;
6+
import std::io;
7+
import cci_nested_lib::*;
8+
9+
fn main() {
10+
let lst = new_int_alist();
11+
alist_add(lst, 22, "hi");
12+
alist_add(lst, 44, "ho");
13+
assert alist_get(lst, 22) == "hi";
14+
assert alist_get(lst, 44) == "ho";
15+
16+
let lst = new_int_alist_2();
17+
alist_add(lst, 22, "hi");
18+
alist_add(lst, 44, "ho");
19+
assert alist_get(lst, 22) == "hi";
20+
assert alist_get(lst, 44) == "ho";
21+
}

0 commit comments

Comments
 (0)