Skip to content

Commit 2577bd9

Browse files
committed
rustc: Don't assume that all crates with the same name are the same
1 parent d13c0c7 commit 2577bd9

File tree

6 files changed

+113
-21
lines changed

6 files changed

+113
-21
lines changed

src/rustc/metadata/creader.rs

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export list_file_metadata;
2020
// libraries necessary for later resolving, typechecking, linking, etc.
2121
fn read_crates(sess: session::session, crate: ast::crate) {
2222
let e = @{sess: sess,
23-
crate_cache: std::map::str_hash::<int>(),
23+
mut crate_cache: [],
2424
mut next_crate_num: 1};
2525
let v =
2626
visit::mk_simple_visitor(@{visit_view_item:
@@ -31,7 +31,7 @@ fn read_crates(sess: session::session, crate: ast::crate) {
3131
}
3232

3333
type env = @{sess: session::session,
34-
crate_cache: hashmap<str, int>,
34+
mut crate_cache: [(int, @[@ast::meta_item])],
3535
mut next_crate_num: ast::crate_num};
3636

3737
fn visit_view_item(e: env, i: @ast::view_item) {
@@ -100,21 +100,26 @@ fn list_file_metadata(sess: session::session, path: str, out: io::writer) {
100100
}
101101
}
102102

103-
fn metadata_matches(crate_data: @[u8], metas: [@ast::meta_item]) -> bool {
103+
fn crate_matches(crate_data: @[u8], metas: [@ast::meta_item]) -> bool {
104104
let attrs = decoder::get_crate_attributes(crate_data);
105105
let linkage_metas = attr::find_linkage_metas(attrs);
106+
metadata_matches(linkage_metas, metas)
107+
}
108+
109+
fn metadata_matches(extern_metas: [@ast::meta_item],
110+
local_metas: [@ast::meta_item]) -> bool {
106111

107112
#debug("matching %u metadata requirements against %u items",
108-
vec::len(metas), vec::len(linkage_metas));
113+
vec::len(local_metas), vec::len(extern_metas));
109114

110115
#debug("crate metadata:");
111-
for have: @ast::meta_item in linkage_metas {
116+
for have: @ast::meta_item in extern_metas {
112117
#debug(" %s", pprust::meta_item_to_str(*have));
113118
}
114119

115-
for needed: @ast::meta_item in metas {
120+
for needed: @ast::meta_item in local_metas {
116121
#debug("looking for %s", pprust::meta_item_to_str(*needed));
117-
if !attr::contains(linkage_metas, needed) {
122+
if !attr::contains(extern_metas, needed) {
118123
#debug("missing %s", pprust::meta_item_to_str(*needed));
119124
ret false;
120125
}
@@ -133,7 +138,7 @@ fn default_native_lib_naming(sess: session::session, static: bool) ->
133138
}
134139
}
135140

136-
fn find_library_crate(sess: session::session, ident: ast::ident,
141+
fn find_library_crate(sess: session::session,
137142
metas: [@ast::meta_item])
138143
-> option<{ident: str, data: @[u8]}> {
139144

@@ -149,10 +154,10 @@ fn find_library_crate(sess: session::session, ident: ast::ident,
149154
some(n) { n }
150155
// FIXME: Probably want a warning here since the user
151156
// is using the wrong type of meta item
152-
_ { ident }
157+
_ { fail }
153158
}
154159
}
155-
none { ident }
160+
none { fail }
156161
}
157162
};
158163

@@ -186,7 +191,7 @@ fn find_library_crate_aux(sess: session::session,
186191
#debug("%s is a candidate", path);
187192
alt get_metadata_section(sess, path) {
188193
option::some(cvec) {
189-
if !metadata_matches(cvec, metas) {
194+
if !crate_matches(cvec, metas) {
190195
#debug("skipping %s, metadata doesn't match", path);
191196
option::none
192197
} else {
@@ -230,31 +235,55 @@ fn get_metadata_section(sess: session::session,
230235
ret option::none::<@[u8]>;
231236
}
232237

233-
fn load_library_crate(sess: session::session, span: span, ident: ast::ident,
238+
fn load_library_crate(sess: session::session, ident: ast::ident, span: span,
234239
metas: [@ast::meta_item])
235240
-> {ident: str, data: @[u8]} {
236241

237242

238-
alt find_library_crate(sess, ident, metas) {
243+
alt find_library_crate(sess, metas) {
239244
some(t) { ret t; }
240245
none {
241246
sess.span_fatal(span, #fmt["can't find crate for '%s'", ident]);
242247
}
243248
}
244249
}
245250

251+
fn metas_with_ident(ident: ast::ident,
252+
metas: [@ast::meta_item]) -> [@ast::meta_item] {
253+
let name_items = attr::find_meta_items_by_name(metas, "name");
254+
if name_items.is_empty() {
255+
metas + [attr::mk_name_value_item_str("name", ident)]
256+
} else {
257+
metas
258+
}
259+
}
260+
261+
fn existing_match(e: env, metas: [@ast::meta_item]) -> option<int> {
262+
let maybe_entry = e.crate_cache.find {|c|
263+
metadata_matches(*tuple::second(c), metas)
264+
};
265+
266+
maybe_entry.map {|c| tuple::first(c) }
267+
}
268+
246269
fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
247270
span: span) -> ast::crate_num {
248-
if !e.crate_cache.contains_key(ident) {
271+
let metas = metas_with_ident(ident, metas);
272+
273+
alt existing_match(e, metas) {
274+
none {
249275
let cinfo =
250-
load_library_crate(e.sess, span, ident, metas);
276+
load_library_crate(e.sess, ident, span, metas);
251277

252278
let cfilename = cinfo.ident;
253279
let cdata = cinfo.data;
254280

281+
let attrs = decoder::get_crate_attributes(cdata);
282+
let linkage_metas = attr::find_linkage_metas(attrs);
283+
255284
// Claim this crate number and cache it
256285
let cnum = e.next_crate_num;
257-
e.crate_cache.insert(ident, cnum);
286+
e.crate_cache += [(cnum, @linkage_metas)];
258287
e.next_crate_num += 1;
259288

260289
// Now resolve the crates referenced by this crate
@@ -267,7 +296,11 @@ fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
267296
cstore::set_crate_data(cstore, cnum, cmeta);
268297
cstore::add_used_crate_file(cstore, cfilename);
269298
ret cnum;
270-
} else { ret e.crate_cache.get(ident); }
299+
}
300+
some(cnum) {
301+
ret cnum;
302+
}
303+
}
271304
}
272305

273306
// Go through the crate metadata and load any crates that it references
@@ -279,19 +312,24 @@ fn resolve_crate_deps(e: env, cdata: @[u8]) -> cstore::cnum_map {
279312
for dep: decoder::crate_dep in decoder::get_crate_deps(cdata) {
280313
let extrn_cnum = dep.cnum;
281314
let cname = dep.ident;
315+
// FIXME: We really need to know the linkage metas of our transitive
316+
// dependencies in order to resolve them correctly.
317+
let cmetas = [];
282318
#debug("resolving dep %s", cname);
283-
if e.crate_cache.contains_key(cname) {
319+
alt existing_match(e, metas_with_ident(cname, cmetas)) {
320+
some(local_cnum) {
284321
#debug("already have it");
285322
// We've already seen this crate
286-
let local_cnum = e.crate_cache.get(cname);
287323
cnum_map.insert(extrn_cnum, local_cnum);
288-
} else {
324+
}
325+
none {
289326
#debug("need to load it");
290327
// This is a new one so we've got to load it
291328
// FIXME: Need better error reporting than just a bogus span
292329
let fake_span = ast_util::dummy_sp();
293-
let local_cnum = resolve_crate(e, cname, [], fake_span);
330+
let local_cnum = resolve_crate(e, cname, cmetas, fake_span);
294331
cnum_map.insert(extrn_cnum, local_cnum);
332+
}
295333
}
296334
}
297335
ret cnum_map;

src/test/auxiliary/crateresolve-1.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[link(name = "crateresolve",
2+
vers = "0.1")];
3+
4+
#[crate_type = "lib"];
5+
6+
fn f() -> int { 10 }

src/test/auxiliary/crateresolve-2.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[link(name = "crateresolve",
2+
vers = "0.2")];
3+
4+
#[crate_type = "lib"];
5+
6+
fn f() -> int { 20 }

src/test/auxiliary/crateresolve-3.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#[link(name = "crateresolve",
2+
vers = "0.3")];
3+
4+
#[crate_type = "lib"];
5+
6+
fn f() -> int { 30 }

src/test/run-pass/crateresolve.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// xfail-fast
2+
// aux-build:crateresolve-1.rs
3+
// aux-build:crateresolve-2.rs
4+
// aux-build:crateresolve-3.rs
5+
6+
use crateresolve(vers = "0.2");
7+
8+
fn main() {
9+
assert crateresolve::f() == 20;
10+
}

src/test/run-pass/crateresolve2.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// xfail-fast
2+
// xfail-test
3+
// aux-build:crateresolve-1.rs
4+
// aux-build:crateresolve-2.rs
5+
// aux-build:crateresolve-3.rs
6+
7+
mod a {
8+
use crateresolve(vers = "0.1");
9+
fn f() { assert crateresolve::f() == 10; }
10+
}
11+
12+
mod b {
13+
use crateresolve(vers = "0.2");
14+
fn f() { assert crateresolve::f() == 20; }
15+
}
16+
17+
mod c {
18+
use crateresolve(vers = "0.3");
19+
fn f() { assert crateresolve::f() == 30; }
20+
}
21+
22+
fn main() {
23+
a::f();
24+
b::f();
25+
c::f();
26+
}

0 commit comments

Comments
 (0)