Make the compiler emit an error if the crate graph contains two crates with the same crate-name and crate-salt but different SVHs.

This commit is contained in:
Michael Woerister 2016-02-26 16:25:25 -05:00 committed by Niko Matsakis
parent fafdfa8bdc
commit 2eebb7b605
22 changed files with 103 additions and 24 deletions

View file

@ -526,11 +526,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
let macros = time(time_passes,
"macro loading",
|| macro_import::read_macro_defs(sess, &cstore, &krate));
|| macro_import::read_macro_defs(sess, &cstore, &krate, crate_name));
let mut addl_plugins = Some(addl_plugins);
let registrars = time(time_passes, "plugin loading", || {
plugin::load::load_plugins(sess, &cstore, &krate, addl_plugins.take().unwrap())
plugin::load::load_plugins(sess,
&cstore,
&krate,
crate_name,
addl_plugins.take().unwrap())
});
let mut registry = Registry::new(sess, &krate);
@ -755,7 +759,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
time(time_passes,
"external crate/lib resolution",
|| LocalCrateReader::new(sess, cstore, &hir_map).read_crates());
|| LocalCrateReader::new(sess, cstore, &hir_map, name).read_crates());
let lang_items = time(time_passes, "language item collection", || {
sess.track_errors(|| {

View file

@ -55,6 +55,7 @@ pub struct CrateReader<'a> {
cstore: &'a CStore,
next_crate_num: ast::CrateNum,
foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
local_crate_name: String,
}
impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> {
@ -146,12 +147,15 @@ impl PMDSource {
}
impl<'a> CrateReader<'a> {
pub fn new(sess: &'a Session, cstore: &'a CStore) -> CrateReader<'a> {
pub fn new(sess: &'a Session,
cstore: &'a CStore,
local_crate_name: &str) -> CrateReader<'a> {
CrateReader {
sess: sess,
cstore: cstore,
next_crate_num: cstore.next_crate_num(),
foreign_item_map: FnvHashMap(),
local_crate_name: local_crate_name.to_owned(),
}
}
@ -272,6 +276,38 @@ impl<'a> CrateReader<'a> {
}
}
fn verify_no_symbol_conflicts(&self,
crate_name: &str,
span: Span,
metadata: &MetadataBlob) {
let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice());
// Check for (potential) conflicts with the local crate
if self.local_crate_name == crate_name &&
&self.sess.crate_disambiguator.borrow()[..] == disambiguator {
span_fatal!(self.sess, span, E0519,
"the current crate is indistinguishable from one of its \
dependencies: it has the same crate-name `{}` and was \
compiled with the same `-C metadata` arguments. This \
will result in symbol conflicts between the two.",
crate_name)
}
let svh = decoder::get_crate_hash(metadata.as_slice());
// Check for conflicts with any crate loaded so far
self.cstore.iter_crate_data(|_, other| {
if other.name() == crate_name && // same crate-name
other.disambiguator() == disambiguator && // same crate-disambiguator
other.hash() != svh { // but different SVH
span_fatal!(self.sess, span, E0520,
"found two different crates with name `{}` that are \
not distinguished by differing `-C metadata`. This \
will result in symbol conflicts between the two.",
crate_name)
}
});
}
fn register_crate(&mut self,
root: &Option<CratePaths>,
ident: &str,
@ -282,6 +318,7 @@ impl<'a> CrateReader<'a> {
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
self.verify_rustc_version(name, span, &lib.metadata);
self.verify_no_symbol_conflicts(name, span, &lib.metadata);
// Claim this crate number and cache it
let cnum = self.next_crate_num;
@ -713,12 +750,15 @@ impl<'a> CrateReader<'a> {
}
impl<'a, 'b> LocalCrateReader<'a, 'b> {
pub fn new(sess: &'a Session, cstore: &'a CStore,
map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> {
pub fn new(sess: &'a Session,
cstore: &'a CStore,
map: &'a hir_map::Map<'b>,
local_crate_name: &str)
-> LocalCrateReader<'a, 'b> {
LocalCrateReader {
sess: sess,
cstore: cstore,
creader: CrateReader::new(sess, cstore),
creader: CrateReader::new(sess, cstore, local_crate_name),
ast_map: map,
}
}

View file

@ -250,6 +250,9 @@ impl crate_metadata {
pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
pub fn disambiguator(&self) -> &str {
decoder::get_crate_disambiguator(self.data())
}
pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
-> Ref<'a, Vec<ImportedFileMap>> {
let filemaps = self.codemap_import_info.borrow();

View file

@ -1297,8 +1297,8 @@ pub fn maybe_get_crate_name(data: &[u8]) -> Option<String> {
pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str {
let crate_doc = rbml::Doc::new(data);
let salt_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
let slice: &'a str = salt_doc.as_str_slice();
let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
let slice: &'a str = disambiguator_doc.as_str_slice();
slice
}

View file

@ -87,4 +87,6 @@ register_diagnostics! {
E0468, // an `extern crate` loading macros must be at the crate root
E0469, // imported macro not found
E0470, // reexported macro not found
E0519, // local crate and dependency have same (crate-name, disambiguator)
E0520, // two dependencies have same (crate-name, disambiguator) but different SVH
}

View file

@ -32,11 +32,11 @@ struct MacroLoader<'a> {
}
impl<'a> MacroLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore) -> MacroLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
MacroLoader {
sess: sess,
span_whitelist: HashSet::new(),
reader: CrateReader::new(sess, cstore),
reader: CrateReader::new(sess, cstore, crate_name),
macros: vec![],
}
}
@ -47,10 +47,13 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) {
}
/// Read exported macros.
pub fn read_macro_defs(sess: &Session, cstore: &CStore, krate: &ast::Crate)
pub fn read_macro_defs(sess: &Session,
cstore: &CStore,
krate: &ast::Crate,
crate_name: &str)
-> Vec<ast::MacroDef>
{
let mut loader = MacroLoader::new(sess, cstore);
let mut loader = MacroLoader::new(sess, cstore, crate_name);
// We need to error on `#[macro_use] extern crate` when it isn't at the
// crate root, because `$crate` won't work properly. Identify these by

View file

@ -44,9 +44,12 @@ fn call_malformed_plugin_attribute(a: &Session, b: Span) {
}
/// Read plugin metadata and dynamically load registrar functions.
pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate,
pub fn load_plugins(sess: &Session,
cstore: &CStore,
krate: &ast::Crate,
crate_name: &str,
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let mut loader = PluginLoader::new(sess, cstore);
let mut loader = PluginLoader::new(sess, cstore, crate_name);
for attr in &krate.attrs {
if !attr.check_name("plugin") {
@ -82,10 +85,10 @@ pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate,
}
impl<'a> PluginLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore) -> PluginLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> PluginLoader<'a> {
PluginLoader {
sess: sess,
reader: CrateReader::new(sess, cstore),
reader: CrateReader::new(sess, cstore, crate_name),
plugins: vec![],
}
}

View file

@ -78,11 +78,12 @@
//!
//! - In order to be able to also use symbols from two versions of the same
//! crate (which naturally also have the same name), a stronger measure is
//! required: The compiler accepts an arbitrary "salt" value via the
//! `-C metadata` commandline argument. This salt is then fed into the symbol
//! hash of every exported item. Consequently, the symbols in two identical
//! crates but with different salts are not in conflict with each other. This
//! facility is mainly intended to be used by build tools like Cargo.
//! required: The compiler accepts an arbitrary "disambiguator" value via the
//! `-C metadata` commandline argument. This disambiguator is then fed into
//! the symbol hash of every exported item. Consequently, the symbols in two
//! identical crates but with different disambiguators are not in conflict
//! with each other. This facility is mainly intended to be used by build
//! tools like Cargo.
//!
//! A note on symbol name stability
//! -------------------------------

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Foo {
fn bar(&self);
fn foo(&mut self) {}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Foo {
#[doc(hidden)]
fn foo(&self) {}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
#![doc(html_root_url = "http://example.com/")]
/// dox

View file

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
#![doc(html_root_url = "http://example.com")]

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
use std::ops::Deref;
pub struct Foo;

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Trait {
type Output;
}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Deref {
type Target: ?Sized;

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Foo {
type Bar;
fn foo(&self) {}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub struct Foo;
impl Foo {

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub mod foo {
pub trait Foo {}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
#![feature(const_fn)]
pub const fn foo() {}

View file

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub struct Foo;
#[doc(hidden)]

View file

@ -1,5 +1,5 @@
-include ../tools.mk
all:
$(RUSTC) libc.rs
$(RUSTC) libc.rs -Cmetadata=foo
$(RUSTC) main.rs --extern libc=$(TMPDIR)/liblibc.rlib

View file

@ -12,7 +12,7 @@ time: libc
libc:
mkdir -p $(OUT)/libc
$(RUSTC) in/libc/lib.rs --crate-name=libc -o $(OUT)/libc/liblibc.rlib
$(RUSTC) in/libc/lib.rs --crate-name=libc -Cmetadata=foo -o $(OUT)/libc/liblibc.rlib
else
all:
endif