From 5dd1677b0a8044097937d507c0f32dbbace80c0a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 5 Apr 2012 23:42:32 -0700 Subject: [PATCH] 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. --- src/rustc/metadata/creader.rs | 90 ++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs index 44bc44913811..708c4a1ab5c1 100644 --- a/src/rustc/metadata/creader.rs +++ b/src/rustc/metadata/creader.rs @@ -28,10 +28,50 @@ fn read_crates(sess: session::session, crate: ast::crate) { visit_item: bind visit_item(e, _) with *visit::default_simple_visitor()}); visit::visit_crate(crate, (), v); + warn_if_multiple_versions(sess, copy e.crate_cache); +} + +type cache_entry = { + cnum: int, + span: span, + metas: @[@ast::meta_item] +}; + +fn warn_if_multiple_versions(sess: session::session, + crate_cache: [cache_entry]) { + import either::*; + + if crate_cache.is_not_empty() { + let name = crate_name_from_metas(*crate_cache.last().metas); + let {lefts: matches, rights: non_matches} = + partition(crate_cache.map {|entry| + let othername = crate_name_from_metas(*entry.metas); + if name == othername { + left(entry) + } else { + right(entry) + } + }); + + assert matches.is_not_empty(); + + if matches.len() != 1u { + sess.warn(#fmt("using multiple versions of crate `%s`", name)); + for matches.each {|match| + sess.span_note(match.span, "used here"); + let attrs = [ + attr::mk_attr(attr::mk_list_item("link", *match.metas)) + ]; + note_linkage_attrs(sess, attrs); + } + } + + warn_if_multiple_versions(sess, non_matches); + } } type env = @{sess: session::session, - mut crate_cache: [(int, @[@ast::meta_item])], + mut crate_cache: [cache_entry], mut next_crate_num: ast::crate_num}; fn visit_view_item(e: env, i: @ast::view_item) { @@ -138,28 +178,28 @@ fn default_native_lib_naming(sess: session::session, static: bool) -> } } +fn crate_name_from_metas(metas: [@ast::meta_item]) -> str { + let name_items = attr::find_meta_items_by_name(metas, "name"); + alt vec::last_opt(name_items) { + some(i) { + alt attr::get_meta_item_value_str(i) { + some(n) { n } + // FIXME: Probably want a warning here since the user + // is using the wrong type of meta item + _ { fail } + } + } + none { fail "expected to find the crate name" } + } +} + fn find_library_crate(sess: session::session, span: span, metas: [@ast::meta_item]) -> option<{ident: str, data: @[u8]}> { attr::require_unique_names(sess.diagnostic(), metas); let metas = metas; - - let crate_name = - { - let name_items = attr::find_meta_items_by_name(metas, "name"); - alt vec::last_opt(name_items) { - some(i) { - alt attr::get_meta_item_value_str(i) { - some(n) { n } - // FIXME: Probably want a warning here since the user - // is using the wrong type of meta item - _ { fail } - } - } - none { fail } - } - }; + let crate_name = crate_name_from_metas(metas); let nn = default_native_lib_naming(sess, sess.opts.static); let x = @@ -221,15 +261,19 @@ fn find_library_crate_aux(sess: session::session, for matches.each {|match| sess.note(#fmt("path: %s", match.ident)); let attrs = decoder::get_crate_attributes(match.data); - for attr::find_linkage_attrs(attrs).each {|attr| - sess.note(#fmt("meta: %s", pprust::attr_to_str(attr))); - } + note_linkage_attrs(sess, attrs); } sess.abort_if_errors(); none } } +fn note_linkage_attrs(sess: session::session, attrs: [ast::attribute]) { + for attr::find_linkage_attrs(attrs).each {|attr| + sess.note(#fmt("meta: %s", pprust::attr_to_str(attr))); + } +} + fn get_metadata_section(sess: session::session, filename: str) -> option<@[u8]> unsafe { let mb = str::as_c_str(filename, {|buf| @@ -282,10 +326,10 @@ fn metas_with_ident(ident: ast::ident, fn existing_match(e: env, metas: [@ast::meta_item]) -> option { let maybe_entry = e.crate_cache.find {|c| - metadata_matches(*tuple::second(c), metas) + metadata_matches(*c.metas, metas) }; - maybe_entry.map {|c| tuple::first(c) } + maybe_entry.map {|c| c.cnum } } 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], // Claim this crate number and cache it let cnum = e.next_crate_num; - e.crate_cache += [(cnum, @linkage_metas)]; + e.crate_cache += [{cnum: cnum, span: span, metas: @linkage_metas}]; e.next_crate_num += 1; // Now resolve the crates referenced by this crate