From 02a47032dda473e6d8fa9da969bf157c48fba6dd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Aug 2016 20:14:47 -0400 Subject: [PATCH] use preds to serialize just what we need This massively speeds up serialization. It also seems to produce deterministic metadata hashes (before I was seeing inconsistent results). Fixes #35232. --- src/librustc_incremental/persist/data.rs | 16 +- src/librustc_incremental/persist/load.rs | 191 +++++++----------- src/librustc_incremental/persist/save.rs | 166 +++++++-------- .../callee_caller_cross_crate/b.rs | 1 + src/test/incremental/dirty_clean.rs | 1 + src/test/incremental/hello_world.rs | 1 + src/test/incremental/rlib_cross_crate/b.rs | 2 +- src/test/incremental/spike.rs | 5 - src/test/incremental/string_constant.rs | 1 + src/test/incremental/struct_add_field.rs | 1 + .../incremental/struct_change_field_name.rs | 1 + .../incremental/struct_change_field_type.rs | 1 + .../struct_change_field_type_cross_crate/b.rs | 1 + src/test/incremental/struct_change_nothing.rs | 1 + src/test/incremental/struct_remove_field.rs | 1 + .../incremental/type_alias_cross_crate/b.rs | 1 + 16 files changed, 177 insertions(+), 214 deletions(-) diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 95e9a16f29b..12f3ed8ae2b 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -19,7 +19,6 @@ use super::directory::DefPathIndex; /// Data for use when recompiling the **current crate**. #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedDepGraph { - pub nodes: Vec>, pub edges: Vec, /// These are hashes of two things: @@ -44,15 +43,22 @@ pub struct SerializedDepGraph { pub hashes: Vec, } +/// Represents a "reduced" dependency edge. Unlike the full dep-graph, +/// the dep-graph we serialize contains only edges `S -> T` where the +/// source `S` is something hashable (a HIR node or foreign metadata) +/// and the target `T` is something significant, like a work-product. +/// Normally, significant nodes are only those that have saved data on +/// disk, but in unit-testing the set of significant nodes can be +/// increased. pub type SerializedEdge = (DepNode, DepNode); #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct SerializedHash { - /// node being hashed; either a Hir or MetaData variant, in - /// practice - pub node: DepNode, + /// def-id of thing being hashed + pub dep_node: DepNode, - /// the hash itself, computed by `calculate_item_hash` + /// the hash as of previous compilation, computed by code in + /// `hash` module pub hash: u64, } diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 793a0466c31..b704af12a6d 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -28,7 +28,7 @@ use super::dirty_clean; use super::hash::*; use super::util::*; -type DirtyNodes = FnvHashSet>; +type DirtyNodes = FnvHashSet>; type CleanEdges = Vec<(DepNode, DepNode)>; @@ -110,157 +110,106 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Retrace the paths in the directory to find their current location (if any). let retraced = directory.retrace(tcx); - // Compute the set of Hir nodes whose data has changed. - let mut dirty_nodes = - initial_dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced); + // TODO -- this could be more efficient if we integrated the `DefIdDirectory` and + // pred set more deeply - debug!("decode_dep_graph: initial dirty_nodes = {:#?}", dirty_nodes); + // Compute the set of Hir nodes whose data has changed or which have been removed. + let dirty_raw_source_nodes = dirty_nodes(tcx, &serialized_dep_graph.hashes, &retraced); - // Find all DepNodes reachable from that core set. This loop - // iterates repeatedly over the list of edges whose source is not - // known to be dirty (`clean_edges`). If it finds an edge whose - // source is dirty, it removes it from that list and adds the - // target to `dirty_nodes`. It stops when it reaches a fixed - // point. - let clean_edges = compute_clean_edges(tcx, - &directory, - &serialized_dep_graph.edges, - &retraced, - &mut dirty_nodes); + // Create a (maybe smaller) list of + let retraced_edges: Vec<_> = + serialized_dep_graph.edges.iter() + .filter_map(|&(ref raw_source_node, ref raw_target_node)| { + retraced.map(raw_target_node) + .map(|target_node| (raw_source_node, target_node)) + }) + .collect(); - // Add synthetic `foo->foo` edges for each clean node `foo` that - // we had before. This is sort of a hack to create clean nodes in - // the graph, since the existence of a node is a signal that the - // work it represents need not be repeated. - let clean_nodes = - serialized_dep_graph.nodes - .iter() - .filter_map(|node| retraced.map(node)) - .filter(|node| !dirty_nodes.contains(node)) - .map(|node| (node.clone(), node)); + // Compute which work-products have changed. + let mut dirty_target_nodes = FnvHashSet(); + for &(raw_source_node, ref target_node) in &retraced_edges { + if dirty_raw_source_nodes.contains(raw_source_node) { + if !dirty_target_nodes.contains(target_node) { + dirty_target_nodes.insert(target_node.clone()); - // Add nodes and edges that are not dirty into our main graph. + if tcx.sess.opts.debugging_opts.incremental_info { + // It'd be nice to pretty-print these paths better than just + // using the `Debug` impls, but wev. + println!("module {:?} is dirty because {:?} changed or was removed", + target_node, + raw_source_node.map_def(|&index| { + Some(directory.def_path_string(tcx, index)) + }).unwrap()); + } + } + } + } + + // For work-products that are still clean, add their deps into the + // graph. This is needed because later we will have to save this + // back out again! let dep_graph = tcx.dep_graph.clone(); - for (source, target) in clean_edges.into_iter().chain(clean_nodes) { - debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source, target); + for (raw_source_node, target_node) in retraced_edges { + if dirty_target_nodes.contains(&target_node) { + continue; + } - let _task = dep_graph.in_task(target); - dep_graph.read(source); + let source_node = retraced.map(raw_source_node).unwrap(); + + debug!("decode_dep_graph: clean edge: {:?} -> {:?}", source_node, target_node); + + let _task = dep_graph.in_task(target_node); + dep_graph.read(source_node); } // Add in work-products that are still clean, and delete those that are // dirty. let mut work_product_decoder = Decoder::new(work_products_data, 0); let work_products = try!(>::decode(&mut work_product_decoder)); - reconcile_work_products(tcx, work_products, &dirty_nodes); + reconcile_work_products(tcx, work_products, &dirty_target_nodes); Ok(()) } -fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - hashes: &[SerializedHash], - retraced: &RetracedDefIdDirectory) - -> DirtyNodes { +/// Computes which of the original set of def-ids are dirty. Stored in +/// a bit vector where the index is the DefPathIndex. +fn dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + hashes: &[SerializedHash], + retraced: &RetracedDefIdDirectory) + -> DirtyNodes { let mut hcx = HashContext::new(tcx); - let mut items_removed = false; let mut dirty_nodes = FnvHashSet(); - for hash in hashes { - match hash.node.map_def(|&i| retraced.def_id(i)) { - Some(dep_node) => { - let (_, current_hash) = hcx.hash(&dep_node).unwrap(); - if current_hash != hash.hash { - debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", - dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), - current_hash, - hash.hash); - dirty_nodes.insert(dep_node); - } - } - None => { - items_removed = true; - } - } - } - // If any of the items in the krate have changed, then we consider - // the meta-node `Krate` to be dirty, since that means something - // which (potentially) read the contents of every single item. - if items_removed || !dirty_nodes.is_empty() { - dirty_nodes.insert(DepNode::Krate); + for hash in hashes { + if let Some(dep_node) = retraced.map(&hash.dep_node) { + let (_, current_hash) = hcx.hash(&dep_node).unwrap(); + if current_hash == hash.hash { + continue; + } + debug!("initial_dirty_nodes: {:?} is dirty as hash is {:?}, was {:?}", + dep_node.map_def(|&def_id| Some(tcx.def_path(def_id))).unwrap(), + current_hash, + hash.hash); + } else { + debug!("initial_dirty_nodes: {:?} is dirty as it was removed", + hash.dep_node); + } + + dirty_nodes.insert(hash.dep_node.clone()); } dirty_nodes } -fn compute_clean_edges(tcx: TyCtxt, - directory: &DefIdDirectory, - serialized_edges: &[(SerializedEdge)], - retraced: &RetracedDefIdDirectory, - dirty_nodes: &mut DirtyNodes) - -> CleanEdges { - // Build up an initial list of edges. Include an edge (source, - // target) if neither node has been removed. If the source has - // been removed, add target to the list of dirty nodes. - let mut clean_edges = Vec::with_capacity(serialized_edges.len()); - for &(ref serialized_source, ref serialized_target) in serialized_edges { - if let Some(target) = retraced.map(serialized_target) { - if let Some(source) = retraced.map(serialized_source) { - clean_edges.push((source, target)) - } else { - // source removed, target must be dirty - debug!("compute_clean_edges: {:?} dirty because {:?} no longer exists", - target, - serialized_source.map_def(|&index| { - Some(directory.def_path_string(tcx, index)) - }).unwrap()); - - dirty_nodes.insert(target); - } - } else { - // target removed, ignore the edge - } - } - - debug!("compute_clean_edges: dirty_nodes={:#?}", dirty_nodes); - - // Propagate dirty marks by iterating repeatedly over - // `clean_edges`. If we find an edge `(source, target)` where - // `source` is dirty, add `target` to the list of dirty nodes and - // remove it. Keep doing this until we find no more dirty nodes. - let mut previous_size = 0; - while dirty_nodes.len() > previous_size { - debug!("compute_clean_edges: previous_size={}", previous_size); - previous_size = dirty_nodes.len(); - let mut i = 0; - while i < clean_edges.len() { - if dirty_nodes.contains(&clean_edges[i].0) { - let (source, target) = clean_edges.swap_remove(i); - debug!("compute_clean_edges: dirty source {:?} -> {:?}", - source, target); - dirty_nodes.insert(target); - } else if dirty_nodes.contains(&clean_edges[i].1) { - let (source, target) = clean_edges.swap_remove(i); - debug!("compute_clean_edges: dirty target {:?} -> {:?}", - source, target); - } else { - i += 1; - } - } - } - - clean_edges -} - /// Go through the list of work-products produced in the previous run. /// Delete any whose nodes have been found to be dirty or which are /// otherwise no longer applicable. fn reconcile_work_products<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, work_products: Vec, - dirty_nodes: &DirtyNodes) { + dirty_target_nodes: &FnvHashSet>) { debug!("reconcile_work_products({:?})", work_products); for swp in work_products { - let dep_node = DepNode::WorkProduct(swp.id.clone()); - if dirty_nodes.contains(&dep_node) { + if dirty_target_nodes.contains(&DepNode::WorkProduct(swp.id.clone())) { debug!("reconcile_work_products: dep-node for {:?} is dirty", swp); delete_dirty_work_product(tcx, swp); } else { diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index e71204dd839..049702a0451 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -9,11 +9,12 @@ // except according to those terms. use rbml::opaque::Encoder; -use rustc::dep_graph::{DepGraphQuery, DepNode}; +use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::middle::cstore::LOCAL_CRATE; use rustc::session::Session; use rustc::ty::TyCtxt; +use rustc_data_structures::fnv::FnvHashMap; use rustc_serialize::Encodable as RustcEncodable; use std::hash::{Hash, Hasher, SipHasher}; use std::io::{self, Cursor, Write}; @@ -23,6 +24,7 @@ use std::path::PathBuf; use super::data::*; use super::directory::*; use super::hash::*; +use super::preds::*; use super::util::*; pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { @@ -35,12 +37,13 @@ pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let mut hcx = HashContext::new(tcx); let mut builder = DefIdDirectoryBuilder::new(tcx); let query = tcx.dep_graph.query(); + let preds = Predecessors::new(&query, &mut hcx); save_in(sess, dep_graph_path(tcx), - |e| encode_dep_graph(&mut hcx, &mut builder, &query, e)); + |e| encode_dep_graph(&preds, &mut builder, e)); save_in(sess, metadata_hash_path(tcx, LOCAL_CRATE), - |e| encode_metadata_hashes(&mut hcx, &mut builder, &query, e)); + |e| encode_metadata_hashes(tcx, &preds, &mut builder, e)); } pub fn save_work_products(sess: &Session, local_crate_name: &str) { @@ -98,38 +101,37 @@ fn save_in(sess: &Session, opt_path_buf: Option, encode: F) } } -pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, - builder: &mut DefIdDirectoryBuilder, - query: &DepGraphQuery, - encoder: &mut Encoder) - -> io::Result<()> { - let (nodes, edges) = (query.nodes(), query.edges()); - - // Create hashes for inputs. - let hashes = nodes.iter() - .filter_map(|dep_node| { - hcx.hash(dep_node) - .map(|(_, hash)| { - let node = builder.map(dep_node); - SerializedHash { - node: node, - hash: hash, - } - }) - }) - .collect(); +pub fn encode_dep_graph(preds: &Predecessors, + builder: &mut DefIdDirectoryBuilder, + encoder: &mut Encoder) + -> io::Result<()> { + // Create a flat list of (Input, WorkProduct) edges for + // serialization. + let mut edges = vec![]; + for (&target, sources) in &preds.inputs { + match *target { + DepNode::MetaData(_) => continue, // see encode_metadata_hashes instead + _ => (), + } + let target = builder.map(target); + for &source in sources { + let source = builder.map(source); + edges.push((source, target.clone())); + } + } // Create the serialized dep-graph. let graph = SerializedDepGraph { - nodes: nodes.iter().map(|node| builder.map(node)).collect(), - edges: edges.iter() - .map(|&(ref source_node, ref target_node)| { - let source = builder.map(source_node); - let target = builder.map(target_node); - (source, target) + edges: edges, + hashes: preds.hashes + .iter() + .map(|(&dep_node, &hash)| { + SerializedHash { + dep_node: builder.map(dep_node), + hash: hash, + } }) .collect(), - hashes: hashes, }; debug!("graph = {:#?}", graph); @@ -141,24 +143,37 @@ pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, Ok(()) } -pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, - builder: &mut DefIdDirectoryBuilder, - query: &DepGraphQuery, - encoder: &mut Encoder) - -> io::Result<()> { - let tcx = hcx.tcx; +pub fn encode_metadata_hashes(tcx: TyCtxt, + preds: &Predecessors, + builder: &mut DefIdDirectoryBuilder, + encoder: &mut Encoder) + -> io::Result<()> { + let mut def_id_hashes = FnvHashMap(); + let mut def_id_hash = |def_id: DefId| -> u64 { + *def_id_hashes.entry(def_id) + .or_insert_with(|| { + let index = builder.add(def_id); + let path = builder.lookup_def_path(index); + path.deterministic_hash(tcx) + }) + }; - let serialized_hashes = { - // Identify the `MetaData(X)` nodes where `X` is local. These are - // the metadata items we export. Downstream crates will want to - // see a hash that tells them whether we might have changed the - // metadata for a given item since they last compiled. - let meta_data_def_ids = query.nodes() - .into_iter() - .filter_map(|dep_node| match *dep_node { - DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id), - _ => None, - }); + // For each `MetaData(X)` node where `X` is local, accumulate a + // hash. These are the metadata items we export. Downstream + // crates will want to see a hash that tells them whether we might + // have changed the metadata for a given item since they last + // compiled. + // + // (I initially wrote this with an iterator, but it seemed harder to read.) + let mut serialized_hashes = SerializedMetadataHashes { hashes: vec![] }; + for (&target, sources) in &preds.inputs { + let def_id = match *target { + DepNode::MetaData(def_id) => { + assert!(def_id.is_local()); + def_id + } + _ => continue, + }; // To create the hash for each item `X`, we don't hash the raw // bytes of the metadata (though in principle we @@ -166,45 +181,32 @@ pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>, // from the dep-graph. This corresponds to all the inputs that // were read to construct the metadata. To create the hash for // the metadata, we hash (the hash of) all of those inputs. - let hashes = meta_data_def_ids.map(|def_id| { - assert!(def_id.is_local()); - let dep_node = DepNode::MetaData(def_id); - let mut state = SipHasher::new(); - debug!("save: computing metadata hash for {:?}", dep_node); + debug!("save: computing metadata hash for {:?}", def_id); - let predecessors = query.transitive_predecessors(&dep_node); - let mut hashes: Vec<_> = predecessors.iter() - .filter_map(|node| hcx.hash(&node)) - .map(|(def_id, hash)| { - let index = builder.add(def_id); - let path = builder.lookup_def_path(index); - (path.to_string(tcx), hash) // (*) - }) - .collect(); + // Create a vector containing a pair of (source-id, hash). + // The source-id is stored as a `DepNode`, where the u64 + // is the det. hash of the def-path. This is convenient + // because we can sort this to get a table ordering across + // compilations, even if the def-ids themselves have changed. + let mut hashes: Vec<(DepNode, u64)> = sources.iter() + .map(|dep_node| { + let hash_dep_node = dep_node.map_def(|&def_id| Some(def_id_hash(def_id))).unwrap(); + let hash = preds.hashes[dep_node]; + (hash_dep_node, hash) + }) + .collect(); - // (*) creating a `String` from each def-path is a bit inefficient, - // but it's the easiest way to get a deterministic ord/hash. + hashes.sort(); + let mut state = SipHasher::new(); + hashes.hash(&mut state); + let hash = state.finish(); - hashes.sort(); - state.write_usize(hashes.len()); - for (path, hash) in hashes { - debug!("save: predecessor {:?} has hash {}", path, hash); - path.hash(&mut state); - state.write_u64(hash.to_le()); - } - - let hash = state.finish(); - debug!("save: metadata hash for {:?} is {}", dep_node, hash); - - SerializedMetadataHash { - def_index: def_id.index, - hash: hash, - } + debug!("save: metadata hash for {:?} is {}", def_id, hash); + serialized_hashes.hashes.push(SerializedMetadataHash { + def_index: def_id.index, + hash: hash, }); - - // Collect these up into a vector. - SerializedMetadataHashes { hashes: hashes.collect() } - }; + } // Encode everything. try!(serialized_hashes.encode(encoder)); diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs index e81f828beb1..e8b187b5454 100644 --- a/src/test/incremental/callee_caller_cross_crate/b.rs +++ b/src/test/incremental/callee_caller_cross_crate/b.rs @@ -10,6 +10,7 @@ // aux-build:a.rs // revisions:rpass1 rpass2 +// compile-flags:-Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 9a3097831c5..64b7f2951d2 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -9,6 +9,7 @@ // except according to those terms. // revisions: rpass1 cfail2 +// compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs index f98ae188bad..a06c25ac055 100644 --- a/src/test/incremental/hello_world.rs +++ b/src/test/incremental/hello_world.rs @@ -9,6 +9,7 @@ // except according to those terms. // revisions: rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs index 55398370425..21b654bdf58 100644 --- a/src/test/incremental/rlib_cross_crate/b.rs +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -16,7 +16,7 @@ // aux-build:a.rs // revisions:rpass1 rpass2 rpass3 // no-prefer-dynamic - +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/spike.rs b/src/test/incremental/spike.rs index 68af20d4191..257699cd3fc 100644 --- a/src/test/incremental/spike.rs +++ b/src/test/incremental/spike.rs @@ -35,14 +35,10 @@ mod x { X { x: 11, y: 11 } } - #[rustc_dirty(label="TypeckItemBody", cfg="rpass2")] - #[rustc_clean(label="ItemSignature", cfg="rpass2")] pub fn new() -> X { make() } - #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] - #[rustc_clean(label="ItemSignature", cfg="rpass2")] pub fn sum(x: &X) -> u32 { x.x + x.y } @@ -51,7 +47,6 @@ mod x { mod y { use x; - #[rustc_clean(label="TypeckItemBody", cfg="rpass2")] pub fn assert_sum() -> bool { let x = x::new(); x::sum(&x) == 22 diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 0aa728b94dd..f4062169256 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -9,6 +9,7 @@ // except according to those terms. // revisions: rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] diff --git a/src/test/incremental/struct_add_field.rs b/src/test/incremental/struct_add_field.rs index cc8ef8aedd7..da1b32cd73d 100644 --- a/src/test/incremental/struct_add_field.rs +++ b/src/test/incremental/struct_add_field.rs @@ -12,6 +12,7 @@ // in between revisions (hashing should be stable). // revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index fe29ad66b5f..ba469c62002 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -12,6 +12,7 @@ // in between revisions (hashing should be stable). // revisions:rpass1 cfail2 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/struct_change_field_type.rs b/src/test/incremental/struct_change_field_type.rs index 1a50d515db6..65f3b1b4f36 100644 --- a/src/test/incremental/struct_change_field_type.rs +++ b/src/test/incremental/struct_change_field_type.rs @@ -12,6 +12,7 @@ // in between revisions (hashing should be stable). // revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/struct_change_field_type_cross_crate/b.rs b/src/test/incremental/struct_change_field_type_cross_crate/b.rs index 7a4900d1d9a..95e15d0b7f9 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/b.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/b.rs @@ -10,6 +10,7 @@ // aux-build:a.rs // revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/struct_change_nothing.rs b/src/test/incremental/struct_change_nothing.rs index 8095e1ecd84..2bc636153f7 100644 --- a/src/test/incremental/struct_change_nothing.rs +++ b/src/test/incremental/struct_change_nothing.rs @@ -12,6 +12,7 @@ // in between revisions (hashing should be stable). // revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/struct_remove_field.rs b/src/test/incremental/struct_remove_field.rs index ae6399463b8..a7ed79d1a5a 100644 --- a/src/test/incremental/struct_remove_field.rs +++ b/src/test/incremental/struct_remove_field.rs @@ -12,6 +12,7 @@ // in between revisions (hashing should be stable). // revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs index c5421fcbf5c..09d4db33198 100644 --- a/src/test/incremental/type_alias_cross_crate/b.rs +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -10,6 +10,7 @@ // aux-build:a.rs // revisions:rpass1 rpass2 rpass3 +// compile-flags: -Z query-dep-graph #![feature(rustc_attrs)]