Auto merge of #49847 - sinkuu:save_analysis_implicit_extern, r=petrochenkov
Fix save-analysis generation with extern_in_paths/extern_absolute_paths Fixes #48742.
This commit is contained in:
commit
748c549185
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
_ => {},
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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, _) => {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
10
src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
Normal file
10
src/test/run-make-fulldeps/save-analysis-rfc2126/Makefile
Normal file
@ -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) $<
|
@ -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();
|
||||
}
|
@ -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
src/test/run-make-fulldeps/save-analysis-rfc2126/krate2.rs
Normal file
15
src/test/run-make-fulldeps/save-analysis-rfc2126/krate2.rs
Normal file
@ -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() {
|
||||
}
|
@ -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 <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.
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
crates = json.loads(sys.stdin.readline().strip())["prelude"]["external_crates"]
|
||||
assert any(map(lambda c: c["id"]["name"] == "krate2", crates))
|
Loading…
Reference in New Issue
Block a user