Skip to content

Commit b5f0149

Browse files
committed
---
yaml --- r: 276934 b: refs/heads/try c: 3fb40c1 h: refs/heads/master
1 parent baed8ca commit b5f0149

File tree

11 files changed

+743
-1
lines changed

11 files changed

+743
-1
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: 6dbb0e86aec11050480beb76eade6fb805010ba7
33
refs/heads/snap-stage3: 235d77457d80b549dad3ac36d94f235208a1eafb
4-
refs/heads/try: d8263c4758e8821d87d4fc300fd30e78457c769f
4+
refs/heads/try: 3fb40c1d95dd3a14ad14d71e3ec847a0a102bd49
55
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
66
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
77
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try/src/librustc_driver/driver.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
829829
index,
830830
name,
831831
|tcx| {
832+
time(time_passes,
833+
"load_dep_graph",
834+
|| rustc_incremental::load_dep_graph(tcx));
835+
832836
// passes are timed inside typeck
833837
try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis));
834838

@@ -962,6 +966,10 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
962966
"assert dep graph",
963967
move || rustc_incremental::assert_dep_graph(tcx));
964968

969+
time(time_passes,
970+
"serialize dep graph",
971+
move || rustc_incremental::save_dep_graph(tcx));
972+
965973
translation
966974
}
967975

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
//! The data that we will serialize and deserialize.
12+
13+
use rustc::dep_graph::DepNode;
14+
use rustc_serialize::{Decoder as RustcDecoder,
15+
Encodable as RustcEncodable, Encoder as RustcEncoder};
16+
17+
use super::directory::DefPathIndex;
18+
19+
#[derive(Debug, RustcEncodable, RustcDecodable)]
20+
pub struct SerializedDepGraph {
21+
pub nodes: Vec<DepNode<DefPathIndex>>,
22+
pub edges: Vec<SerializedEdge>,
23+
pub hashes: Vec<SerializedHash>,
24+
}
25+
26+
pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>);
27+
28+
#[derive(Debug, RustcEncodable, RustcDecodable)]
29+
pub struct SerializedHash {
30+
pub index: DefPathIndex,
31+
32+
/// the hash itself, computed by `calculate_item_hash`
33+
pub hash: u64,
34+
}
35+
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
//! Code to convert a DefId into a DefPath (when serializing) and then
12+
//! back again (when deserializing). Note that the new DefId
13+
//! necessarily will not be the same as the old (and of course the
14+
//! item might even be removed in the meantime).
15+
16+
use rustc::dep_graph::DepNode;
17+
use rustc::front::map::DefPath;
18+
use rustc::middle::def_id::DefId;
19+
use rustc::ty;
20+
use rustc::util::nodemap::DefIdMap;
21+
use rustc_serialize::{Decoder as RustcDecoder,
22+
Encodable as RustcEncodable, Encoder as RustcEncoder};
23+
use std::fmt::{self, Debug};
24+
25+
/// Index into the DefIdDirectory
26+
#[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq,
27+
RustcEncodable, RustcDecodable)]
28+
pub struct DefPathIndex {
29+
index: u32
30+
}
31+
32+
#[derive(RustcEncodable, RustcDecodable)]
33+
pub struct DefIdDirectory {
34+
// N.B. don't use Removable here because these def-ids are loaded
35+
// directly without remapping, so loading them should not fail.
36+
paths: Vec<DefPath>
37+
}
38+
39+
impl DefIdDirectory {
40+
pub fn new() -> DefIdDirectory {
41+
DefIdDirectory { paths: vec![] }
42+
}
43+
44+
pub fn retrace(&self, tcx: &ty::TyCtxt) -> RetracedDefIdDirectory {
45+
let ids = self.paths.iter()
46+
.map(|path| tcx.map.retrace_path(path))
47+
.collect();
48+
RetracedDefIdDirectory { ids: ids }
49+
}
50+
}
51+
52+
#[derive(Debug, RustcEncodable, RustcDecodable)]
53+
pub struct RetracedDefIdDirectory {
54+
ids: Vec<Option<DefId>>
55+
}
56+
57+
impl RetracedDefIdDirectory {
58+
pub fn def_id(&self, index: DefPathIndex) -> Option<DefId> {
59+
self.ids[index.index as usize]
60+
}
61+
62+
pub fn map(&self, node: DepNode<DefPathIndex>) -> Option<DepNode<DefId>> {
63+
node.map_def(|&index| self.def_id(index))
64+
}
65+
}
66+
67+
pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
68+
tcx: &'a ty::TyCtxt<'tcx>,
69+
hash: DefIdMap<Option<DefPathIndex>>,
70+
directory: DefIdDirectory,
71+
}
72+
73+
impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
74+
pub fn new(tcx: &'a ty::TyCtxt<'tcx>) -> DefIdDirectoryBuilder<'a, 'tcx> {
75+
DefIdDirectoryBuilder {
76+
tcx: tcx,
77+
hash: DefIdMap(),
78+
directory: DefIdDirectory::new()
79+
}
80+
}
81+
82+
pub fn add(&mut self, def_id: DefId) -> Option<DefPathIndex> {
83+
if !def_id.is_local() {
84+
// FIXME(#32015) clarify story about cross-crate dep tracking
85+
return None;
86+
}
87+
88+
let tcx = self.tcx;
89+
let paths = &mut self.directory.paths;
90+
self.hash.entry(def_id)
91+
.or_insert_with(|| {
92+
let def_path = tcx.def_path(def_id);
93+
if !def_path.is_local() {
94+
return None;
95+
}
96+
let index = paths.len() as u32;
97+
paths.push(def_path);
98+
Some(DefPathIndex { index: index })
99+
})
100+
.clone()
101+
}
102+
103+
pub fn map(&mut self, node: DepNode<DefId>) -> Option<DepNode<DefPathIndex>> {
104+
node.map_def(|&def_id| self.add(def_id))
105+
}
106+
107+
pub fn into_directory(self) -> DefIdDirectory {
108+
self.directory
109+
}
110+
}
111+
112+
impl Debug for DefIdDirectory {
113+
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
114+
fmt.debug_list()
115+
.entries(self.paths.iter().enumerate())
116+
.finish()
117+
}
118+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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+
//! Debugging code to test the state of the dependency graph just
12+
//! after it is loaded from disk. For each node marked with
13+
//! `#[rustc_clean]` or `#[rustc_dirty]`, we will check that a
14+
//! suitable node for that item either appears or does not appear in
15+
//! the dep-graph, as appropriate:
16+
//!
17+
//! - `#[rustc_dirty(label="TypeckItemBody", cfg="rev2")]` if we are
18+
//! in `#[cfg(rev2)]`, then there MUST NOT be a node
19+
//! `DepNode::TypeckItemBody(X)` where `X` is the def-id of the
20+
//! current node.
21+
//! - `#[rustc_clean(label="TypeckItemBody", cfg="rev2")]` same as above,
22+
//! except that the node MUST exist.
23+
//!
24+
//! Errors are reported if we are in the suitable configuration but
25+
//! the required condition is not met.
26+
27+
use rustc::dep_graph::{DepGraphQuery, DepNode};
28+
use rustc::middle::def_id::DefId;
29+
use rustc_front::hir;
30+
use rustc_front::intravisit::Visitor;
31+
use syntax::ast::{self, Attribute, MetaItem};
32+
use syntax::attr::AttrMetaMethods;
33+
use syntax::parse::token::InternedString;
34+
use rustc::ty;
35+
36+
const DIRTY: &'static str = "rustc_dirty";
37+
const CLEAN: &'static str = "rustc_clean";
38+
const LABEL: &'static str = "label";
39+
const CFG: &'static str = "cfg";
40+
41+
pub fn check_dirty_clean_annotations(tcx: &ty::TyCtxt) {
42+
let _ignore = tcx.dep_graph.in_ignore();
43+
let query = tcx.dep_graph.query();
44+
let krate = tcx.map.krate();
45+
krate.visit_all_items(&mut DirtyCleanVisitor {
46+
tcx: tcx,
47+
query: &query,
48+
});
49+
}
50+
51+
pub struct DirtyCleanVisitor<'a, 'tcx:'a> {
52+
tcx: &'a ty::TyCtxt<'tcx>,
53+
query: &'a DepGraphQuery<DefId>,
54+
}
55+
56+
impl<'a, 'tcx> DirtyCleanVisitor<'a, 'tcx> {
57+
fn expect_associated_value(&self, item: &MetaItem) -> InternedString {
58+
if let Some(value) = item.value_str() {
59+
value
60+
} else {
61+
self.tcx.sess.span_fatal(
62+
item.span,
63+
&format!("associated value expected for `{}`", item.name()));
64+
}
65+
}
66+
67+
/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan
68+
/// for a `cfg="foo"` attribute and check whether we have a cfg
69+
/// flag called `foo`.
70+
fn check_config(&self, attr: &ast::Attribute) -> bool {
71+
debug!("check_config(attr={:?})", attr);
72+
let config = &self.tcx.map.krate().config;
73+
debug!("check_config: config={:?}", config);
74+
for item in attr.meta_item_list().unwrap_or(&[]) {
75+
if item.check_name(CFG) {
76+
let value = self.expect_associated_value(item);
77+
debug!("check_config: searching for cfg {:?}", value);
78+
for cfg in &config[..] {
79+
if cfg.check_name(&value[..]) {
80+
debug!("check_config: matched {:?}", cfg);
81+
return true;
82+
}
83+
}
84+
}
85+
}
86+
debug!("check_config: no match found");
87+
return false;
88+
}
89+
90+
fn dep_node(&self, attr: &Attribute, def_id: DefId) -> DepNode<DefId> {
91+
for item in attr.meta_item_list().unwrap_or(&[]) {
92+
if item.check_name(LABEL) {
93+
let value = self.expect_associated_value(item);
94+
match DepNode::from_label_string(&value[..], def_id) {
95+
Ok(def_id) => return def_id,
96+
Err(()) => {
97+
self.tcx.sess.span_fatal(
98+
item.span,
99+
&format!("dep-node label `{}` not recognized", value));
100+
}
101+
}
102+
}
103+
}
104+
105+
self.tcx.sess.span_fatal(attr.span, "no `label` found");
106+
}
107+
108+
fn dep_node_str(&self, dep_node: DepNode<DefId>) -> DepNode<String> {
109+
dep_node.map_def(|&def_id| Some(self.tcx.item_path_str(def_id))).unwrap()
110+
}
111+
112+
fn assert_dirty(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
113+
debug!("assert_dirty({:?})", dep_node);
114+
115+
if self.query.contains_node(&dep_node) {
116+
let dep_node_str = self.dep_node_str(dep_node);
117+
self.tcx.sess.span_err(
118+
item.span,
119+
&format!("`{:?}` found in dep graph, but should be dirty", dep_node_str));
120+
}
121+
}
122+
123+
fn assert_clean(&self, item: &hir::Item, dep_node: DepNode<DefId>) {
124+
debug!("assert_clean({:?})", dep_node);
125+
126+
if !self.query.contains_node(&dep_node) {
127+
let dep_node_str = self.dep_node_str(dep_node);
128+
self.tcx.sess.span_err(
129+
item.span,
130+
&format!("`{:?}` not found in dep graph, but should be clean", dep_node_str));
131+
}
132+
}
133+
}
134+
135+
impl<'a, 'tcx> Visitor<'tcx> for DirtyCleanVisitor<'a, 'tcx> {
136+
fn visit_item(&mut self, item: &'tcx hir::Item) {
137+
let def_id = self.tcx.map.local_def_id(item.id);
138+
for attr in self.tcx.get_attrs(def_id).iter() {
139+
if attr.check_name(DIRTY) {
140+
if self.check_config(attr) {
141+
self.assert_dirty(item, self.dep_node(attr, def_id));
142+
}
143+
} else if attr.check_name(CLEAN) {
144+
if self.check_config(attr) {
145+
self.assert_clean(item, self.dep_node(attr, def_id));
146+
}
147+
}
148+
}
149+
}
150+
}
151+

0 commit comments

Comments
 (0)