diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 33397e56b86c..08a12b6447e6 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -168,7 +168,7 @@ macro_rules! assert_ne { #[allow_internal_unstable(panic_internals)] #[rustc_macro_transparency = "semiopaque"] pub macro assert_matches { - ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { + ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {{ match $left { $( $pattern )|+ $( if $guard )? => {} ref left_val => { @@ -179,8 +179,8 @@ macro_rules! assert_ne { ); } } - }, - ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => { + }}, + ($left:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => {{ match $left { $( $pattern )|+ $( if $guard )? => {} ref left_val => { @@ -191,7 +191,7 @@ macro_rules! assert_ne { ); } } - }, + }}, } /// Selects code at compile-time based on `cfg` predicates. diff --git a/library/coretests/tests/macros.rs b/library/coretests/tests/macros.rs index 50b5eb63e43a..52435b226e65 100644 --- a/library/coretests/tests/macros.rs +++ b/library/coretests/tests/macros.rs @@ -1,5 +1,7 @@ #![allow(unused_must_use)] +use std::{assert_matches, debug_assert_matches}; + #[allow(dead_code)] trait Trait { fn blah(&self); @@ -219,3 +221,24 @@ fn _matches_does_not_trigger_non_exhaustive_omitted_patterns_lint(o: core::sync: // Ordering is a #[non_exhaustive] enum from a separate crate let _m = matches!(o, core::sync::atomic::Ordering::Relaxed); } + +struct MutRefWithDrop<'a>(&'a mut u32); + +// MutRefWithDrop needs to have a non-trivial drop to encounter potential lifetime issues if the +// macros don't introduce a temporary scope. +impl Drop for MutRefWithDrop<'_> { + fn drop(&mut self) { + *self.0 = u32::MAX; + } +} + +#[test] +fn temporary_scope_introduction() { + // Fails to compile if the macros don't introduce a temporary scope, since `&mut val` would + // create a second mutable borrow while `MutRefWithDrop` still holds a unique ref. + let mut val = 0; + + (assert_matches!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val)); + + (debug_assert_matches!(*MutRefWithDrop(&mut val).0, 0), std::mem::take(&mut val)); +}