diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs index 60f24b71de245..673f1ae10843c 100644 --- a/src/librustc_incremental/persist/data.rs +++ b/src/librustc_incremental/persist/data.rs @@ -23,6 +23,11 @@ use super::directory::DefPathIndex; pub struct SerializedDepGraph { pub edges: Vec, + /// These are output nodes that have no incoming edges. We track + /// these separately so that when we reload all edges, we don't + /// lose track of these nodes. + pub bootstrap_outputs: Vec>, + /// These are hashes of two things: /// - the HIR nodes in this crate /// - the metadata nodes from dependent crates we use diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 7724658a9d6fe..03411e01a5798 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -184,6 +184,18 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } + // Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot + // be dirty). + for bootstrap_output in &serialized_dep_graph.bootstrap_outputs { + if let Some(n) = retraced.map(bootstrap_output) { + if let DepNode::WorkProduct(ref wp) = n { + clean_work_products.insert(wp.clone()); + } + + tcx.dep_graph.with_task(n, || ()); // create the node with no inputs + } + } + // Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph. // This is pretty unusual but it arises in a scenario like this: // diff --git a/src/librustc_incremental/persist/preds/mod.rs b/src/librustc_incremental/persist/preds/mod.rs index a80620fbde66f..f6a37c7a12265 100644 --- a/src/librustc_incremental/persist/preds/mod.rs +++ b/src/librustc_incremental/persist/preds/mod.rs @@ -11,7 +11,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::hir::def_id::DefId; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::Graph; +use rustc_data_structures::graph::{Graph, NodeIndex}; use super::hash::*; use ich::Fingerprint; @@ -28,6 +28,14 @@ pub struct Predecessors<'query> { // of the graph down. pub reduced_graph: Graph<&'query DepNode, ()>, + // These are output nodes that have no incoming edges. We have to + // track these specially because, when we load the data back up + // again, we want to make sure and recreate these nodes (we want + // to recreate the nodes where all incoming edges are clean; but + // since we ordinarily just serialize edges, we wind up just + // forgetting that bootstrap outputs even exist in that case.) + pub bootstrap_outputs: Vec<&'query DepNode>, + // For the inputs (hir/foreign-metadata), we include hashes. pub hashes: FxHashMap<&'query DepNode, Fingerprint>, } @@ -57,7 +65,7 @@ impl<'q> Predecessors<'q> { // Reduce the graph to the most important nodes. let compress::Reduction { graph, input_nodes } = - compress::reduce_graph(&query.graph, HashContext::is_hashable, is_output); + compress::reduce_graph(&query.graph, HashContext::is_hashable, |n| is_output(n)); let mut hashes = FxHashMap(); for input_index in input_nodes { @@ -67,8 +75,17 @@ impl<'q> Predecessors<'q> { .or_insert_with(|| hcx.hash(input).unwrap()); } + let bootstrap_outputs: Vec<&'q DepNode> = + (0 .. graph.len_nodes()) + .map(NodeIndex) + .filter(|&n| graph.incoming_edges(n).next().is_none()) + .map(|n| *graph.node_data(n)) + .filter(|n| is_output(n)) + .collect(); + Predecessors { reduced_graph: graph, + bootstrap_outputs: bootstrap_outputs, hashes: hashes, } } diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 34bb125ef3f45..dfa6bf6bbb5e7 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -204,11 +204,15 @@ pub fn encode_dep_graph(preds: &Predecessors, } // Create the serialized dep-graph. + let bootstrap_outputs = preds.bootstrap_outputs.iter() + .map(|n| builder.map(n)) + .collect(); let edges = edges.into_iter() .map(|(k, v)| SerializedEdgeSet { source: k, targets: v }) .collect(); let graph = SerializedDepGraph { - edges: edges, + bootstrap_outputs, + edges, hashes: preds.hashes .iter() .map(|(&dep_node, &hash)| { @@ -221,6 +225,7 @@ pub fn encode_dep_graph(preds: &Predecessors, }; if tcx.sess.opts.debugging_opts.incremental_info { + println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes()); println!("incremental: {} edges in serialized dep-graph", graph.edges.len()); println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len()); } diff --git a/src/test/incremental/issue-39828/auxiliary/generic.rs b/src/test/incremental/issue-39828/auxiliary/generic.rs new file mode 100644 index 0000000000000..a562eab1768f3 --- /dev/null +++ b/src/test/incremental/issue-39828/auxiliary/generic.rs @@ -0,0 +1,18 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions:rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")] +#![feature(rustc_attrs)] + +#![crate_type="rlib"] +pub fn foo() { } diff --git a/src/test/incremental/issue-39828/issue-39828.rs b/src/test/incremental/issue-39828/issue-39828.rs new file mode 100644 index 0000000000000..c729380bd5a31 --- /dev/null +++ b/src/test/incremental/issue-39828/issue-39828.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for #39828. If you make use of a module that +// consists only of generics, no code is generated, just a dummy +// module. The reduced graph consists of a single node (for that +// module) with no inputs. Since we only serialize edges, when we +// reload, we would consider that node dirty since it is not recreated +// (it is not the target of any edges). + +// revisions:rpass1 rpass2 +// aux-build:generic.rs + +extern crate generic; +fn main() { }