about summary refs log tree commit diff
diff options
context:
space:
mode:
-rwxr-xr-xsrc/tools/miri/ci.sh21
-rwxr-xr-xsrc/tools/miri/miri11
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs7
-rw-r--r--src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs183
-rw-r--r--src/tools/miri/src/diagnostics.rs17
-rw-r--r--src/tools/miri/src/helpers.rs6
-rw-r--r--src/tools/miri/tests/compiletest.rs14
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs8
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr15
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs (renamed from src/tools/miri/tests/fail/intrinsics/overflowing-unchecked-rsh.rs)0
-rw-r--r--src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr (renamed from src/tools/miri/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr)4
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr6
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/error-range.stderr14
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr2
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr6
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr6
-rw-r--r--src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr2
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs2
19 files changed, 218 insertions, 108 deletions
diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh
index b5b3b211b05..a8aae524e71 100755
--- a/src/tools/miri/ci.sh
+++ b/src/tools/miri/ci.sh
@@ -17,11 +17,11 @@ begingroup "Building Miri"
 echo "Installing release version of Miri"
 export RUSTFLAGS="-D warnings"
 export CARGO_INCREMENTAL=0
-./miri install # implicitly locked
+export CARGO_EXTRA_FLAGS="--locked"
+./miri install
 
 # Prepare debug build for direct `./miri` invocations
 echo "Building debug version of Miri"
-export CARGO_EXTRA_FLAGS="--locked"
 ./miri check --no-default-features # make sure this can be built
 ./miri check --all-features # and this, too
 ./miri build --all-targets # the build that all the `./miri test` below will use
@@ -39,8 +39,11 @@ function run_tests {
   ## ui test suite
   ./miri test
   if [ -z "${MIRI_TEST_TARGET+exists}" ]; then
-    # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR
-    # optimizations up all the way, too).
+    # Host-only tests: running these on all targets is unlikely to catch more problems and would
+    # cost a lot of CI time.
+
+    # Tests with optimizations (`-O` is what cargo passes, but crank MIR optimizations up all the
+    # way, too).
     # Optimizations change diagnostics (mostly backtraces), so we don't check
     # them. Also error locations change so we don't run the failing tests.
     # We explicitly enable debug-assertions here, they are disabled by -O but we have tests
@@ -51,6 +54,9 @@ function run_tests {
     for FILE in tests/many-seeds/*.rs; do
       MIRI_SEEDS=64 CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS -q" ./miri many-seeds ./miri run "$FILE"
     done
+
+    # Check that the benchmarks build and run, but without actually benchmarking.
+    HYPERFINE="bash -c" ./miri bench
   fi
 
   ## test-cargo-miri
@@ -75,13 +81,6 @@ function run_tests {
   unset RUSTC MIRI
   rm -rf .cargo
 
-  # Ensure that our benchmarks all work, but only on Linux hosts.
-  if [ -z "${MIRI_TEST_TARGET+exists}" ] && [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ] ; then
-    for BENCH in $(ls "bench-cargo-miri"); do
-      cargo miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml
-    done
-  fi
-
   endgroup
 }
 
diff --git a/src/tools/miri/miri b/src/tools/miri/miri
index 48a46a76a12..7cda995879c 100755
--- a/src/tools/miri/miri
+++ b/src/tools/miri/miri
@@ -77,7 +77,7 @@ if [ -z "$COMMAND" ]; then
 fi
 shift
 # macOS does not have a useful readlink/realpath so we have to use Python instead...
-MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0")
+MIRIDIR=$(python3 -c 'import pathlib, sys; print(pathlib.Path(sys.argv[1]).resolve().parent.as_posix())' "$0")
 # Used for rustc syncs.
 JOSH_FILTER=":rev(75dd959a3a40eb5b4574f8d2e23aa6efbeb33573:prefix=src/tools/miri):/src/tools/miri"
 # Needed for `./miri bench`.
@@ -184,6 +184,8 @@ many-seeds)
     exit 0
     ;;
 bench)
+    # The hyperfine to use
+    HYPERFINE=${HYPERFINE:-hyperfine -w 1 -m 5 --shell=none}
     # Make sure we have an up-to-date Miri installed
     "$0" install
     # Run the requested benchmarks
@@ -193,7 +195,7 @@ bench)
         BENCHES=("$@")
     fi
     for BENCH in "${BENCHES[@]}"; do
-        hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml"
+        $HYPERFINE "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml"
     done
     exit 0
     ;;
@@ -280,10 +282,9 @@ find_sysroot() {
 # Run command.
 case "$COMMAND" in
 install)
-    # "--locked" to respect the Cargo.lock file if it exists.
     # Install binaries to the miri toolchain's sysroot so they do not interact with other toolchains.
-    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --root "$SYSROOT" "$@"
-    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --root "$SYSROOT" "$@"
+    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --root "$SYSROOT" "$@"
+    $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --root "$SYSROOT" "$@"
     ;;
 check)
     # Check, and let caller control flags.
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 0bff100dc14..ee815ae6f8f 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-8b4b20836b832e91aa605a2faf5e2a55190202c8
+33c3d101280c8eb3cd8af421bfb56a8afcc3881d
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index 10873c46a6c..cea2cffa913 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -92,7 +92,7 @@ impl HistoryData {
         {
             // NOTE: `transition_range` is explicitly absent from the error message, it has no significance
             // to the user. The meaningful one is `access_range`.
-            self.events.push((Some(span.data()), format!("{this} then transitioned {transition} due to a {rel} {access_kind} at offsets {access_range:?}", rel = if is_foreign { "foreign" } else { "child" })));
+            self.events.push((Some(span.data()), format!("{this} later transitioned to {endpoint} due to a {rel} {access_kind} at offsets {access_range:?}", endpoint = transition.endpoint(), rel = if is_foreign { "foreign" } else { "child" })));
             self.events.push((None, format!("this corresponds to {}", transition.summary())));
         }
     }
@@ -212,12 +212,13 @@ impl History {
 
     /// Reconstruct the history relevant to `error_offset` by filtering
     /// only events whose range contains the offset we are interested in.
-    fn extract_relevant(&self, error_offset: u64) -> Self {
+    fn extract_relevant(&self, error_offset: u64, error_kind: TransitionError) -> Self {
         History {
             events: self
                 .events
                 .iter()
                 .filter(|e| e.transition_range.contains(&error_offset))
+                .filter(|e| e.transition.is_relevant(error_kind))
                 .cloned()
                 .collect::<Vec<_>>(),
             created: self.created,
@@ -303,7 +304,7 @@ impl TbError<'_> {
             history.extend(self.accessed_info.history.forget(), "accessed", false);
         }
         history.extend(
-            self.conflicting_info.history.extract_relevant(self.error_offset),
+            self.conflicting_info.history.extract_relevant(self.error_offset, self.error_kind),
             conflicting_tag_name,
             true,
         );
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index 7e3e587db72..6b1e722b65e 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -1,6 +1,7 @@
 use std::cmp::{Ordering, PartialOrd};
 use std::fmt;
 
+use crate::borrow_tracker::tree_borrows::diagnostics::TransitionError;
 use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness;
 use crate::borrow_tracker::AccessKind;
 
@@ -115,26 +116,31 @@ mod transition {
 /// Public interface to the state machine that controls read-write permissions.
 /// This is the "private `enum`" pattern.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct Permission(PermissionPriv);
+pub struct Permission {
+    inner: PermissionPriv,
+}
 
 /// Transition from one permission to the next.
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub struct PermTransition(PermissionPriv, PermissionPriv);
+pub struct PermTransition {
+    from: PermissionPriv,
+    to: PermissionPriv,
+}
 
 impl Permission {
     /// Default initial permission of the root of a new tree.
     pub fn new_root() -> Self {
-        Self(Active)
+        Self { inner: Active }
     }
 
     /// Default initial permission of a reborrowed mutable reference.
     pub fn new_unique_2phase(ty_is_freeze: bool) -> Self {
-        Self(Reserved { ty_is_freeze })
+        Self { inner: Reserved { ty_is_freeze } }
     }
 
     /// Default initial permission of a reborrowed shared reference
     pub fn new_frozen() -> Self {
-        Self(Frozen)
+        Self { inner: Frozen }
     }
 
     /// Apply the transition to the inner PermissionPriv.
@@ -144,9 +150,9 @@ impl Permission {
         old_perm: Self,
         protected: bool,
     ) -> Option<PermTransition> {
-        let old_state = old_perm.0;
+        let old_state = old_perm.inner;
         transition::perform_access(kind, rel_pos, old_state, protected)
-            .map(|new_state| PermTransition(old_state, new_state))
+            .map(|new_state| PermTransition { from: old_state, to: new_state })
     }
 }
 
@@ -155,26 +161,27 @@ impl PermTransition {
     /// should be possible, but the same is not guaranteed by construction of
     /// transitions inferred by diagnostics. This checks that a transition
     /// reconstructed by diagnostics is indeed one that could happen.
-    fn is_possible(old: PermissionPriv, new: PermissionPriv) -> bool {
-        old <= new
+    fn is_possible(self) -> bool {
+        self.from <= self.to
     }
 
-    pub fn from(old: Permission, new: Permission) -> Option<Self> {
-        Self::is_possible(old.0, new.0).then_some(Self(old.0, new.0))
+    pub fn from(from: Permission, to: Permission) -> Option<Self> {
+        let t = Self { from: from.inner, to: to.inner };
+        t.is_possible().then_some(t)
     }
 
     pub fn is_noop(self) -> bool {
-        self.0 == self.1
+        self.from == self.to
     }
 
     /// Extract result of a transition (checks that the starting point matches).
     pub fn applied(self, starting_point: Permission) -> Option<Permission> {
-        (starting_point.0 == self.0).then_some(Permission(self.1))
+        (starting_point.inner == self.from).then_some(Permission { inner: self.to })
     }
 
     /// Extract starting point of a transition
     pub fn started(self) -> Permission {
-        Permission(self.0)
+        Permission { inner: self.from }
     }
 
     /// Determines whether a transition that occured is compatible with the presence
@@ -190,10 +197,9 @@ impl PermTransition {
     /// };
     /// ```
     pub fn is_allowed_by_protector(&self) -> bool {
-        let &Self(old, new) = self;
-        assert!(Self::is_possible(old, new));
-        match (old, new) {
-            _ if old == new => true,
+        assert!(self.is_possible());
+        match (self.from, self.to) {
+            _ if self.from == self.to => true,
             // It is always a protector violation to not be readable anymore
             (_, Disabled) => false,
             // In the case of a `Reserved` under a protector, both transitions
@@ -204,16 +210,9 @@ impl PermTransition {
             (Reserved { .. }, Active) | (Reserved { .. }, Frozen) => true,
             // This pointer should have stayed writeable for the whole function
             (Active, Frozen) => false,
-            _ => unreachable!("Transition from {old:?} to {new:?} should never be possible"),
+            _ => unreachable!("Transition {} should never be possible", self),
         }
     }
-
-    /// Composition function: get the transition that can be added after `app` to
-    /// produce `self`.
-    pub fn apply_start(self, app: Self) -> Option<Self> {
-        let new_start = app.applied(Permission(self.0))?;
-        Self::from(new_start, Permission(self.1))
-    }
 }
 
 pub mod diagnostics {
@@ -224,10 +223,10 @@ pub mod diagnostics {
                 f,
                 "{}",
                 match self {
-                    PermissionPriv::Reserved { .. } => "Reserved",
-                    PermissionPriv::Active => "Active",
-                    PermissionPriv::Frozen => "Frozen",
-                    PermissionPriv::Disabled => "Disabled",
+                    Reserved { .. } => "Reserved",
+                    Active => "Active",
+                    Frozen => "Frozen",
+                    Disabled => "Disabled",
                 }
             )
         }
@@ -235,13 +234,13 @@ pub mod diagnostics {
 
     impl fmt::Display for PermTransition {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "from {} to {}", self.0, self.1)
+            write!(f, "from {} to {}", self.from, self.to)
         }
     }
 
     impl fmt::Display for Permission {
         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            write!(f, "{}", self.0)
+            write!(f, "{}", self.inner)
         }
     }
 
@@ -251,7 +250,7 @@ pub mod diagnostics {
             // Make sure there are all of the same length as each other
             // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise
             // alignment will be incorrect.
-            match self.0 {
+            match self.inner {
                 Reserved { ty_is_freeze: true } => "Res",
                 Reserved { ty_is_freeze: false } => "Re*",
                 Active => "Act",
@@ -269,9 +268,9 @@ pub mod diagnostics {
         /// to have write permissions, because that's what the diagnostics care about
         /// (otherwise `Reserved -> Frozen` would be considered a noop).
         pub fn summary(&self) -> &'static str {
-            assert!(Self::is_possible(self.0, self.1));
-            match (self.0, self.1) {
-                (_, Active) => "an activation",
+            assert!(self.is_possible());
+            match (self.from, self.to) {
+                (_, Active) => "the first write to a 2-phase borrowed mutable reference",
                 (_, Frozen) => "a loss of write permissions",
                 (Frozen, Disabled) => "a loss of read permissions",
                 (_, Disabled) => "a loss of read and write permissions",
@@ -279,6 +278,118 @@ pub mod diagnostics {
                     unreachable!("Transition from {old:?} to {new:?} should never be possible"),
             }
         }
+
+        /// Determines whether `self` is a relevant transition for the error `err`.
+        /// `self` will be a transition that happened to a tag some time before
+        /// that tag caused the error.
+        ///
+        /// Irrelevant events:
+        /// - modifications of write permissions when the error is related to read permissions
+        ///   (on failed reads and protected `Frozen -> Disabled`, ignore `Reserved -> Active`,
+        ///   `Reserved -> Frozen`, and `Active -> Frozen`)
+        /// - all transitions for attempts to deallocate strongly protected tags
+        ///
+        /// # Panics
+        ///
+        /// This function assumes that its arguments apply to the same location
+        /// and that they were obtained during a normal execution. It will panic otherwise.
+        /// - `err` cannot be a `ProtectedTransition(_)` of a noop transition, as those
+        /// never trigger protectors;
+        /// - all transitions involved in `self` and `err` should be increasing
+        /// (Reserved < Active < Frozen < Disabled);
+        /// - between `self` and `err` the permission should also be increasing,
+        /// so all permissions inside `err` should be greater than `self.1`;
+        /// - `Active` and `Reserved` cannot cause an error due to insufficient permissions,
+        /// so `err` cannot be a `ChildAccessForbidden(_)` of either of them;
+        pub(in super::super) fn is_relevant(&self, err: TransitionError) -> bool {
+            // NOTE: `super::super` is the visibility of `TransitionError`
+            assert!(self.is_possible());
+            if self.is_noop() {
+                return false;
+            }
+            match err {
+                TransitionError::ChildAccessForbidden(insufficient) => {
+                    // Show where the permission was gained then lost,
+                    // but ignore unrelated permissions.
+                    // This eliminates transitions like `Active -> Frozen`
+                    // when the error is a failed `Read`.
+                    match (self.to, insufficient.inner) {
+                        (Frozen, Frozen) => true,
+                        (Active, Frozen) => true,
+                        (Disabled, Disabled) => true,
+                        // A pointer being `Disabled` is a strictly stronger source of
+                        // errors than it being `Frozen`. If we try to access a `Disabled`,
+                        // then where it became `Frozen` (or `Active`) is the least of our concerns for now.
+                        (Active | Frozen, Disabled) => false,
+
+                        // `Active` and `Reserved` have all permissions, so a
+                        // `ChildAccessForbidden(Reserved | Active)` can never exist.
+                        (_, Active) | (_, Reserved { .. }) =>
+                            unreachable!("this permission cannot cause an error"),
+                        // No transition has `Reserved` as its `.to` unless it's a noop.
+                        (Reserved { .. }, _) => unreachable!("self is a noop transition"),
+                        // All transitions produced in normal executions (using `apply_access`)
+                        // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`.
+                        // We assume that the error was triggered on the same location that
+                        // the transition `self` applies to, so permissions found must be increasing
+                        // in the order `self.from < self.to <= insufficient.inner`
+                        (Disabled, Frozen) =>
+                            unreachable!("permissions between self and err must be increasing"),
+                    }
+                }
+                TransitionError::ProtectedTransition(forbidden) => {
+                    assert!(!forbidden.is_noop());
+                    // Show how we got to the starting point of the forbidden transition,
+                    // but ignore what came before.
+                    // This eliminates transitions like `Reserved -> Active`
+                    // when the error is a `Frozen -> Disabled`.
+                    match (self.to, forbidden.from, forbidden.to) {
+                        // We absolutely want to know where it was activated.
+                        (Active, Active, Frozen | Disabled) => true,
+                        // And knowing where it became Frozen is also important.
+                        (Frozen, Frozen, Disabled) => true,
+                        // If the error is a transition `Frozen -> Disabled`, then we don't really
+                        // care whether before that was `Reserved -> Active -> Frozen` or
+                        // `Reserved -> Frozen` or even `Frozen` directly.
+                        // The error will only show either
+                        // - created as Frozen, then Frozen -> Disabled is forbidden
+                        // - created as Reserved, later became Frozen, then Frozen -> Disabled is forbidden
+                        // In both cases the `Reserved -> Active` part is inexistant or irrelevant.
+                        (Active, Frozen, Disabled) => false,
+
+                        // `Reserved -> Frozen` does not trigger protectors.
+                        (_, Reserved { .. }, Frozen) =>
+                            unreachable!("this transition cannot cause an error"),
+                        // No transition has `Reserved` as its `.to` unless it's a noop.
+                        (Reserved { .. }, _, _) => unreachable!("self is a noop transition"),
+                        (_, Disabled, Disabled) | (_, Frozen, Frozen) | (_, Active, Active) =>
+                            unreachable!("err contains a noop transition"),
+
+                        // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`,
+                        // so permissions found must be increasing in the order
+                        // `self.from < self.to <= forbidden.from < forbidden.to`.
+                        (Disabled, Reserved { .. } | Active | Frozen, _)
+                        | (Frozen, Reserved { .. } | Active, _)
+                        | (Active, Reserved { .. }, _) =>
+                            unreachable!("permissions between self and err must be increasing"),
+                        (_, Disabled, Reserved { .. } | Active | Frozen)
+                        | (_, Frozen, Reserved { .. } | Active)
+                        | (_, Active, Reserved { .. }) =>
+                            unreachable!("permissions within err must be increasing"),
+                    }
+                }
+                // We don't care because protectors evolve independently from
+                // permissions.
+                TransitionError::ProtectedDealloc => false,
+            }
+        }
+
+        /// Endpoint of a transition.
+        /// Meant only for diagnostics, use `applied` in non-diagnostics
+        /// code, which also checks that the starting point matches the current state.
+        pub fn endpoint(&self) -> Permission {
+            Permission { inner: self.to }
+        }
     }
 }
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 8c788c915fe..2a06bd871ef 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -97,8 +97,12 @@ impl MachineStopType for TerminationInfo {
     }
     fn add_args(
         self: Box<Self>,
-        _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue<'static>),
-    ) {}
+        _: &mut dyn FnMut(
+            std::borrow::Cow<'static, str>,
+            rustc_errors::DiagnosticArgValue<'static>,
+        ),
+    ) {
+    }
 }
 
 /// Miri specific diagnostics
@@ -324,10 +328,9 @@ pub fn report_error<'tcx, 'mir>(
     // We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes
     // the `InterpError`, we extract the variables it before that.
     let extra = match e {
-        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
-            Some((alloc_id, access))
-        }
-        _ => None
+        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) =>
+            Some((alloc_id, access)),
+        _ => None,
     };
 
     // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
@@ -477,7 +480,7 @@ pub fn report_msg<'tcx>(
     }
 
     let (mut err, handler) = err.into_diagnostic().unwrap();
-    
+
     // Add backtrace
     for (idx, frame_info) in stacktrace.iter().enumerate() {
         let is_local = machine.is_local(frame_info);
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index f1190265239..befdddfa8c9 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -162,9 +162,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let instance = this.resolve_path(path, Namespace::ValueNS);
         let cid = GlobalId { instance, promoted: None };
         // We don't give a span -- this isn't actually used directly by the program anyway.
-        let const_val = this
-            .eval_global(cid, None)
-            .unwrap_or_else(|err| panic!("failed to evaluate required Rust item: {path:?}\n{err:?}"));
+        let const_val = this.eval_global(cid, None).unwrap_or_else(|err| {
+            panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
+        });
         this.read_scalar(&const_val.into())
             .unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err:?}"))
     }
diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs
index fa06c4b6a12..9e6e3703153 100644
--- a/src/tools/miri/tests/compiletest.rs
+++ b/src/tools/miri/tests/compiletest.rs
@@ -51,18 +51,9 @@ fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) ->
     let mut program = CommandBuilder::rustc();
     program.program = miri_path();
 
-    let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some();
-
     // Add some flags we always want.
-    if in_rustc_test_suite {
-        // Less aggressive warnings to make the rustc toolstate management less painful.
-        // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.)
-        program.args.push("-Astable-features".into());
-        program.args.push("-Aunused".into());
-    } else {
-        program.args.push("-Dwarnings".into());
-        program.args.push("-Dunused".into());
-    }
+    program.args.push("-Dwarnings".into());
+    program.args.push("-Dunused".into());
     if let Ok(extra_flags) = env::var("MIRIFLAGS") {
         for flag in extra_flags.split_whitespace() {
             program.args.push(flag.into());
@@ -277,7 +268,6 @@ fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Res
     // the arguments to the interpreted prog
     cmd.arg("--");
     cmd.args(args);
-    println!("{cmd:?}");
     if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) }
 }
 
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs
new file mode 100644
index 00000000000..4554d0cb82b
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.rs
@@ -0,0 +1,8 @@
+#![feature(unchecked_math)]
+
+fn main() {
+    unsafe {
+        let _n = 1i8.unchecked_shl(8);
+        //~^ ERROR: overflowing shift by 8 in `unchecked_shl`
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr
new file mode 100644
index 00000000000..264e9baf053
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shl.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: overflowing shift by 8 in `unchecked_shl`
+  --> $DIR/unchecked_shl.rs:LL:CC
+   |
+LL |         let _n = 1i8.unchecked_shl(8);
+   |                  ^^^^^^^^^^^^^^^^^^^^ overflowing shift by 8 in `unchecked_shl`
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/unchecked_shl.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/overflowing-unchecked-rsh.rs b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs
index fe2e85be698..fe2e85be698 100644
--- a/src/tools/miri/tests/fail/intrinsics/overflowing-unchecked-rsh.rs
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.rs
diff --git a/src/tools/miri/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr
index 9c5d0d13108..378ff9734c1 100644
--- a/src/tools/miri/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr
+++ b/src/tools/miri/tests/fail/intrinsics/unchecked_shr.stderr
@@ -1,5 +1,5 @@
 error: Undefined Behavior: overflowing shift by 64 in `unchecked_shr`
-  --> $DIR/overflowing-unchecked-rsh.rs:LL:CC
+  --> $DIR/unchecked_shr.rs:LL:CC
    |
 LL |         let _n = 1i64.unchecked_shr(64);
    |                  ^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr`
@@ -7,7 +7,7 @@ LL |         let _n = 1i64.unchecked_shr(64);
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC
+   = note: inside `main` at $DIR/unchecked_shr.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr
index bb601fc8835..d82cb8288a3 100644
--- a/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr
+++ b/src/tools/miri/tests/fail/tree-borrows/alternate-read-write.stderr
@@ -17,13 +17,13 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved
    |
 LL |     let y = unsafe { &mut *(x as *mut u8) };
    |                      ^^^^^^^^^^^^^^^^^^^^
-help: the conflicting tag <TAG> then transitioned from Reserved to Active due to a child write access at offsets [0x0..0x1]
+help: the conflicting tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
   --> $DIR/alternate-read-write.rs:LL:CC
    |
 LL |     *y += 1; // Success
    |     ^^^^^^^
-   = help: this corresponds to an activation
-help: the conflicting tag <TAG> then transitioned from Active to Frozen due to a foreign read access at offsets [0x0..0x1]
+   = help: this corresponds to the first write to a 2-phase borrowed mutable reference
+help: the conflicting tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
   --> $DIR/alternate-read-write.rs:LL:CC
    |
 LL |     let _val = *x;
diff --git a/src/tools/miri/tests/fail/tree-borrows/error-range.stderr b/src/tools/miri/tests/fail/tree-borrows/error-range.stderr
index bc829fd86d3..10c2e95ca2f 100644
--- a/src/tools/miri/tests/fail/tree-borrows/error-range.stderr
+++ b/src/tools/miri/tests/fail/tree-borrows/error-range.stderr
@@ -17,19 +17,7 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved
    |
 LL |         let rmut = &mut *addr_of_mut!(data[0..6]);
    |                                       ^^^^
-help: the conflicting tag <TAG> then transitioned from Reserved to Active due to a child write access at offsets [0x5..0x6]
-  --> $DIR/error-range.rs:LL:CC
-   |
-LL |         rmut[5] += 1;
-   |         ^^^^^^^^^^^^
-   = help: this corresponds to an activation
-help: the conflicting tag <TAG> then transitioned from Active to Frozen due to a foreign read access at offsets [0x5..0x6]
-  --> $DIR/error-range.rs:LL:CC
-   |
-LL |         let _v = data[5];
-   |                  ^^^^^^^
-   = help: this corresponds to a loss of write permissions
-help: the conflicting tag <TAG> then transitioned from Frozen to Disabled due to a foreign write access at offsets [0x5..0x6]
+help: the conflicting tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x5..0x6]
   --> $DIR/error-range.rs:LL:CC
    |
 LL |         data[5] = 1;
diff --git a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr
index 79744964a8b..86fdf97ac41 100644
--- a/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr
+++ b/src/tools/miri/tests/fail/tree-borrows/fragile-data-race.stderr
@@ -17,7 +17,7 @@ help: the conflicting tag <TAG> was created here, in the initial state Reserved
    |
 LL | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> {
    |                                                       ^
-help: the conflicting tag <TAG> then transitioned from Reserved to Frozen due to a foreign read access at offsets [0x0..0x1]
+help: the conflicting tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
   --> RUSTLIB/core/src/ptr/mod.rs:LL:CC
    |
 LL |         crate::intrinsics::read_via_copy(src)
diff --git a/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr
index 8c9c2f8f965..6deb4b43f6a 100644
--- a/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr
+++ b/src/tools/miri/tests/fail/tree-borrows/read-to-local.stderr
@@ -11,13 +11,13 @@ help: the accessed tag <TAG> was created here, in the initial state Reserved
    |
 LL |         let mref = &mut root;
    |                    ^^^^^^^^^
-help: the accessed tag <TAG> then transitioned from Reserved to Active due to a child write access at offsets [0x0..0x1]
+help: the accessed tag <TAG> later transitioned to Active due to a child write access at offsets [0x0..0x1]
   --> $DIR/read-to-local.rs:LL:CC
    |
 LL |         *ptr = 0; // Write
    |         ^^^^^^^^
-   = help: this corresponds to an activation
-help: the accessed tag <TAG> then transitioned from Active to Frozen due to a foreign read access at offsets [0x0..0x1]
+   = help: this corresponds to the first write to a 2-phase borrowed mutable reference
+help: the accessed tag <TAG> later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1]
   --> $DIR/read-to-local.rs:LL:CC
    |
 LL |         assert_eq!(root, 0); // Parent Read
diff --git a/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr b/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr
index 071b216ff98..97088d5854c 100644
--- a/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr
+++ b/src/tools/miri/tests/fail/tree-borrows/strongly-protected.stderr
@@ -17,12 +17,6 @@ help: the strongly protected tag <TAG> was created here, in the initial state Re
    |
 LL | fn inner(x: &mut i32, f: fn(&mut i32)) {
    |          ^
-help: the strongly protected tag <TAG> then transitioned from Reserved to Active due to a child write access at offsets [0x0..0x4]
-  --> $DIR/strongly-protected.rs:LL:CC
-   |
-LL |         drop(unsafe { Box::from_raw(raw) });
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = help: this corresponds to an activation
    = note: BACKTRACE (of the first span):
    = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC
    = note: inside `<std::alloc::Global as std::alloc::Allocator>::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC
diff --git a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr
index f6285bdcf16..898f6108ccb 100644
--- a/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr
+++ b/src/tools/miri/tests/fail/tree-borrows/write-during-2phase.stderr
@@ -18,7 +18,7 @@ LL | |         *inner = 42;
 LL | |         n
 LL | |     });
    | |______^
-help: the accessed tag <TAG> then transitioned from Reserved to Disabled due to a foreign write access at offsets [0x0..0x8]
+help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8]
   --> $DIR/write-during-2phase.rs:LL:CC
    |
 LL |         *inner = 42;
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 3258a2be460..af245aa89aa 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -31,7 +31,7 @@ fn main() {
 }
 
 fn host_to_target_path(path: String) -> PathBuf {
-    use std::ffi::{c_char, CStr, CString};
+    use std::ffi::{CStr, CString};
 
     let path = CString::new(path).unwrap();
     let mut out = Vec::with_capacity(1024);