Skip to content

Commit

Permalink
Auto merge of #49847 - sinkuu:save_analysis_implicit_extern, r=petroc…
Browse files Browse the repository at this point in the history
…henkov

Fix save-analysis generation with extern_in_paths/extern_absolute_paths

Fixes #48742.
  • Loading branch information
bors committed Apr 16, 2018
2 parents d6ba1b9 + c3dc014 commit 748c549
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 49 deletions.
12 changes: 9 additions & 3 deletions src/librustc/ich/impls_cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
45 changes: 35 additions & 10 deletions src/librustc/middle/cstore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
34 changes: 19 additions & 15 deletions src/librustc/ty/item_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
Expand Down Expand Up @@ -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;
}
_ => {},
Expand Down
88 changes: 75 additions & 13 deletions src/librustc_metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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: {:?}",
Expand All @@ -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
}
}
8 changes: 3 additions & 5 deletions src/librustc_resolve/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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, _) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion src/librustc_resolve/resolve_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_save_analysis/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
Original file line number Diff line number Diff line change
@@ -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) $<
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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();
}
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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();
}
15 changes: 15 additions & 0 deletions src/test/run-make-fulldeps/save-analysis-rfc2126/krate2.rs
Original file line number Diff line number Diff line change
@@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() {
}
Loading

0 comments on commit 748c549

Please sign in to comment.