Skip to content

Commit b4929d1

Browse files
committed
watch out for krate numbers being reassigned
The biggest problem, actually, is krate numbers being removed entirely, which can lead to array-index-out-of-bounds errors. cc #35123 -- not a complete fix, since really we ought to "map" the old crate numbers to the new ones, not just detect changes.
1 parent c56eb4b commit b4929d1

File tree

3 files changed

+117
-5
lines changed

3 files changed

+117
-5
lines changed

src/librustc_incremental/persist/directory.rs

+73-5
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
use rustc::dep_graph::DepNode;
1717
use rustc::hir::map::DefPath;
1818
use rustc::hir::def_id::DefId;
19+
use rustc::middle::cstore::LOCAL_CRATE;
1920
use rustc::ty::TyCtxt;
2021
use rustc::util::nodemap::DefIdMap;
2122
use std::fmt::{self, Debug};
23+
use std::iter::once;
24+
use syntax::ast;
2225

2326
/// Index into the DefIdDirectory
2427
#[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
@@ -31,17 +34,66 @@ pub struct DefPathIndex {
3134
pub struct DefIdDirectory {
3235
// N.B. don't use Removable here because these def-ids are loaded
3336
// directly without remapping, so loading them should not fail.
34-
paths: Vec<DefPath>
37+
paths: Vec<DefPath>,
38+
39+
// For each crate, saves the crate-name/disambiguator so that
40+
// later we can match crate-numbers up again.
41+
krates: Vec<KrateInfo>,
42+
}
43+
44+
#[derive(Debug, RustcEncodable, RustcDecodable)]
45+
pub struct KrateInfo {
46+
krate: ast::CrateNum,
47+
name: String,
48+
disambiguator: String,
3549
}
3650

3751
impl DefIdDirectory {
38-
pub fn new() -> DefIdDirectory {
39-
DefIdDirectory { paths: vec![] }
52+
pub fn new(krates: Vec<KrateInfo>) -> DefIdDirectory {
53+
DefIdDirectory { paths: vec![], krates: krates }
54+
}
55+
56+
pub fn krate_still_valid(&self,
57+
tcx: TyCtxt,
58+
max_current_crate: ast::CrateNum,
59+
krate: ast::CrateNum) -> bool {
60+
// Check that the crate-number still matches. For now, if it
61+
// doesn't, just return None. We could do better, such as
62+
// finding the new number.
63+
64+
if krate > max_current_crate {
65+
false
66+
} else {
67+
let old_info = &self.krates[krate as usize];
68+
assert_eq!(old_info.krate, krate);
69+
let old_name: &str = &old_info.name;
70+
let old_disambiguator: &str = &old_info.disambiguator;
71+
let new_name: &str = &tcx.crate_name(krate);
72+
let new_disambiguator: &str = &tcx.crate_disambiguator(krate);
73+
old_name == new_name && old_disambiguator == new_disambiguator
74+
}
4075
}
4176

4277
pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
78+
let max_current_crate =
79+
tcx.sess.cstore.crates()
80+
.into_iter()
81+
.max()
82+
.unwrap_or(LOCAL_CRATE);
83+
4384
let ids = self.paths.iter()
44-
.map(|path| tcx.retrace_path(path))
85+
.map(|path| {
86+
if self.krate_still_valid(tcx, max_current_crate, path.krate) {
87+
tcx.retrace_path(path)
88+
} else {
89+
debug!("crate {} changed from {:?} to {:?}/{:?}",
90+
path.krate,
91+
self.krates[path.krate as usize],
92+
tcx.crate_name(path.krate),
93+
tcx.crate_disambiguator(path.krate));
94+
None
95+
}
96+
})
4597
.collect();
4698
RetracedDefIdDirectory { ids: ids }
4799
}
@@ -70,10 +122,26 @@ pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
70122

71123
impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
72124
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> DefIdDirectoryBuilder<'a, 'tcx> {
125+
let mut krates: Vec<_> =
126+
once(LOCAL_CRATE)
127+
.chain(tcx.sess.cstore.crates())
128+
.map(|krate| {
129+
KrateInfo {
130+
krate: krate,
131+
name: tcx.crate_name(krate).to_string(),
132+
disambiguator: tcx.crate_disambiguator(krate).to_string()
133+
}
134+
})
135+
.collect();
136+
137+
// the result of crates() is not in order, so sort list of
138+
// crates so that we can just index it later
139+
krates.sort_by_key(|k| k.krate);
140+
73141
DefIdDirectoryBuilder {
74142
tcx: tcx,
75143
hash: DefIdMap(),
76-
directory: DefIdDirectory::new()
144+
directory: DefIdDirectory::new(krates),
77145
}
78146
}
79147

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2014 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_type="rlib"]
12+
13+
pub type X = u32;
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2014 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+
// aux-build:a.rs
12+
// revisions:rpass1 rpass2
13+
14+
#![feature(rustc_attrs)]
15+
16+
#[cfg(rpass1)]
17+
extern crate a;
18+
19+
#[cfg(rpass1)]
20+
pub fn use_X() -> u32 {
21+
let x: a::X = 22;
22+
x as u32
23+
}
24+
25+
#[cfg(rpass2)]
26+
pub fn use_X() -> u32 {
27+
22
28+
}
29+
30+
pub fn main() { }

0 commit comments

Comments
 (0)