From a98fd112281a2e5681a8023b421a52e98ea39eb5 Mon Sep 17 00:00:00 2001 From: mitaa Date: Thu, 30 Jul 2015 21:59:42 +0200 Subject: [PATCH 1/3] Split off `LocalCrateReader` from `CrateReader` --- src/librustc/metadata/creader.rs | 263 ++++++++++++++++--------------- src/librustc_driver/driver.rs | 4 +- 2 files changed, 142 insertions(+), 125 deletions(-) diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 623682a9cd5..578507296fc 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -34,14 +34,21 @@ use syntax::codemap::{self, Span, mk_sp, Pos}; use syntax::parse; use syntax::parse::token::InternedString; use syntax::visit; +use ast_map; use log; +pub struct LocalCrateReader<'a, 'b:'a> { + sess: &'a Session, + creader: CrateReader<'a>, + ast_map: &'a ast_map::Map<'b>, +} + pub struct CrateReader<'a> { sess: &'a Session, next_crate_num: ast::CrateNum, } -impl<'a, 'v> visit::Visitor<'v> for CrateReader<'a> { +impl<'a, 'b, 'v> visit::Visitor<'v> for LocalCrateReader<'a, 'b> { fn visit_item(&mut self, a: &ast::Item) { self.process_item(a); visit::walk_item(self, a); @@ -152,31 +159,6 @@ impl<'a> CrateReader<'a> { } } - // Traverses an AST, reading all the information about use'd crates and - // extern libraries necessary for later resolving, typechecking, linking, - // etc. - pub fn read_crates(&mut self, krate: &ast::Crate) { - self.process_crate(krate); - visit::walk_crate(self, krate); - - if log_enabled!(log::DEBUG) { - dump_crates(&self.sess.cstore); - } - - for &(ref name, kind) in &self.sess.opts.libs { - register_native_lib(self.sess, None, name.clone(), kind); - } - } - - fn process_crate(&self, c: &ast::Crate) { - for a in c.attrs.iter().filter(|m| m.name() == "link_args") { - match a.value_str() { - Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg), - None => { /* fallthrough */ } - } - } - } - fn extract_crate_info(&self, i: &ast::Item) -> Option { match i.node { ast::ItemExternCrate(ref path_opt) => { @@ -201,103 +183,6 @@ impl<'a> CrateReader<'a> { } } - fn process_item(&mut self, i: &ast::Item) { - match i.node { - ast::ItemExternCrate(_) => { - if !should_link(i) { - return; - } - - match self.extract_crate_info(i) { - Some(info) => { - let (cnum, _, _) = self.resolve_crate(&None, - &info.ident, - &info.name, - None, - i.span, - PathKind::Crate); - self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); - } - None => () - } - } - ast::ItemForeignMod(ref fm) => { - if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { - return; - } - - // First, add all of the custom link_args attributes - let link_args = i.attrs.iter() - .filter_map(|at| if at.name() == "link_args" { - Some(at) - } else { - None - }) - .collect::>(); - for m in &link_args { - match m.value_str() { - Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg), - None => { /* fallthrough */ } - } - } - - // Next, process all of the #[link(..)]-style arguments - let link_args = i.attrs.iter() - .filter_map(|at| if at.name() == "link" { - Some(at) - } else { - None - }) - .collect::>(); - for m in &link_args { - match m.meta_item_list() { - Some(items) => { - let kind = items.iter().find(|k| { - k.name() == "kind" - }).and_then(|a| a.value_str()); - let kind = match kind { - Some(k) => { - if k == "static" { - cstore::NativeStatic - } else if self.sess.target.target.options.is_like_osx - && k == "framework" { - cstore::NativeFramework - } else if k == "framework" { - cstore::NativeFramework - } else if k == "dylib" { - cstore::NativeUnknown - } else { - self.sess.span_err(m.span, - &format!("unknown kind: `{}`", - k)); - cstore::NativeUnknown - } - } - None => cstore::NativeUnknown - }; - let n = items.iter().find(|n| { - n.name() == "name" - }).and_then(|a| a.value_str()); - let n = match n { - Some(n) => n, - None => { - self.sess.span_err(m.span, - "#[link(...)] specified without \ - `name = \"foo\"`"); - InternedString::new("foo") - } - }; - register_native_lib(self.sess, Some(m.span), - n.to_string(), kind); - } - None => {} - } - } - } - _ => { } - } - } - fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) -> Option { let mut ret = None; @@ -592,6 +477,138 @@ impl<'a> CrateReader<'a> { } } +impl<'a, 'b> LocalCrateReader<'a, 'b> { + pub fn new(sess: &'a Session, map: &'a ast_map::Map<'b>) -> LocalCrateReader<'a, 'b> { + LocalCrateReader { + sess: sess, + creader: CrateReader::new(sess), + ast_map: map, + } + } + + // Traverses an AST, reading all the information about use'd crates and + // extern libraries necessary for later resolving, typechecking, linking, + // etc. + pub fn read_crates(&mut self, krate: &ast::Crate) { + self.process_crate(krate); + visit::walk_crate(self, krate); + + if log_enabled!(log::DEBUG) { + dump_crates(&self.sess.cstore); + } + + for &(ref name, kind) in &self.sess.opts.libs { + register_native_lib(self.sess, None, name.clone(), kind); + } + } + + fn process_crate(&self, c: &ast::Crate) { + for a in c.attrs.iter().filter(|m| m.name() == "link_args") { + match a.value_str() { + Some(ref linkarg) => self.sess.cstore.add_used_link_args(&linkarg), + None => { /* fallthrough */ } + } + } + } + + fn process_item(&mut self, i: &ast::Item) { + match i.node { + ast::ItemExternCrate(_) => { + if !should_link(i) { + return; + } + + match self.creader.extract_crate_info(i) { + Some(info) => { + let (cnum, _, _) = self.creader.resolve_crate(&None, + &info.ident, + &info.name, + None, + i.span, + PathKind::Crate); + self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); + } + None => () + } + } + ast::ItemForeignMod(ref fm) => { + if fm.abi == abi::Rust || fm.abi == abi::RustIntrinsic { + return; + } + + // First, add all of the custom link_args attributes + let link_args = i.attrs.iter() + .filter_map(|at| if at.name() == "link_args" { + Some(at) + } else { + None + }) + .collect::>(); + for m in &link_args { + match m.value_str() { + Some(linkarg) => self.sess.cstore.add_used_link_args(&linkarg), + None => { /* fallthrough */ } + } + } + + // Next, process all of the #[link(..)]-style arguments + let link_args = i.attrs.iter() + .filter_map(|at| if at.name() == "link" { + Some(at) + } else { + None + }) + .collect::>(); + for m in &link_args { + match m.meta_item_list() { + Some(items) => { + let kind = items.iter().find(|k| { + k.name() == "kind" + }).and_then(|a| a.value_str()); + let kind = match kind { + Some(k) => { + if k == "static" { + cstore::NativeStatic + } else if self.sess.target.target.options.is_like_osx + && k == "framework" { + cstore::NativeFramework + } else if k == "framework" { + cstore::NativeFramework + } else if k == "dylib" { + cstore::NativeUnknown + } else { + self.sess.span_err(m.span, + &format!("unknown kind: `{}`", + k)); + cstore::NativeUnknown + } + } + None => cstore::NativeUnknown + }; + let n = items.iter().find(|n| { + n.name() == "name" + }).and_then(|a| a.value_str()); + let n = match n { + Some(n) => n, + None => { + self.sess.span_err(m.span, + "#[link(...)] specified without \ + `name = \"foo\"`"); + InternedString::new("foo") + } + }; + register_native_lib(self.sess, Some(m.span), + n.to_string(), kind); + } + None => {} + } + } + } + _ => { } + } + } +} + /// Imports the codemap from an external crate into the codemap of the crate /// currently being compiled (the "local crate"). /// diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 67301a09e52..80db6426917 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -14,7 +14,7 @@ use rustc::session::search_paths::PathKind; use rustc::ast_map; use rustc::lint; use rustc::metadata; -use rustc::metadata::creader::CrateReader; +use rustc::metadata::creader::LocalCrateReader; use rustc::middle::{stability, ty, reachable}; use rustc::middle::dependency_format; use rustc::middle; @@ -609,7 +609,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session, let krate = ast_map.krate(); time(time_passes, "external crate/lib resolution", (), |_| - CrateReader::new(&sess).read_crates(krate)); + LocalCrateReader::new(&sess, &ast_map).read_crates(krate)); let lang_items = time(time_passes, "language item collection", (), |_| middle::lang_items::collect_language_items(krate, &sess)); From 2b4124684e26708038b6678a38fcfbeeecb90c6e Mon Sep 17 00:00:00 2001 From: mitaa Date: Sat, 1 Aug 2015 16:14:45 +0200 Subject: [PATCH 2/3] Store and use crate-local paths to extern crates --- src/librustc/metadata/creader.rs | 6 +++++- src/librustc/metadata/csearch.rs | 12 ++++++------ src/librustc/metadata/cstore.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 578507296fc..f4561d68906 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -34,6 +34,7 @@ use syntax::codemap::{self, Span, mk_sp, Pos}; use syntax::parse; use syntax::parse::token::InternedString; use syntax::visit; +use syntax::util::small_vector::SmallVector; use ast_map; use log; @@ -263,6 +264,7 @@ impl<'a> CrateReader<'a> { let cmeta = Rc::new( cstore::crate_metadata { name: name.to_string(), + local_path: RefCell::new(SmallVector::zero()), data: metadata, cnum_map: cnum_map, cnum: cnum, @@ -520,12 +522,14 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> { match self.creader.extract_crate_info(i) { Some(info) => { - let (cnum, _, _) = self.creader.resolve_crate(&None, + let (cnum, cmeta, _) = self.creader.resolve_crate(&None, &info.ident, &info.name, None, i.span, PathKind::Crate); + self.ast_map.with_path(i.id, |path| + cmeta.update_local_path(path)); self.sess.cstore.add_extern_mod_stmt_cnum(info.id, cnum); } None => () diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 2a469ed69ef..21d5dac7e5d 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -24,7 +24,6 @@ use syntax::ast; use syntax::attr; use syntax::attr::AttrMetaMethods; use syntax::diagnostic::expect; -use syntax::parse::token; use std::collections::hash_map::HashMap; @@ -89,11 +88,12 @@ pub fn get_item_path(tcx: &ty::ctxt, def: ast::DefId) -> Vec let cdata = cstore.get_crate_data(def.krate); let path = decoder::get_item_path(&*cdata, def.node); - // FIXME #1920: This path is not always correct if the crate is not linked - // into the root namespace. - let mut r = vec![ast_map::PathMod(token::intern(&cdata.name))]; - r.push_all(&path); - r + cdata.with_local_path(|cpath| { + let mut r = Vec::with_capacity(cpath.len() + path.len()); + r.push_all(cpath); + r.push_all(&path); + r + }) } pub enum FoundAst<'ast> { diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 4941c932ead..08c05b76862 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -28,7 +28,10 @@ use std::path::PathBuf; use flate::Bytes; use syntax::ast; use syntax::codemap; +use syntax::parse::token; use syntax::parse::token::IdentInterner; +use syntax::util::small_vector::SmallVector; +use ast_map; // A map from external crate numbers (as decoded from some crate file) to // local crate numbers (as generated during this session). Each external @@ -54,6 +57,7 @@ pub struct ImportedFileMap { pub struct crate_metadata { pub name: String, + pub local_path: RefCell>, pub data: MetadataBlob, pub cnum_map: cnum_map, pub cnum: ast::CrateNum, @@ -255,6 +259,30 @@ impl crate_metadata { filemaps } } + pub fn with_local_path(&self, f: F) -> T + where F: Fn(&[ast_map::PathElem]) -> T { + let cpath = self.local_path.borrow(); + if cpath.is_empty() { + let name = ast_map::PathMod(token::intern(&self.name)); + f(&[name]) + } else { + f(cpath.as_slice()) + } + } + pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) { + let mut cpath = self.local_path.borrow_mut(); + let cap = cpath.len(); + match cap { + 0 => *cpath = candidate.collect(), + 1 => (), + _ => { + let candidate: SmallVector<_> = candidate.collect(); + if candidate.len() < cap { + *cpath = candidate; + } + }, + } + } } impl MetadataBlob { From dcf7ac6f9a84ae52b07f9d7310637c9f9d9815ce Mon Sep 17 00:00:00 2001 From: mitaa Date: Sat, 1 Aug 2015 19:41:01 +0200 Subject: [PATCH 3/3] Fix and add tests regarding extern crate paths --- src/test/compile-fail/issue-12997-2.rs | 2 +- src/test/compile-fail/issue-1920-1.rs | 22 +++++++++++++++++ src/test/compile-fail/issue-1920-2.rs | 20 ++++++++++++++++ src/test/compile-fail/issue-1920-3.rs | 24 +++++++++++++++++++ src/test/compile-fail/privacy5.rs | 18 +++++++------- src/test/compile-fail/struct-field-privacy.rs | 4 ++-- .../compile-fail/suggest-private-fields.rs | 4 ++-- 7 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 src/test/compile-fail/issue-1920-1.rs create mode 100644 src/test/compile-fail/issue-1920-2.rs create mode 100644 src/test/compile-fail/issue-1920-3.rs diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs index 1cf534e7e41..8b467c2ba11 100644 --- a/src/test/compile-fail/issue-12997-2.rs +++ b/src/test/compile-fail/issue-12997-2.rs @@ -15,7 +15,7 @@ #[bench] fn bar(x: isize) { } //~^ ERROR mismatched types -//~| expected `fn(&mut test::Bencher)` +//~| expected `fn(&mut __test::test::Bencher)` //~| found `fn(isize) {bar}` //~| expected &-ptr //~| found isize diff --git a/src/test/compile-fail/issue-1920-1.rs b/src/test/compile-fail/issue-1920-1.rs new file mode 100644 index 00000000000..c26c5ff8421 --- /dev/null +++ b/src/test/compile-fail/issue-1920-1.rs @@ -0,0 +1,22 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Test that absolute path names are correct when a crate is not linked into the root namespace + +mod foo { + extern crate core; +} + +fn assert_clone() where T : Clone { } + +fn main() { + assert_clone::(); + //~^ ERROR the trait `foo::core::clone::Clone` is not implemented for the type `foo::core:: +} \ No newline at end of file diff --git a/src/test/compile-fail/issue-1920-2.rs b/src/test/compile-fail/issue-1920-2.rs new file mode 100644 index 00000000000..63cfcbdd8c7 --- /dev/null +++ b/src/test/compile-fail/issue-1920-2.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Test that when a crate is linked under another name that that name is used in global paths + +extern crate core as bar; + +fn assert_clone() where T : Clone { } + +fn main() { + assert_clone::(); + //~^ ERROR the trait `bar::clone::Clone` is not implemented for the type `bar::atomic:: +} \ No newline at end of file diff --git a/src/test/compile-fail/issue-1920-3.rs b/src/test/compile-fail/issue-1920-3.rs new file mode 100644 index 00000000000..619c8c3f3a4 --- /dev/null +++ b/src/test/compile-fail/issue-1920-3.rs @@ -0,0 +1,24 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Test that when a crate is linked multiple times that the shortest absolute path name is used + +mod foo { + extern crate core; +} + +extern crate core; + +fn assert_clone() where T : Clone { } + +fn main() { + assert_clone::(); + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `core::atomic:: +} \ No newline at end of file diff --git a/src/test/compile-fail/privacy5.rs b/src/test/compile-fail/privacy5.rs index 4ca37fc2ad2..83e13ff52f6 100644 --- a/src/test/compile-fail/privacy5.rs +++ b/src/test/compile-fail/privacy5.rs @@ -101,30 +101,30 @@ fn xcrate() { let c = other::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor let d = other::D(4); - let other::A(()) = a; //~ ERROR: field #1 of struct `privacy_tuple_struct::A` is private + let other::A(()) = a; //~ ERROR: field #1 of struct `other::A` is private let other::A(_) = a; match a { other::A(()) => {} } - //~^ ERROR: field #1 of struct `privacy_tuple_struct::A` is private + //~^ ERROR: field #1 of struct `other::A` is private match a { other::A(_) => {} } let other::B(_) = b; - let other::B(_b) = b; //~ ERROR: field #1 of struct `privacy_tuple_struct::B` is private + let other::B(_b) = b; //~ ERROR: field #1 of struct `other::B` is private match b { other::B(_) => {} } match b { other::B(_b) => {} } - //~^ ERROR: field #1 of struct `privacy_tuple_struct::B` is private + //~^ ERROR: field #1 of struct `other::B` is private match b { other::B(1) => {} other::B(_) => {} } - //~^ ERROR: field #1 of struct `privacy_tuple_struct::B` is private + //~^ ERROR: field #1 of struct `other::B` is private let other::C(_, _) = c; let other::C(_a, _) = c; - let other::C(_, _b) = c; //~ ERROR: field #2 of struct `privacy_tuple_struct::C` is private - let other::C(_a, _b) = c; //~ ERROR: field #2 of struct `privacy_tuple_struct::C` is private + let other::C(_, _b) = c; //~ ERROR: field #2 of struct `other::C` is private + let other::C(_a, _b) = c; //~ ERROR: field #2 of struct `other::C` is private match c { other::C(_, _) => {} } match c { other::C(_a, _) => {} } match c { other::C(_, _b) => {} } - //~^ ERROR: field #2 of struct `privacy_tuple_struct::C` is private + //~^ ERROR: field #2 of struct `other::C` is private match c { other::C(_a, _b) => {} } - //~^ ERROR: field #2 of struct `privacy_tuple_struct::C` is private + //~^ ERROR: field #2 of struct `other::C` is private let other::D(_) = d; let other::D(_d) = d; diff --git a/src/test/compile-fail/struct-field-privacy.rs b/src/test/compile-fail/struct-field-privacy.rs index a1b6b9a744c..aae09cc0eae 100644 --- a/src/test/compile-fail/struct-field-privacy.rs +++ b/src/test/compile-fail/struct-field-privacy.rs @@ -37,11 +37,11 @@ fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B) { c.a; c.b; //~ ERROR: field `b` of struct `inner::B` is private - d.a; //~ ERROR: field `a` of struct `struct_field_privacy::A` is private + d.a; //~ ERROR: field `a` of struct `xc::A` is private d.b; e.a; - e.b; //~ ERROR: field `b` of struct `struct_field_privacy::B` is private + e.b; //~ ERROR: field `b` of struct `xc::B` is private } fn main() {} diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs index f987257d4ee..8bc8a7a60bd 100644 --- a/src/test/compile-fail/suggest-private-fields.rs +++ b/src/test/compile-fail/suggest-private-fields.rs @@ -22,9 +22,9 @@ struct A { fn main () { // external crate struct let k = B { - aa: 20, //~ ERROR structure `struct_field_privacy::B` has no field named `aa` + aa: 20, //~ ERROR structure `xc::B` has no field named `aa` //~^ HELP did you mean `a`? - bb: 20, //~ ERROR structure `struct_field_privacy::B` has no field named `bb` + bb: 20, //~ ERROR structure `xc::B` has no field named `bb` }; // local crate struct let l = A {