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 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>(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;