Skip to content

Commit 748c549

Browse files
committed
Auto merge of #49847 - sinkuu:save_analysis_implicit_extern, r=petrochenkov
Fix save-analysis generation with extern_in_paths/extern_absolute_paths Fixes #48742.
2 parents d6ba1b9 + c3dc014 commit 748c549

File tree

13 files changed

+227
-49
lines changed

13 files changed

+227
-49
lines changed

src/librustc/ich/impls_cstore.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,16 @@ impl_stable_hash_for!(enum middle::cstore::LinkagePreference {
4747
});
4848

4949
impl_stable_hash_for!(struct middle::cstore::ExternCrate {
50-
def_id,
50+
src,
5151
span,
52-
direct,
53-
path_len
52+
path_len,
53+
direct
54+
});
55+
56+
impl_stable_hash_for!(enum middle::cstore::ExternCrateSource {
57+
Extern(def_id),
58+
Use,
59+
Path,
5460
});
5561

5662
impl_stable_hash_for!(struct middle::cstore::CrateSource {

src/librustc/middle/cstore.rs

+35-10
Original file line numberDiff line numberDiff line change
@@ -148,23 +148,34 @@ pub enum LoadedMacro {
148148

149149
#[derive(Copy, Clone, Debug)]
150150
pub struct ExternCrate {
151-
/// def_id of an `extern crate` in the current crate that caused
152-
/// this crate to be loaded; note that there could be multiple
153-
/// such ids
154-
pub def_id: DefId,
151+
pub src: ExternCrateSource,
155152

156153
/// span of the extern crate that caused this to be loaded
157154
pub span: Span,
158155

156+
/// Number of links to reach the extern;
157+
/// used to select the extern with the shortest path
158+
pub path_len: usize,
159+
159160
/// If true, then this crate is the crate named by the extern
160161
/// crate referenced above. If false, then this crate is a dep
161162
/// of the crate.
162163
pub direct: bool,
164+
}
163165

164-
/// Number of links to reach the extern crate `def_id`
165-
/// declaration; used to select the extern crate with the shortest
166-
/// path
167-
pub path_len: usize,
166+
#[derive(Copy, Clone, Debug)]
167+
pub enum ExternCrateSource {
168+
/// Crate is loaded by `extern crate`.
169+
Extern(
170+
/// def_id of the item in the current crate that caused
171+
/// this crate to be loaded; note that there could be multiple
172+
/// such ids
173+
DefId,
174+
),
175+
// Crate is loaded by `use`.
176+
Use,
177+
/// Crate is implicitly loaded by an absolute or an `extern::` path.
178+
Path,
168179
}
169180

170181
pub struct EncodedMetadata {
@@ -357,9 +368,23 @@ impl CrateStore for DummyCrateStore {
357368
}
358369

359370
pub trait CrateLoader {
360-
fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
371+
fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum;
372+
373+
fn process_path_extern(
374+
&mut self,
375+
name: Symbol,
376+
span: Span,
377+
) -> CrateNum;
378+
379+
fn process_use_extern(
380+
&mut self,
381+
name: Symbol,
382+
span: Span,
383+
id: ast::NodeId,
384+
defs: &Definitions,
385+
) -> CrateNum;
386+
361387
fn postprocess(&mut self, krate: &ast::Crate);
362-
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum;
363388
}
364389

365390
// This method is used when generating the command line to pass through to

src/librustc/ty/item_path.rs

+19-15
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use hir::map::DefPathData;
1212
use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
1313
use ty::{self, Ty, TyCtxt};
14+
use middle::cstore::{ExternCrate, ExternCrateSource};
1415
use syntax::ast;
1516
use syntax::symbol::Symbol;
1617
use syntax::symbol::InternedString;
@@ -95,21 +96,20 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
9596
// `extern crate` manually, we put the `extern
9697
// crate` as the parent. So you wind up with
9798
// something relative to the current crate.
98-
// 2. for an indirect crate, where there is no extern
99-
// crate, we just prepend the crate name.
99+
// 2. for an extern inferred from a path or an indirect crate,
100+
// where there is no explicit `extern crate`, we just prepend
101+
// the crate name.
100102
//
101103
// Returns `None` for the local crate.
102104
if cnum != LOCAL_CRATE {
103105
let opt_extern_crate = self.extern_crate(cnum.as_def_id());
104-
let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| {
105-
if extern_crate.direct {
106-
Some(extern_crate.def_id)
107-
} else {
108-
None
109-
}
110-
});
111-
if let Some(extern_crate_def_id) = opt_extern_crate {
112-
self.push_item_path(buffer, extern_crate_def_id);
106+
if let Some(ExternCrate {
107+
src: ExternCrateSource::Extern(def_id),
108+
direct: true,
109+
..
110+
}) = *opt_extern_crate
111+
{
112+
self.push_item_path(buffer, def_id);
113113
} else {
114114
buffer.push(&self.crate_name(cnum).as_str());
115115
}
@@ -137,14 +137,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
137137
// followed by the path to the item within the crate and return.
138138
if cur_def.index == CRATE_DEF_INDEX {
139139
match *self.extern_crate(cur_def) {
140-
Some(ref extern_crate) if extern_crate.direct => {
141-
self.push_item_path(buffer, extern_crate.def_id);
142-
cur_path.iter().rev().map(|segment| buffer.push(&segment)).count();
140+
Some(ExternCrate {
141+
src: ExternCrateSource::Extern(def_id),
142+
direct: true,
143+
..
144+
}) => {
145+
self.push_item_path(buffer, def_id);
146+
cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
143147
return true;
144148
}
145149
None => {
146150
buffer.push(&self.crate_name(cur_def.krate).as_str());
147-
cur_path.iter().rev().map(|segment| buffer.push(&segment)).count();
151+
cur_path.iter().rev().for_each(|segment| buffer.push(&segment));
148152
return true;
149153
}
150154
_ => {},

src/librustc_metadata/creader.rs

+75-13
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use rustc_back::PanicStrategy;
2525
use rustc_back::target::TargetTriple;
2626
use rustc::session::search_paths::PathKind;
2727
use rustc::middle;
28-
use rustc::middle::cstore::{validate_crate_name, ExternCrate};
28+
use rustc::middle::cstore::{validate_crate_name, ExternCrate, ExternCrateSource};
2929
use rustc::util::common::record_time;
3030
use rustc::util::nodemap::FxHashSet;
3131
use rustc::hir::map::Definitions;
@@ -371,12 +371,19 @@ impl<'a> CrateLoader<'a> {
371371
// - something over nothing (tuple.0);
372372
// - direct extern crate to indirect (tuple.1);
373373
// - shorter paths to longer (tuple.2).
374-
let new_rank = (true, extern_crate.direct, !extern_crate.path_len);
374+
let new_rank = (
375+
true,
376+
extern_crate.direct,
377+
cmp::Reverse(extern_crate.path_len),
378+
);
375379
let old_rank = match *old_extern_crate {
376-
None => (false, false, !0),
377-
Some(ref c) => (true, c.direct, !c.path_len),
380+
None => (false, false, cmp::Reverse(usize::max_value())),
381+
Some(ref c) => (
382+
true,
383+
c.direct,
384+
cmp::Reverse(c.path_len),
385+
),
378386
};
379-
380387
if old_rank >= new_rank {
381388
return; // no change needed
382389
}
@@ -1053,7 +1060,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
10531060
}
10541061
}
10551062

1056-
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
1063+
fn process_extern_crate(&mut self, item: &ast::Item, definitions: &Definitions) -> CrateNum {
10571064
match item.node {
10581065
ast::ItemKind::ExternCrate(orig_name) => {
10591066
debug!("resolving extern crate stmt. ident: {} orig_name: {:?}",
@@ -1079,17 +1086,72 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
10791086

10801087
let def_id = definitions.opt_local_def_id(item.id).unwrap();
10811088
let path_len = definitions.def_path(def_id.index).data.len();
1082-
1083-
let extern_crate = ExternCrate { def_id, span: item.span, direct: true, path_len };
1084-
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
1089+
self.update_extern_crate(
1090+
cnum,
1091+
ExternCrate {
1092+
src: ExternCrateSource::Extern(def_id),
1093+
span: item.span,
1094+
path_len,
1095+
direct: true,
1096+
},
1097+
&mut FxHashSet(),
1098+
);
10851099
self.cstore.add_extern_mod_stmt_cnum(item.id, cnum);
1100+
cnum
10861101
}
1087-
_ => {}
1102+
_ => bug!(),
10881103
}
10891104
}
10901105

1091-
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum {
1092-
self.resolve_crate(&None, name, name, None, None, span, PathKind::Crate,
1093-
DepKind::Explicit).0
1106+
fn process_path_extern(
1107+
&mut self,
1108+
name: Symbol,
1109+
span: Span,
1110+
) -> CrateNum {
1111+
let cnum = self.resolve_crate(
1112+
&None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit
1113+
).0;
1114+
1115+
self.update_extern_crate(
1116+
cnum,
1117+
ExternCrate {
1118+
src: ExternCrateSource::Path,
1119+
span,
1120+
// to have the least priority in `update_extern_crate`
1121+
path_len: usize::max_value(),
1122+
direct: true,
1123+
},
1124+
&mut FxHashSet(),
1125+
);
1126+
1127+
cnum
1128+
}
1129+
1130+
fn process_use_extern(
1131+
&mut self,
1132+
name: Symbol,
1133+
span: Span,
1134+
id: ast::NodeId,
1135+
definitions: &Definitions,
1136+
) -> CrateNum {
1137+
let cnum = self.resolve_crate(
1138+
&None, name, name, None, None, span, PathKind::Crate, DepKind::Explicit
1139+
).0;
1140+
1141+
let def_id = definitions.opt_local_def_id(id).unwrap();
1142+
let path_len = definitions.def_path(def_id.index).data.len();
1143+
1144+
self.update_extern_crate(
1145+
cnum,
1146+
ExternCrate {
1147+
src: ExternCrateSource::Use,
1148+
span,
1149+
path_len,
1150+
direct: true,
1151+
},
1152+
&mut FxHashSet(),
1153+
);
1154+
1155+
cnum
10941156
}
10951157
}

src/librustc_resolve/build_reduced_graph.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,7 @@ impl<'a> Resolver<'a> {
252252
}
253253

254254
ItemKind::ExternCrate(orig_name) => {
255-
self.crate_loader.process_item(item, &self.definitions);
256-
257-
// n.b. we don't need to look at the path option here, because cstore already did
258-
let crate_id = self.cstore.extern_mod_stmt_cnum_untracked(item.id).unwrap();
255+
let crate_id = self.crate_loader.process_extern_crate(item, &self.definitions);
259256
let module =
260257
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
261258
self.populate_module_if_necessary(module);
@@ -302,7 +299,8 @@ impl<'a> Resolver<'a> {
302299
self.current_module = module;
303300
}
304301

305-
ItemKind::ForeignMod(..) => self.crate_loader.process_item(item, &self.definitions),
302+
// Handled in `rustc_metadata::{native_libs,link_args}`
303+
ItemKind::ForeignMod(..) => {}
306304

307305
// These items live in the value namespace.
308306
ItemKind::Static(_, m, _) => {

src/librustc_resolve/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3254,7 +3254,7 @@ impl<'a> Resolver<'a> {
32543254
prev_name == keywords::CrateRoot.name() &&
32553255
self.session.features_untracked().extern_absolute_paths {
32563256
// `::extern_crate::a::b`
3257-
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
3257+
let crate_id = self.crate_loader.process_path_extern(name, ident.span);
32583258
let crate_root =
32593259
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
32603260
self.populate_module_if_necessary(crate_root);

src/librustc_resolve/resolve_imports.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,12 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
627627
}
628628
} else if is_extern && !token::is_path_segment_keyword(source) {
629629
let crate_id =
630-
self.crate_loader.resolve_crate_from_path(source.name, directive.span);
630+
self.resolver.crate_loader.process_use_extern(
631+
source.name,
632+
directive.span,
633+
directive.id,
634+
&self.resolver.definitions,
635+
);
631636
let crate_root =
632637
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
633638
self.populate_module_if_necessary(crate_root);

src/librustc_save_analysis/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use rustc::hir;
4141
use rustc::hir::def::Def as HirDef;
4242
use rustc::hir::map::{Node, NodeItem};
4343
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
44+
use rustc::middle::cstore::ExternCrate;
4445
use rustc::session::config::CrateType::CrateTypeExecutable;
4546
use rustc::ty::{self, TyCtxt};
4647
use rustc_typeck::hir_ty_to_ty;
@@ -111,7 +112,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
111112

112113
for &n in self.tcx.crates().iter() {
113114
let span = match *self.tcx.extern_crate(n.as_def_id()) {
114-
Some(ref c) => c.span,
115+
Some(ExternCrate { span, .. }) => span,
115116
None => {
116117
debug!("Skipping crate {}, no data", n);
117118
continue;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
-include ../tools.mk
2+
3+
all: extern_absolute_paths.rs extern_in_paths.rs krate2
4+
$(RUSTC) extern_absolute_paths.rs -Zsave-analysis
5+
cat $(TMPDIR)/save-analysis/extern_absolute_paths.json | "$(PYTHON)" validate_json.py
6+
$(RUSTC) extern_in_paths.rs -Zsave-analysis
7+
cat $(TMPDIR)/save-analysis/extern_in_paths.json | "$(PYTHON)" validate_json.py
8+
9+
krate2: krate2.rs
10+
$(RUSTC) $<
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(extern_absolute_paths)]
12+
13+
use krate2::hello;
14+
15+
fn main() {
16+
hello();
17+
::krate2::hello();
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(extern_in_paths)]
12+
13+
use extern::krate2;
14+
15+
fn main() {
16+
extern::krate2::hello();
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_name = "krate2"]
12+
#![crate_type = "lib"]
13+
14+
pub fn hello() {
15+
}

0 commit comments

Comments
 (0)