Skip to content

Commit bbed61d

Browse files
committed
Extend ExternCrate to cover externs inferred from use or paths
1 parent 4b9b70c commit bbed61d

File tree

8 files changed

+173
-51
lines changed

8 files changed

+173
-51
lines changed

src/librustc/ich/impls_cstore.rs

+24-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! from rustc::middle::cstore in no particular order.
1313
1414
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult};
15+
use ich::StableHashingContext;
1516

1617
use middle;
1718

@@ -47,12 +48,32 @@ impl_stable_hash_for!(enum middle::cstore::LinkagePreference {
4748
});
4849

4950
impl_stable_hash_for!(struct middle::cstore::ExternCrate {
50-
def_id,
51+
src,
5152
span,
52-
direct,
53-
path_len
53+
direct
5454
});
5555

56+
impl<'a> HashStable<StableHashingContext<'a>> for middle::cstore::ExternCrateSource {
57+
fn hash_stable<W: StableHasherResult>(
58+
&self,
59+
hcx: &mut StableHashingContext<'a>,
60+
hasher: &mut StableHasher<W>,
61+
) {
62+
use middle::cstore::ExternCrateSource::*;
63+
64+
::std::mem::discriminant(self).hash_stable(hcx, hasher);
65+
66+
match *self {
67+
Extern { def_id, path_len } => {
68+
def_id.hash_stable(hcx, hasher);
69+
path_len.hash_stable(hcx, hasher);
70+
}
71+
Use { path_len } => path_len.hash_stable(hcx, hasher),
72+
Path => {}
73+
}
74+
}
75+
}
76+
5677
impl_stable_hash_for!(struct middle::cstore::CrateSource {
5778
dylib,
5879
rlib,

src/librustc/middle/cstore.rs

+38-10
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,7 @@ 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,
@@ -160,11 +157,28 @@ pub struct ExternCrate {
160157
/// crate referenced above. If false, then this crate is a dep
161158
/// of the crate.
162159
pub direct: bool,
160+
}
163161

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

170184
pub struct EncodedMetadata {
@@ -357,9 +371,23 @@ impl CrateStore for DummyCrateStore {
357371
}
358372

359373
pub trait CrateLoader {
360-
fn process_item(&mut self, item: &ast::Item, defs: &Definitions);
374+
fn process_extern_crate(&mut self, item: &ast::Item, defs: &Definitions) -> CrateNum;
375+
376+
fn process_path_extern(
377+
&mut self,
378+
name: Symbol,
379+
span: Span,
380+
) -> CrateNum;
381+
382+
fn process_use_extern(
383+
&mut self,
384+
name: Symbol,
385+
span: Span,
386+
id: ast::NodeId,
387+
defs: &Definitions,
388+
) -> CrateNum;
389+
361390
fn postprocess(&mut self, krate: &ast::Crate);
362-
fn resolve_crate_from_path(&mut self, name: Symbol, span: Span) -> CrateNum;
363391
}
364392

365393
// 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

+79-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;
@@ -367,16 +367,31 @@ impl<'a> CrateLoader<'a> {
367367
let cmeta = self.cstore.get_crate_data(cnum);
368368
let mut old_extern_crate = cmeta.extern_crate.borrow_mut();
369369

370+
fn path_len_reverse(src: ExternCrateSource) -> cmp::Reverse<usize> {
371+
cmp::Reverse(match src {
372+
ExternCrateSource::Extern { path_len, .. } |
373+
ExternCrateSource::Use { path_len } => path_len,
374+
_ => usize::max_value(),
375+
})
376+
}
377+
370378
// Prefer:
371379
// - something over nothing (tuple.0);
372380
// - direct extern crate to indirect (tuple.1);
373381
// - shorter paths to longer (tuple.2).
374-
let new_rank = (true, extern_crate.direct, !extern_crate.path_len);
382+
let new_rank = (
383+
true,
384+
extern_crate.direct,
385+
path_len_reverse(extern_crate.src),
386+
);
375387
let old_rank = match *old_extern_crate {
376-
None => (false, false, !0),
377-
Some(ref c) => (true, c.direct, !c.path_len),
388+
None => (false, false, cmp::Reverse(usize::max_value())),
389+
Some(ref c) => (
390+
true,
391+
c.direct,
392+
path_len_reverse(c.src),
393+
),
378394
};
379-
380395
if old_rank >= new_rank {
381396
return; // no change needed
382397
}
@@ -1045,7 +1060,7 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
10451060
}
10461061
}
10471062

1048-
fn process_item(&mut self, item: &ast::Item, definitions: &Definitions) {
1063+
fn process_extern_crate(&mut self, item: &ast::Item, definitions: &Definitions) -> CrateNum {
10491064
match item.node {
10501065
ast::ItemKind::ExternCrate(orig_name) => {
10511066
debug!("resolving extern crate stmt. ident: {} orig_name: {:?}",
@@ -1071,17 +1086,68 @@ impl<'a> middle::cstore::CrateLoader for CrateLoader<'a> {
10711086

10721087
let def_id = definitions.opt_local_def_id(item.id).unwrap();
10731088
let path_len = definitions.def_path(def_id.index).data.len();
1074-
1075-
let extern_crate = ExternCrate { def_id, span: item.span, direct: true, path_len };
1076-
self.update_extern_crate(cnum, extern_crate, &mut FxHashSet());
1089+
self.update_extern_crate(
1090+
cnum,
1091+
ExternCrate {
1092+
src: ExternCrateSource::Extern { def_id, path_len },
1093+
span: item.span,
1094+
direct: true,
1095+
},
1096+
&mut FxHashSet(),
1097+
);
10771098
self.cstore.add_extern_mod_stmt_cnum(item.id, cnum);
1099+
cnum
10781100
}
1079-
_ => {}
1101+
_ => bug!(),
10801102
}
10811103
}
10821104

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

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
@@ -3258,7 +3258,7 @@ impl<'a> Resolver<'a> {
32583258
prev_name == keywords::CrateRoot.name() &&
32593259
self.session.features_untracked().extern_absolute_paths {
32603260
// `::extern_crate::a::b`
3261-
let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
3261+
let crate_id = self.crate_loader.process_path_extern(name, ident.span);
32623262
let crate_root =
32633263
self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX });
32643264
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

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ use rustc::hir;
4242
use rustc::hir::def::Def as HirDef;
4343
use rustc::hir::map::{Node, NodeItem};
4444
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
45+
use rustc::middle::cstore::ExternCrate;
4546
use rustc::session::config::CrateType::CrateTypeExecutable;
4647
use rustc::ty::{self, TyCtxt};
4748
use rustc_typeck::hir_ty_to_ty;
@@ -112,10 +113,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
112113

113114
for &n in self.tcx.crates().iter() {
114115
let span = match *self.tcx.extern_crate(n.as_def_id()) {
115-
Some(ref c) => c.span,
116+
Some(ExternCrate { span, .. }) => span,
116117
None => {
117-
debug!("Skipping crate {}, no data", n);
118-
continue;
118+
bug!("no data for crate {}", n);
119119
}
120120
};
121121
let lo_loc = self.span_utils.sess.codemap().lookup_char_pos(span.lo());

0 commit comments

Comments
 (0)