about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2024-06-09 14:13:01 +0000
committer许杰友 Jieyou Xu (Joe) <jieyouxu@outlook.com>2024-06-11 08:21:10 +0000
commita3feeb3afe075898e4112baa90d948ef57ce4401 (patch)
treeb533d9e3d7cc8ccf43170b2e91666e140b6fdf89
parent7255c2825df1b6497dea1d689173a62ea872244f (diff)
downloadrust-a3feeb3afe075898e4112baa90d948ef57ce4401.tar.gz
rust-a3feeb3afe075898e4112baa90d948ef57ce4401.zip
run-make-support: add drop bomb module
-rw-r--r--src/tools/run-make-support/src/drop_bomb/mod.rs50
-rw-r--r--src/tools/run-make-support/src/drop_bomb/tests.rs15
-rw-r--r--src/tools/run-make-support/src/lib.rs1
3 files changed, 66 insertions, 0 deletions
diff --git a/src/tools/run-make-support/src/drop_bomb/mod.rs b/src/tools/run-make-support/src/drop_bomb/mod.rs
new file mode 100644
index 00000000000..2fc84892c1b
--- /dev/null
+++ b/src/tools/run-make-support/src/drop_bomb/mod.rs
@@ -0,0 +1,50 @@
+//! This module implements "drop bombs" intended for use by command wrappers to ensure that the
+//! constructed commands are *eventually* executed. This is exactly like `rustc_errors::Diag` where
+//! we force every `Diag` to be consumed or we emit a bug, but we panic instead.
+//!
+//! This is adapted from <https://docs.rs/drop_bomb/latest/drop_bomb/> and simplified for our
+//! purposes.
+
+use std::ffi::{OsStr, OsString};
+use std::panic;
+
+#[cfg(test)]
+mod tests;
+
+#[derive(Debug)]
+pub(crate) struct DropBomb {
+    command: OsString,
+    defused: bool,
+    armed_line: u32,
+}
+
+impl DropBomb {
+    /// Arm a [`DropBomb`]. If the value is dropped without being [`defused`][Self::defused], then
+    /// it will panic. It is expected that the command wrapper uses `#[track_caller]` to help
+    /// propagate the caller info from rmake.rs.
+    #[track_caller]
+    pub(crate) fn arm<S: AsRef<OsStr>>(command: S) -> DropBomb {
+        DropBomb {
+            command: command.as_ref().into(),
+            defused: false,
+            armed_line: panic::Location::caller().line(),
+        }
+    }
+
+    /// Defuse the [`DropBomb`]. This will prevent the drop bomb from panicking when dropped.
+    pub(crate) fn defuse(&mut self) {
+        self.defused = true;
+    }
+}
+
+impl Drop for DropBomb {
+    fn drop(&mut self) {
+        if !self.defused && !std::thread::panicking() {
+            panic!(
+                "command constructed but not executed at line {}: `{}`",
+                self.armed_line,
+                self.command.to_string_lossy()
+            )
+        }
+    }
+}
diff --git a/src/tools/run-make-support/src/drop_bomb/tests.rs b/src/tools/run-make-support/src/drop_bomb/tests.rs
new file mode 100644
index 00000000000..4a488c0f670
--- /dev/null
+++ b/src/tools/run-make-support/src/drop_bomb/tests.rs
@@ -0,0 +1,15 @@
+use super::DropBomb;
+
+#[test]
+#[should_panic]
+fn test_arm() {
+    let bomb = DropBomb::arm("hi :3");
+    drop(bomb); // <- armed bomb should explode when not defused
+}
+
+#[test]
+fn test_defuse() {
+    let mut bomb = DropBomb::arm("hi :3");
+    bomb.defuse();
+    drop(bomb); // <- defused bomb should not explode
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 93e41b593d1..20ad25efaf0 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -7,6 +7,7 @@ pub mod cc;
 pub mod clang;
 mod command;
 pub mod diff;
+mod drop_bomb;
 pub mod llvm_readobj;
 pub mod run;
 pub mod rustc;