Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix save-analysis generation with extern_in_paths/extern_absolute_paths #49847

Merged
merged 4 commits into from
Apr 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1045,7 +1052,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 @@ -1071,17 +1078,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 @@ -3258,7 +3258,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 @@ -42,6 +42,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 @@ -112,7 +113,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