diff --git a/src/librustc/ich/impls_cstore.rs b/src/librustc/ich/impls_cstore.rs index 0071850e1052b..d885bd43bc89d 100644 --- a/src/librustc/ich/impls_cstore.rs +++ b/src/librustc/ich/impls_cstore.rs @@ -47,10 +47,16 @@ impl_stable_hash_for!(enum middle::cstore::LinkagePreference { }); impl_stable_hash_for!(struct middle::cstore::ExternCrate { - def_id, + src, span, - direct, - path_len + path_len, + direct +}); + +impl_stable_hash_for!(enum middle::cstore::ExternCrateSource { + Extern(def_id), + Use, + Path, }); impl_stable_hash_for!(struct middle::cstore::CrateSource { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 41334a37dbef6..292ec184dfae5 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -148,23 +148,34 @@ pub enum LoadedMacro { #[derive(Copy, Clone, Debug)] pub struct ExternCrate { - /// def_id of an `extern crate` in the current crate that caused - /// this crate to be loaded; note that there could be multiple - /// such ids - pub def_id: DefId, + pub src: ExternCrateSource, /// span of the extern crate that caused this to be loaded pub span: Span, + /// Number of links to reach the extern; + /// used to select the extern with the shortest path + pub path_len: usize, + /// If true, then this crate is the crate named by the extern /// crate referenced above. If false, then this crate is a dep /// of the crate. pub direct: bool, +} - /// Number of links to reach the extern crate `def_id` - /// declaration; used to select the extern crate with the shortest - /// path - pub path_len: usize, +#[derive(Copy, Clone, Debug)] +pub enum ExternCrateSource { + /// Crate is loaded by `extern crate`. + Extern( + /// def_id of the item in the current crate that caused + /// this crate to be loaded; note that there could be multiple + /// such ids + DefId, + ), + // Crate is loaded by `use`. + Use, + /// Crate is implicitly loaded by an absolute or an `extern::` path. + Path, } pub struct EncodedMetadata { @@ -357,9 +368,23 @@ impl CrateStore for DummyCrateStore { } pub trait CrateLoader { - fn process_item(&mut self, item: &ast::Item, defs: &Definitions); + fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum; + + fn process_path_extern( + &mut self, + name: Symbol, + span: Span, + ) -> CrateNum; + + fn process_use_extern( + &mut self, + name: Symbol, + span: Span, + id: ast::NodeId, + defs: &Definitions, + ) -> CrateNum; + fn postprocess(&mut self, krate: &ast::Crate); - fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum; } // This method is used when generating the command line to pass through to diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 1f23b0a27e33d..8189064db6968 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -11,6 +11,7 @@ use hir::map::DefPathData; use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; +use middle::cstore::{ExternCrate, ExternCrateSource}; use syntax::ast; use syntax::symbol::Symbol; use syntax::symbol::InternedString; @@ -95,21 +96,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // `extern crate` manually, we put the `extern // crate` as the parent. So you wind up with // something relative to the current crate. - // 2. for an indirect crate, where there is no extern - // crate, we just prepend the crate name. + // 2. for an extern inferred from a path or an indirect crate, + // where there is no explicit `extern crate`, we just prepend + // the crate name. // // Returns `None` for the local crate. if cnum != LOCAL_CRATE { let opt_extern_crate = self.extern_crate(cnum.as_def_id()); - let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| { - if extern_crate.direct { - Some(extern_crate.def_id) - } else { - None - } - }); - if let Some(extern_crate_def_id) = opt_extern_crate { - self.push_item_path(buffer, extern_crate_def_id); + if let Some(ExternCrate { + src: ExternCrateSource::Extern(def_id), + direct: true, + .. + }) = *opt_extern_crate + { + self.push_item_path(buffer, def_id); } else { buffer.push(&self.crate_name(cnum).as_str()); } @@ -137,14 +137,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // followed by the path to the item within the crate and return. if cur_def.index == CRATE_DEF_INDEX { match *self.extern_crate(cur_def) { - Some(ref extern_crate) if extern_crate.direct => { - self.push_item_path(buffer, extern_crate.def_id); - cur_path.iter().rev().map(|segment| buffer.push(&segment)).count(); + Some(ExternCrate { + src: ExternCrateSource::Extern(def_id), + direct: true, + .. + }) => { + self.push_item_path(buffer, def_id); + cur_path.iter().rev().for_each(|segment| buffer.push(&segment)); return true; } None => { buffer.push(&self.crate_name(cur_def.krate).as_str()); - cur_path.iter().rev().map(|segment| buffer.push(&segment)).count(); + cur_path.iter().rev().for_each(|segment| buffer.push(&segment)); return true; } _ => {}, diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 34d9f47bac3dd..8a18a4b5290f8 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -25,7 +25,7 @@ use rustc_back::PanicStrategy; use rustc_back::target::TargetTriple; use rustc::session::search_paths::PathKind; use rustc::middle; -use rustc::middle::cstore::{validate_crate_name, ExternCrate}; +use rustc::middle::cstore::{validate_crate_name, ExternCrate, ExternCrateSource}; use rustc::util::common::record_time; use rustc::util::nodemap::FxHashSet; use rustc::hir::map::Definitions; @@ -371,12 +371,19 @@ impl<'a> CrateLoader<'a> { // - something over nothing (tuple.0); // - direct extern crate to indirect (tuple.1); // - shorter paths to longer (tuple.2). - let new_rank = (true, extern_crate.direct, !extern_crate.path_len); + let new_rank = ( + true, + extern_crate.direct, + cmp::Reverse(extern_crate.path_len), + ); let old_rank = match *old_extern_crate { - None => (false, false, !0), - Some(ref c) => (true, c.direct, !c.path_len), + None => (false, false, cmp::Reverse(usize::max_value())), + Some(ref c) => ( + true, + c.direct, + cmp::Reverse(c.path_len), + ), }; - if old_rank >= new_rank { return; // no change needed } @@ -1053,7 +1060,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { } } - fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) { + fn process_extern_crate(&mut self, item: &ast::Item, definitions: &Definitions) -> CrateNum { match item.node { ast::ItemKind::ExternCrate(orig_name) => { debug!("resolving extern crate stmt. ident: {} orig_name: {:?}", @@ -1079,17 +1086,72 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> { let def_id = definitions.opt_local_def_id(item.id).unwrap(); let path_len = definitions.def_path(def_id.index).data.len(); - - let extern_crate = ExternCrate { def_id, span: item.span, direct: true, path_len }; - self.update_extern_crate(cnum, extern_crate, &mut FxHashSet()); + self.update_extern_crate( + cnum, + ExternCrate { + src: ExternCrateSource::Extern(def_id), + span: item.span, + path_len, + direct: true, + }, + &mut FxHashSet(), + ); self.cstore.add_extern_mod_stmt_cnum(item.id, cnum); + cnum } - _ => {} + _ => bug!(), } } - fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum { - self.resolve_crate(&None, name, name, None, None, span, PathKind::Crate, - DepKind::Explicit).0 + fn process_path_extern( + &mut self, + name: Symbol, + span: Span, + ) -> CrateNum { + let cnum = self.resolve_crate( + &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit + ).0; + + self.update_extern_crate( + cnum, + ExternCrate { + src: ExternCrateSource::Path, + span, + // to have the least priority in `update_extern_crate` + path_len: usize::max_value(), + direct: true, + }, + &mut FxHashSet(), + ); + + cnum + } + + fn process_use_extern( + &mut self, + name: Symbol, + span: Span, + id: ast::NodeId, + definitions: &Definitions, + ) -> CrateNum { + let cnum = self.resolve_crate( + &None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit + ).0; + + let def_id = definitions.opt_local_def_id(id).unwrap(); + let path_len = definitions.def_path(def_id.index).data.len(); + + self.update_extern_crate( + cnum, + ExternCrate { + src: ExternCrateSource::Use, + span, + path_len, + direct: true, + }, + &mut FxHashSet(), + ); + + cnum } } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0542ca6fb24c2..f4e2136a5a115 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -252,10 +252,7 @@ impl<'a> Resolver<'a> { } ItemKind::ExternCrate(orig_name) => { - self.crate_loader.process_item(item, &self.definitions); - - // n.b. we don't need to look at the path option here, because cstore already did - let crate_id = self.cstore.extern_mod_stmt_cnum_untracked(item.id).unwrap(); + let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions); let module = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(module); @@ -302,7 +299,8 @@ impl<'a> Resolver<'a> { self.current_module = module; } - ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions), + // Handled in `rustc_metadata::{native_libs,link_args}` + ItemKind::ForeignMod(..) => {} // These items live in the value namespace. ItemKind::Static(_, m, _) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d32d853c18bf5..01940ee4fd0f6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3254,7 +3254,7 @@ impl<'a> Resolver<'a> { prev_name == keywords::CrateRoot.name() && self.session.features_untracked().extern_absolute_paths { // `::extern_crate::a::b` - let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span); + let crate_id = self.crate_loader.process_path_extern(name, ident.span); let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(crate_root); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 87738f7b79be5..37c62a7b0b45b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -627,7 +627,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } else if is_extern && !token::is_path_segment_keyword(source) { let crate_id = - self.crate_loader.resolve_crate_from_path(source.name, directive.span); + self.resolver.crate_loader.process_use_extern( + source.name, + directive.span, + directive.id, + &self.resolver.definitions, + ); let crate_root = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(crate_root); diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index ca19ed0df67d1..6a747decbd368 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -41,6 +41,7 @@ use rustc::hir; use rustc::hir::def::Def as HirDef; use rustc::hir::map::{Node, NodeItem}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::middle::cstore::ExternCrate; use rustc::session::config::CrateType::CrateTypeExecutable; use rustc::ty::{self, TyCtxt}; use rustc_typeck::hir_ty_to_ty; @@ -111,7 +112,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { for &n in self.tcx.crates().iter() { let span = match *self.tcx.extern_crate(n.as_def_id()) { - Some(ref c) => c.span, + Some(ExternCrate { span, .. }) => span, None => { debug!("Skipping crate {}, no data", n); continue; diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile b/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile new file mode 100644 index 0000000000000..a132668ec7c8a --- /dev/null +++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile @@ -0,0 +1,10 @@ +-include ../tools.mk + +all: extern_absolute_paths.rs extern_in_paths.rs krate2 + $(RUSTC) extern_absolute_paths.rs -Zsave-analysis + cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py + $(RUSTC) extern_in_paths.rs -Zsave-analysis + cat $(TMPDIR)/save-analysis/extern_in_paths.json | "$(PYTHON)" validate_json.py + +krate2: krate2.rs + $(RUSTC) $< diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/extern_absolute_paths.rs b/src/test/run-make-fulldeps/save-analysis-rfc2126/extern_absolute_paths.rs new file mode 100644 index 0000000000000..b1fe535766d21 --- /dev/null +++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/extern_absolute_paths.rs @@ -0,0 +1,18 @@ +// Copyright 2018 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. + +#![feature(extern_absolute_paths)] + +use krate2::hello; + +fn main() { + hello(); + ::krate2::hello(); +} diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/extern_in_paths.rs b/src/test/run-make-fulldeps/save-analysis-rfc2126/extern_in_paths.rs new file mode 100644 index 0000000000000..e48627e86bac5 --- /dev/null +++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/extern_in_paths.rs @@ -0,0 +1,17 @@ +// Copyright 2018 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. + +#![feature(extern_in_paths)] + +use extern::krate2; + +fn main() { + extern::krate2::hello(); +} diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/krate2.rs b/src/test/run-make-fulldeps/save-analysis-rfc2126/krate2.rs new file mode 100644 index 0000000000000..21fc57ccdf2de --- /dev/null +++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/krate2.rs @@ -0,0 +1,15 @@ +// Copyright 2018 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. + +#![crate_name = "krate2"] +#![crate_type = "lib"] + +pub fn hello() { +} diff --git a/src/test/run-make-fulldeps/save-analysis-rfc2126/validate_json.py b/src/test/run-make-fulldeps/save-analysis-rfc2126/validate_json.py new file mode 100644 index 0000000000000..caab8d0d62697 --- /dev/null +++ b/src/test/run-make-fulldeps/save-analysis-rfc2126/validate_json.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +# Copyright 2018 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. + +import sys +import json + +crates = json.loads(sys.stdin.readline().strip())["prelude"]["external_crates"] +assert any(map(lambda c: c["id"]["name"] == "krate2", crates))