From 1642fdfea0ba60f4e142e5d767491ab7686cd13b Mon Sep 17 00:00:00 2001
From: pierwill <pierwill@users.noreply.github.com>
Date: Sun, 31 Oct 2021 17:05:48 -0500
Subject: [PATCH] Add `-Zassert-incr-state` to assert state of incremental
 cache

---
 .../rustc_incremental/src/persist/load.rs     | 24 +++++++++++++-
 compiler/rustc_interface/src/tests.rs         |  1 +
 compiler/rustc_session/src/config.rs          | 32 +++++++++++++++++++
 compiler/rustc_session/src/options.rs         |  5 ++-
 .../link_order/auxiliary/my_lib.rs            |  4 +--
 .../incremental/struct_change_field_name.rs   |  1 +
 6 files changed, 63 insertions(+), 4 deletions(-)

diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index 5f5e83774dad8..9c6e2aeb50a76 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -6,6 +6,7 @@ use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
 use rustc_middle::ty::OnDiskCache;
 use rustc_serialize::opaque::Decoder;
 use rustc_serialize::Decodable;
+use rustc_session::config::IncrementalStateAssertion;
 use rustc_session::Session;
 use std::path::Path;
 
@@ -16,6 +17,7 @@ use super::work_product;
 
 type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
 
+#[derive(Debug)]
 pub enum LoadResult<T> {
     Ok { data: T },
     DataOutOfDate,
@@ -24,6 +26,26 @@ pub enum LoadResult<T> {
 
 impl<T: Default> LoadResult<T> {
     pub fn open(self, sess: &Session) -> T {
+        // Check for errors when using `-Zassert-incremental-state`
+        match (sess.opts.assert_incr_state, &self) {
+            (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
+                sess.fatal(
+                    "We asserted that the incremental cache should not be loaded, \
+                         but it was loaded.",
+                );
+            }
+            (
+                Some(IncrementalStateAssertion::Loaded),
+                LoadResult::Error { .. } | LoadResult::DataOutOfDate,
+            ) => {
+                sess.fatal(
+                    "We asserted that an existing incremental cache directory should \
+                         be successfully loaded, but it was not.",
+                );
+            }
+            _ => {}
+        };
+
         match self {
             LoadResult::Error { message } => {
                 sess.warn(&message);
@@ -33,7 +55,7 @@ impl<T: Default> LoadResult<T> {
                 if let Err(err) = delete_all_session_dir_contents(sess) {
                     sess.err(&format!(
                         "Failed to delete invalidated or incompatible \
-                                      incremental compilation session directory contents `{}`: {}.",
+                         incremental compilation session directory contents `{}`: {}.",
                         dep_graph_path(sess).display(),
                         err
                     ));
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index eed2e07e890e7..10c049f01263b 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -635,6 +635,7 @@ fn test_debugging_options_tracking_hash() {
 
     // Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
     // This list is in alphabetical order.
+    untracked!(assert_incr_state, Some(String::from("loaded")));
     untracked!(ast_json, true);
     untracked!(ast_json_noexpand, true);
     untracked!(borrowck, String::from("other"));
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 3afe094733928..f6f1d0e4b3678 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -165,6 +165,18 @@ pub enum LinkerPluginLto {
     Disabled,
 }
 
+/// Used with `-Z assert-incr-state`.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum IncrementalStateAssertion {
+    /// Found and loaded an existing session directory.
+    ///
+    /// Note that this says nothing about whether any particular query
+    /// will be found to be red or green.
+    Loaded,
+    /// Did not load an existing session directory.
+    NotLoaded,
+}
+
 impl LinkerPluginLto {
     pub fn enabled(&self) -> bool {
         match *self {
@@ -704,6 +716,7 @@ pub fn host_triple() -> &'static str {
 impl Default for Options {
     fn default() -> Options {
         Options {
+            assert_incr_state: None,
             crate_types: Vec::new(),
             optimize: OptLevel::No,
             debuginfo: DebugInfo::None,
@@ -1626,6 +1639,21 @@ fn select_debuginfo(
     }
 }
 
+crate fn parse_assert_incr_state(
+    opt_assertion: &Option<String>,
+    error_format: ErrorOutputType,
+) -> Option<IncrementalStateAssertion> {
+    match opt_assertion {
+        Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
+        Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
+        Some(s) => early_error(
+            error_format,
+            &format!("unexpected incremental state assertion value: {}", s),
+        ),
+        None => None,
+    }
+}
+
 fn parse_native_lib_kind(
     matches: &getopts::Matches,
     kind: &str,
@@ -2015,6 +2043,9 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
 
     let incremental = cg.incremental.as_ref().map(PathBuf::from);
 
+    let assert_incr_state =
+        parse_assert_incr_state(&debugging_opts.assert_incr_state, error_format);
+
     if debugging_opts.profile && incremental.is_some() {
         early_error(
             error_format,
@@ -2179,6 +2210,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
     };
 
     Options {
+        assert_incr_state,
         crate_types,
         optimize: opt_level,
         debuginfo,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index d1d8606a75a45..c85ea9e812efe 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -4,7 +4,6 @@ use crate::early_error;
 use crate::lint;
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
-
 use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy, SanitizerSet};
 use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
 
@@ -150,6 +149,7 @@ top_level_options!(
         /// If `Some`, enable incremental compilation, using the given
         /// directory to store intermediate results.
         incremental: Option<PathBuf> [UNTRACKED],
+        assert_incr_state: Option<IncrementalStateAssertion> [UNTRACKED],
 
         debugging_opts: DebuggingOptions [SUBSTRUCT],
         prints: Vec<PrintRequest> [UNTRACKED],
@@ -1042,6 +1042,9 @@ options! {
         "make cfg(version) treat the current version as incomplete (default: no)"),
     asm_comments: bool = (false, parse_bool, [TRACKED],
         "generate comments into the assembly (may change behavior) (default: no)"),
+    assert_incr_state: Option<String> = (None, parse_opt_string, [UNTRACKED],
+        "assert that the incremental cache is in given state: \
+         either `loaded` or `not-loaded`."),
     ast_json: bool = (false, parse_bool, [UNTRACKED],
         "print the AST as JSON and halt (default: no)"),
     ast_json_noexpand: bool = (false, parse_bool, [UNTRACKED],
diff --git a/src/test/incremental/link_order/auxiliary/my_lib.rs b/src/test/incremental/link_order/auxiliary/my_lib.rs
index 57cde5f7c6e48..1e7d823050c3d 100644
--- a/src/test/incremental/link_order/auxiliary/my_lib.rs
+++ b/src/test/incremental/link_order/auxiliary/my_lib.rs
@@ -1,3 +1,3 @@
 // no-prefer-dynamic
-//[cfail1] compile-flags: -lbar -lfoo --crate-type lib
-//[cfail2] compile-flags: -lfoo -lbar --crate-type lib
+//[cfail1] compile-flags: -lbar -lfoo --crate-type lib -Zassert-incr-state=not-loaded
+//[cfail2] compile-flags: -lfoo -lbar --crate-type lib -Zassert-incr-state=not-loaded
diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs
index 7498d0305e0b1..a7c79e9d751e0 100644
--- a/src/test/incremental/struct_change_field_name.rs
+++ b/src/test/incremental/struct_change_field_name.rs
@@ -3,6 +3,7 @@
 
 // revisions:rpass1 cfail2
 // compile-flags: -Z query-dep-graph
+// [cfail2] compile-flags: -Z query-dep-graph -Z assert-incr-state=loaded
 
 #![feature(rustc_attrs)]