Skip to content

Commit 5dd1677

Browse files
committed
rustc: Warn when linking to multiple versions of the same crate
This is not something most people want to be doing and may be a source of error.
1 parent 110e02c commit 5dd1677

File tree

1 file changed

+67
-23
lines changed

1 file changed

+67
-23
lines changed

src/rustc/metadata/creader.rs

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,50 @@ fn read_crates(sess: session::session, crate: ast::crate) {
2828
visit_item: bind visit_item(e, _)
2929
with *visit::default_simple_visitor()});
3030
visit::visit_crate(crate, (), v);
31+
warn_if_multiple_versions(sess, copy e.crate_cache);
32+
}
33+
34+
type cache_entry = {
35+
cnum: int,
36+
span: span,
37+
metas: @[@ast::meta_item]
38+
};
39+
40+
fn warn_if_multiple_versions(sess: session::session,
41+
crate_cache: [cache_entry]) {
42+
import either::*;
43+
44+
if crate_cache.is_not_empty() {
45+
let name = crate_name_from_metas(*crate_cache.last().metas);
46+
let {lefts: matches, rights: non_matches} =
47+
partition(crate_cache.map {|entry|
48+
let othername = crate_name_from_metas(*entry.metas);
49+
if name == othername {
50+
left(entry)
51+
} else {
52+
right(entry)
53+
}
54+
});
55+
56+
assert matches.is_not_empty();
57+
58+
if matches.len() != 1u {
59+
sess.warn(#fmt("using multiple versions of crate `%s`", name));
60+
for matches.each {|match|
61+
sess.span_note(match.span, "used here");
62+
let attrs = [
63+
attr::mk_attr(attr::mk_list_item("link", *match.metas))
64+
];
65+
note_linkage_attrs(sess, attrs);
66+
}
67+
}
68+
69+
warn_if_multiple_versions(sess, non_matches);
70+
}
3171
}
3272

3373
type env = @{sess: session::session,
34-
mut crate_cache: [(int, @[@ast::meta_item])],
74+
mut crate_cache: [cache_entry],
3575
mut next_crate_num: ast::crate_num};
3676

3777
fn visit_view_item(e: env, i: @ast::view_item) {
@@ -138,28 +178,28 @@ fn default_native_lib_naming(sess: session::session, static: bool) ->
138178
}
139179
}
140180

181+
fn crate_name_from_metas(metas: [@ast::meta_item]) -> str {
182+
let name_items = attr::find_meta_items_by_name(metas, "name");
183+
alt vec::last_opt(name_items) {
184+
some(i) {
185+
alt attr::get_meta_item_value_str(i) {
186+
some(n) { n }
187+
// FIXME: Probably want a warning here since the user
188+
// is using the wrong type of meta item
189+
_ { fail }
190+
}
191+
}
192+
none { fail "expected to find the crate name" }
193+
}
194+
}
195+
141196
fn find_library_crate(sess: session::session, span: span,
142197
metas: [@ast::meta_item])
143198
-> option<{ident: str, data: @[u8]}> {
144199

145200
attr::require_unique_names(sess.diagnostic(), metas);
146201
let metas = metas;
147-
148-
let crate_name =
149-
{
150-
let name_items = attr::find_meta_items_by_name(metas, "name");
151-
alt vec::last_opt(name_items) {
152-
some(i) {
153-
alt attr::get_meta_item_value_str(i) {
154-
some(n) { n }
155-
// FIXME: Probably want a warning here since the user
156-
// is using the wrong type of meta item
157-
_ { fail }
158-
}
159-
}
160-
none { fail }
161-
}
162-
};
202+
let crate_name = crate_name_from_metas(metas);
163203

164204
let nn = default_native_lib_naming(sess, sess.opts.static);
165205
let x =
@@ -221,15 +261,19 @@ fn find_library_crate_aux(sess: session::session,
221261
for matches.each {|match|
222262
sess.note(#fmt("path: %s", match.ident));
223263
let attrs = decoder::get_crate_attributes(match.data);
224-
for attr::find_linkage_attrs(attrs).each {|attr|
225-
sess.note(#fmt("meta: %s", pprust::attr_to_str(attr)));
226-
}
264+
note_linkage_attrs(sess, attrs);
227265
}
228266
sess.abort_if_errors();
229267
none
230268
}
231269
}
232270

271+
fn note_linkage_attrs(sess: session::session, attrs: [ast::attribute]) {
272+
for attr::find_linkage_attrs(attrs).each {|attr|
273+
sess.note(#fmt("meta: %s", pprust::attr_to_str(attr)));
274+
}
275+
}
276+
233277
fn get_metadata_section(sess: session::session,
234278
filename: str) -> option<@[u8]> unsafe {
235279
let mb = str::as_c_str(filename, {|buf|
@@ -282,10 +326,10 @@ fn metas_with_ident(ident: ast::ident,
282326

283327
fn existing_match(e: env, metas: [@ast::meta_item]) -> option<int> {
284328
let maybe_entry = e.crate_cache.find {|c|
285-
metadata_matches(*tuple::second(c), metas)
329+
metadata_matches(*c.metas, metas)
286330
};
287331

288-
maybe_entry.map {|c| tuple::first(c) }
332+
maybe_entry.map {|c| c.cnum }
289333
}
290334

291335
fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
@@ -305,7 +349,7 @@ fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item],
305349

306350
// Claim this crate number and cache it
307351
let cnum = e.next_crate_num;
308-
e.crate_cache += [(cnum, @linkage_metas)];
352+
e.crate_cache += [{cnum: cnum, span: span, metas: @linkage_metas}];
309353
e.next_crate_num += 1;
310354

311355
// Now resolve the crates referenced by this crate

0 commit comments

Comments
 (0)