Skip to content

Commit 2a84449

Browse files
committed
allow testing DepNode::Krate edges directly
1 parent 753590f commit 2a84449

File tree

2 files changed

+78
-92
lines changed

2 files changed

+78
-92
lines changed

src/librustc_incremental/assert_dep_graph.rs

Lines changed: 71 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,20 @@
2626
//! used to check when paths exist or do not.
2727
//!
2828
//! The full form of the `rustc_if_this_changed` annotation is
29-
//! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and
30-
//! defaults to `"id"` if omitted.
29+
//! `#[rustc_if_this_changed("foo")]`, which will report a
30+
//! source node of `foo(def_id)`. The `"foo"` is optional and
31+
//! defaults to `"Hir"` if omitted.
3132
//!
3233
//! Example:
3334
//!
3435
//! ```
35-
//! #[rustc_if_this_changed]
36+
//! #[rustc_if_this_changed(Hir)]
3637
//! fn foo() { }
3738
//!
38-
//! #[rustc_then_this_would_need("trans")] //~ ERROR no path from `foo`
39+
//! #[rustc_then_this_would_need(trans)] //~ ERROR no path from `foo`
3940
//! fn bar() { }
4041
//!
41-
//! #[rustc_then_this_would_need("trans")] //~ ERROR OK
42+
//! #[rustc_then_this_would_need(trans)] //~ ERROR OK
4243
//! fn baz() { foo(); }
4344
//! ```
4445
@@ -47,7 +48,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode};
4748
use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter};
4849
use rustc::hir::def_id::DefId;
4950
use rustc::ty::TyCtxt;
50-
use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
51+
use rustc_data_structures::fnv::FnvHashSet;
5152
use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex};
5253
use rustc::hir;
5354
use rustc::hir::intravisit::Visitor;
@@ -61,7 +62,6 @@ use syntax_pos::Span;
6162

6263
const IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
6364
const THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
64-
const ID: &'static str = "id";
6565

6666
pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
6767
let _ignore = tcx.dep_graph.in_ignore();
@@ -80,8 +80,9 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
8080
// Find annotations supplied by user (if any).
8181
let (if_this_changed, then_this_would_need) = {
8282
let mut visitor = IfThisChanged { tcx: tcx,
83-
if_this_changed: FnvHashMap(),
84-
then_this_would_need: FnvHashMap() };
83+
if_this_changed: vec![],
84+
then_this_would_need: vec![] };
85+
visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs);
8586
tcx.map.krate().visit_all_items(&mut visitor);
8687
(visitor.if_this_changed, visitor.then_this_would_need)
8788
};
@@ -97,58 +98,51 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
9798
check_paths(tcx, &if_this_changed, &then_this_would_need);
9899
}
99100

100-
type SourceHashMap =
101-
FnvHashMap<InternedString,
102-
FnvHashSet<(Span, DefId, DepNode<DefId>)>>;
103-
type TargetHashMap =
104-
FnvHashMap<InternedString,
105-
FnvHashSet<(Span, InternedString, ast::NodeId, DepNode<DefId>)>>;
101+
type Sources = Vec<(Span, DefId, DepNode<DefId>)>;
102+
type Targets = Vec<(Span, InternedString, ast::NodeId, DepNode<DefId>)>;
106103

107104
struct IfThisChanged<'a, 'tcx:'a> {
108105
tcx: TyCtxt<'a, 'tcx, 'tcx>,
109-
if_this_changed: SourceHashMap,
110-
then_this_would_need: TargetHashMap,
106+
if_this_changed: Sources,
107+
then_this_would_need: Targets,
111108
}
112109

113110
impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
114-
fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) {
115-
for attr in self.tcx.get_attrs(def_id).iter() {
111+
fn argument(&self, attr: &ast::Attribute) -> Option<InternedString> {
112+
let mut value = None;
113+
for list_item in attr.meta_item_list().unwrap_or_default() {
114+
match list_item.word() {
115+
Some(word) if value.is_none() =>
116+
value = Some(word.name().clone()),
117+
_ =>
118+
// FIXME better-encapsulate meta_item (don't directly access `node`)
119+
span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node),
120+
}
121+
}
122+
value
123+
}
124+
125+
fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) {
126+
let def_id = self.tcx.map.local_def_id(node_id);
127+
for attr in attrs {
116128
if attr.check_name(IF_THIS_CHANGED) {
117-
let mut id = None;
118-
for list_item in attr.meta_item_list().unwrap_or_default() {
119-
match list_item.word() {
120-
Some(word) if id.is_none() => {
121-
id = Some(word.name().clone())
122-
},
123-
_ => {
124-
// FIXME better-encapsulate meta_item (don't directly access `node`)
125-
span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node)
129+
let dep_node_interned = self.argument(attr);
130+
let dep_node = match dep_node_interned {
131+
None => DepNode::Hir(def_id),
132+
Some(ref n) => {
133+
match DepNode::from_label_string(&n[..], def_id) {
134+
Ok(n) => n,
135+
Err(()) => {
136+
self.tcx.sess.span_fatal(
137+
attr.span,
138+
&format!("unrecognized DepNode variant {:?}", n));
139+
}
126140
}
127141
}
128-
}
129-
130-
let id = id.unwrap_or(InternedString::new(ID));
131-
self.if_this_changed.entry(id)
132-
.or_insert(FnvHashSet())
133-
.insert((attr.span, def_id, DepNode::Hir(def_id)));
142+
};
143+
self.if_this_changed.push((attr.span, def_id, dep_node));
134144
} else if attr.check_name(THEN_THIS_WOULD_NEED) {
135-
let mut dep_node_interned = None;
136-
let mut id = None;
137-
for list_item in attr.meta_item_list().unwrap_or_default() {
138-
match list_item.word() {
139-
Some(word) if dep_node_interned.is_none() => {
140-
dep_node_interned = Some(word.name().clone());
141-
},
142-
Some(word) if id.is_none() => {
143-
id = Some(word.name().clone())
144-
},
145-
_ => {
146-
// FIXME better-encapsulate meta_item (don't directly access `node`)
147-
span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node)
148-
}
149-
}
150-
}
151-
145+
let dep_node_interned = self.argument(attr);
152146
let dep_node = match dep_node_interned {
153147
Some(ref n) => {
154148
match DepNode::from_label_string(&n[..], def_id) {
@@ -166,59 +160,49 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> {
166160
&format!("missing DepNode variant"));
167161
}
168162
};
169-
let id = id.unwrap_or(InternedString::new(ID));
170-
self.then_this_would_need
171-
.entry(id)
172-
.or_insert(FnvHashSet())
173-
.insert((attr.span, dep_node_interned.clone().unwrap(), node_id, dep_node));
163+
self.then_this_would_need.push((attr.span,
164+
dep_node_interned.clone().unwrap(),
165+
node_id,
166+
dep_node));
174167
}
175168
}
176169
}
177170
}
178171

179172
impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> {
180173
fn visit_item(&mut self, item: &'tcx hir::Item) {
181-
let def_id = self.tcx.map.local_def_id(item.id);
182-
self.process_attrs(item.id, def_id);
174+
self.process_attrs(item.id, &item.attrs);
183175
}
184176
}
185177

186178
fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
187-
if_this_changed: &SourceHashMap,
188-
then_this_would_need: &TargetHashMap)
179+
if_this_changed: &Sources,
180+
then_this_would_need: &Targets)
189181
{
190182
// Return early here so as not to construct the query, which is not cheap.
191183
if if_this_changed.is_empty() {
184+
for &(target_span, _, _, _) in then_this_would_need {
185+
tcx.sess.span_err(
186+
target_span,
187+
&format!("no #[rustc_if_this_changed] annotation detected"));
188+
189+
}
192190
return;
193191
}
194192
let query = tcx.dep_graph.query();
195-
for (id, sources) in if_this_changed {
196-
let targets = match then_this_would_need.get(id) {
197-
Some(targets) => targets,
198-
None => {
199-
for &(source_span, ..) in sources.iter().take(1) {
200-
tcx.sess.span_err(
201-
source_span,
202-
&format!("no targets for id `{}`", id));
203-
}
204-
continue;
205-
}
206-
};
207-
208-
for &(_, source_def_id, ref source_dep_node) in sources {
209-
let dependents = query.transitive_successors(source_dep_node);
210-
for &(target_span, ref target_pass, _, ref target_dep_node) in targets {
211-
if !dependents.contains(&target_dep_node) {
212-
tcx.sess.span_err(
213-
target_span,
214-
&format!("no path from `{}` to `{}`",
215-
tcx.item_path_str(source_def_id),
216-
target_pass));
217-
} else {
218-
tcx.sess.span_err(
219-
target_span,
220-
&format!("OK"));
221-
}
193+
for &(_, source_def_id, ref source_dep_node) in if_this_changed {
194+
let dependents = query.transitive_successors(source_dep_node);
195+
for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
196+
if !dependents.contains(&target_dep_node) {
197+
tcx.sess.span_err(
198+
target_span,
199+
&format!("no path from `{}` to `{}`",
200+
tcx.item_path_str(source_def_id),
201+
target_pass));
202+
} else {
203+
tcx.sess.span_err(
204+
target_span,
205+
&format!("OK"));
222206
}
223207
}
224208
}

src/test/incremental/krate-inlined.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,24 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// revisions: rpass1 rpass2
11+
// Regr. test that using HIR inlined from another krate does *not* add
12+
// a dependency from the local Krate node.
13+
14+
// revisions: cfail1
1215
// compile-flags: -Z query-dep-graph
1316

1417
#![allow(warnings)]
1518
#![feature(rustc_attrs)]
16-
#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")]
19+
20+
#![rustc_if_this_changed(Krate)]
1721

1822
fn main() { }
1923

2024
mod x {
25+
#[rustc_then_this_would_need(TransCrateItem)] //[cfail1]~ ERROR no path
2126
fn method() {
2227
// use some methods that require inlining HIR from another crate:
2328
let mut v = vec![];
2429
v.push(1);
2530
}
2631
}
27-
28-
#[cfg(rpass1)]
29-
fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method`

0 commit comments

Comments
 (0)