diff --git a/googletest/src/lib.rs b/googletest/src/lib.rs
index 3f59546d..382fac2a 100644
--- a/googletest/src/lib.rs
+++ b/googletest/src/lib.rs
@@ -30,7 +30,7 @@ pub mod matcher;
 pub mod matcher_support;
 pub mod matchers;
 
-pub use googletest_macro::{__abbreviated_stringify, __googletest_macro_verify_pred};
+pub use googletest_macro::__abbreviated_stringify;
 
 /// Re-exports of the symbols in this crate which are most likely to be used.
 ///
diff --git a/googletest/src/matchers/matches_pattern.rs b/googletest/src/matchers/matches_pattern.rs
index 7dc9ce33..5de7d7c0 100644
--- a/googletest/src/matchers/matches_pattern.rs
+++ b/googletest/src/matchers/matches_pattern.rs
@@ -293,571 +293,14 @@ macro_rules! __matches_pattern {
 #[doc(hidden)]
 #[macro_export]
 macro_rules! matches_pattern_internal {
-    (
-        @name [$($struct_name:tt)*],
-        { $field_name:ident : ref $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(field!($($struct_name)*.$field_name, ref $matcher))
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $field_name:ident : $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(field!($($struct_name)*.$field_name, $matcher))
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(property!($($struct_name)*.$property_name($($argument),*), ref $matcher))
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(property!($($struct_name)*.$property_name($($argument),*), $matcher))
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $field_name:ident : ref $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (field!($($struct_name)*.$field_name, ref $matcher)),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $field_name:ident : $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (field!($($struct_name)*.$field_name, $matcher)),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (property!($($struct_name)*.$property_name($($argument),*), ref $matcher)),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (property!($($struct_name)*.$property_name($($argument),*), $matcher)),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $field_name:ident : ref $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(
-                $($processed)*,
-                field!($($struct_name)*.$field_name, ref $matcher)
-            ))
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $field_name:ident : $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(
-                $($processed)*,
-                field!($($struct_name)*.$field_name, $matcher)
-            ))
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(
-                $($processed)*,
-                property!($($struct_name)*.$property_name($($argument),*), ref $matcher)
-            ))
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr $(,)? }
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(
-                $($processed)*,
-                property!($($struct_name)*.$property_name($($argument),*), $matcher)
-            ))
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $field_name:ident : ref $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.$field_name, ref $matcher)
-            ),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $field_name:ident : $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.$field_name, $matcher)
-            ),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : ref $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                property!(ref $($struct_name)*.$property_name($($argument),*), $matcher)
-            ),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        { $property_name:ident($($argument:expr),* $(,)?) : $matcher:expr, $($rest:tt)* }
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                property!($($struct_name)*.$property_name($($argument),*), $matcher)
-            ),
-            [$($struct_name)*],
-            { $($rest)* }
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::pattern_only(
-            |v| matches!(v, $($struct_name)*),
-            concat!("is ", stringify!($($struct_name)*)),
-            concat!("is not ", stringify!($($struct_name)*)))
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        (ref $matcher:expr $(,)?)
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(field!($($struct_name)*.0, ref $matcher))
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        ($matcher:expr $(,)?)
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(field!($($struct_name)*.0, $matcher))
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                field!($($struct_name)*.0, ref $matcher)
-            ),
-            [$($struct_name)*],
-            1,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @name [$($struct_name:tt)*],
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                field!($($struct_name)*.0, $matcher)
-            ),
-            [$($struct_name)*],
-            1,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        $field:tt,
-        (ref $matcher:expr $(,)?)
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(
-                $($processed)*,
-                field!($($struct_name)*.$field, ref $matcher)
-            ))
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        $field:tt,
-        ($matcher:expr $(,)?)
-    ) => {
-        $crate::matchers::__internal_unstable_do_not_depend_on_these::is(
-            stringify!($($struct_name)*),
-            all!(
-                $($processed)*,
-                field!($($struct_name)*.$field, $matcher)
-            ))
-    };
-
-    // We need to repeat this once for every supported field position, unfortunately. There appears
-    // to be no way in declarative macros to compute $field + 1 and have the result evaluated to a
-    // token which can be used as a tuple index.
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        1,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.1, ref $matcher)
-            ),
-            [$($struct_name)*],
-            2,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        1,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.1, $matcher)
-            ),
-            [$($struct_name)*],
-            2,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        2,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.2, ref $matcher)
-            ),
-            [$($struct_name)*],
-            3,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        2,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.2, $matcher)
-            ),
-            [$($struct_name)*],
-            3,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        3,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.3, ref $matcher)
-            ),
-            [$($struct_name)*],
-            4,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        3,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.3, $matcher)
-            ),
-            [$($struct_name)*],
-            4,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        4,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.4, ref $matcher)
-            ),
-            [$($struct_name)*],
-            5,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        4,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.4, $matcher)
-            ),
-            [$($struct_name)*],
-            5,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        5,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.5, ref $matcher)
-            ),
-            [$($struct_name)*],
-            6,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        5,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.5, $matcher)
-            ),
-            [$($struct_name)*],
-            6,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        6,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.6, ref $matcher)
-            ),
-            [$($struct_name)*],
-            7,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        6,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.6, $matcher)
-            ),
-            [$($struct_name)*],
-            7,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        7,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.7, ref $matcher)
-            ),
-            [$($struct_name)*],
-            8,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        7,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.7, $matcher)
-            ),
-            [$($struct_name)*],
-            8,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        8,
-        (ref $matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.8, ref $matcher)
-            ),
-            [$($struct_name)*],
-            9,
-            ($($rest)*)
-        )
-    };
-
-    (
-        @fields ($($processed:tt)*),
-        [$($struct_name:tt)*],
-        8,
-        ($matcher:expr, $($rest:tt)*)
-    ) => {
-        $crate::matches_pattern_internal!(
-            @fields (
-                $($processed)*,
-                field!($($struct_name)*.8, $matcher)
-            ),
-            [$($struct_name)*],
-            9,
-            ($($rest)*)
-        )
-    };
-
-    (@name [$($struct_name:tt)*], $first:tt $($rest:tt)*) => {
-        $crate::matches_pattern_internal!(@name [$($struct_name)* $first], $($rest)*)
+    ($($tt:tt)*) => {
+        {
+            use $crate::{self as googletest};
+            #[allow(unused)]
+            use $crate::matchers::{all, field, property};
+            $crate::matchers::__internal_unstable_do_not_depend_on_these::__googletest_macro_matches_pattern!($($tt)*)
+        }
     };
-
-    ($first:tt $($rest:tt)*) => {{
-        #[allow(unused)]
-        use $crate::matchers::{all, field, property};
-        $crate::matches_pattern_internal!(@name [$first], $($rest)*)
-    }};
 }
 
 /// An alias for [`matches_pattern`][crate::matchers::matches_pattern!].
@@ -872,6 +315,8 @@ pub mod internal {
     use crate::matcher::{Matcher, MatcherBase};
     use std::fmt::Debug;
 
+    pub use ::googletest_macro::__googletest_macro_matches_pattern;
+
     // Specialized implementation of the `predicate` matcher to support ref binding
     // mode for `matches_pattern`.
     pub fn pattern_only<T>(
diff --git a/googletest/src/matchers/mod.rs b/googletest/src/matchers/mod.rs
index 16ca900f..18ea1b28 100644
--- a/googletest/src/matchers/mod.rs
+++ b/googletest/src/matchers/mod.rs
@@ -113,7 +113,7 @@ pub mod __internal_unstable_do_not_depend_on_these {
     pub use super::elements_are_matcher::internal::ElementsAre;
     pub use super::field_matcher::internal::field_matcher;
     pub use super::is_matcher::is;
-    pub use super::matches_pattern::internal::pattern_only;
+    pub use super::matches_pattern::internal::{__googletest_macro_matches_pattern, pattern_only};
     pub use super::pointwise_matcher::internal::PointwiseMatcher;
     pub use super::property_matcher::internal::{property_matcher, property_ref_matcher};
     pub use super::result_of_matcher::internal::{result_of, result_of_ref};
diff --git a/googletest/src/matchers/property_matcher.rs b/googletest/src/matchers/property_matcher.rs
index 98c51a67..5744f8ef 100644
--- a/googletest/src/matchers/property_matcher.rs
+++ b/googletest/src/matchers/property_matcher.rs
@@ -177,25 +177,25 @@ macro_rules! __property {
 #[macro_export]
 macro_rules! property_internal {
 
-    (&$($t:ident)::+.$method:tt($($argument:tt),* $(,)?), ref $m:expr) => {{
+    (&$($t:ident)::+.$method:tt($($argument:expr),* $(,)?), ref $m:expr) => {{
         $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher(
             |o: &$($t)::+| $($t)::+::$method(o, $($argument),*),
             &stringify!($method($($argument),*)),
             $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
     }};
-    ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), ref $m:expr) => {{
+    ($($t:ident)::+.$method:tt($($argument:expr),* $(,)?), ref $m:expr) => {{
         $crate::matchers::__internal_unstable_do_not_depend_on_these::property_ref_matcher(
             |o: $($t)::+| $($t)::+::$method(o, $($argument),*),
             &stringify!($method($($argument),*)),
             $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
     }};
-    (& $($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{
+    (& $($t:ident)::+.$method:tt($($argument:expr),* $(,)?), $m:expr) => {{
         $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher(
             |o: &&$($t)::+| o.$method($($argument),*),
             &stringify!($method($($argument),*)),
             $crate::matcher_support::__internal_unstable_do_not_depend_on_these::auto_eq!($m))
     }};
-    ($($t:ident)::+.$method:tt($($argument:tt),* $(,)?), $m:expr) => {{
+    ($($t:ident)::+.$method:tt($($argument:expr),* $(,)?), $m:expr) => {{
         $crate::matchers::__internal_unstable_do_not_depend_on_these::property_matcher(
             |o: &$($t)::+| o.$method($($argument),*),
             &stringify!($method($($argument),*)),
diff --git a/googletest/tests/matches_pattern_test.rs b/googletest/tests/matches_pattern_test.rs
index d1b97e79..186a488e 100644
--- a/googletest/tests/matches_pattern_test.rs
+++ b/googletest/tests/matches_pattern_test.rs
@@ -146,7 +146,6 @@ fn has_correct_assertion_failure_message_for_single_field() -> Result<()> {
     let actual = AStruct { a_field: 123 };
     let result = verify_that!(actual, matches_pattern!(&AStruct { a_field: eq(234) }));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = indoc!(
         "
         Value of: actual
@@ -156,16 +155,6 @@ fn has_correct_assertion_failure_message_for_single_field() -> Result<()> {
         "
     );
 
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = indoc!(
-        "
-        Value of: actual
-        Expected: is &AStruct which has field `a_field`, which is equal to 234
-        Actual: AStruct { a_field: 123 },
-          which has field `a_field`, which isn't equal to 234
-        "
-    );
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
@@ -182,7 +171,6 @@ fn has_correct_assertion_failure_message_for_two_fields() -> Result<()> {
         matches_pattern!(&AStruct { a_field: eq(234), another_field: eq(123) })
     );
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = indoc!(
         "
         Value of: actual
@@ -194,18 +182,6 @@ fn has_correct_assertion_failure_message_for_two_fields() -> Result<()> {
           * which has field `another_field`, which isn't equal to 123"
     );
 
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = indoc!(
-        "
-        Value of: actual
-        Expected: is &AStruct which has all the following properties:
-          * has field `a_field`, which is equal to 234
-          * has field `another_field`, which is equal to 123
-        Actual: AStruct { a_field: 123, another_field: 234 },
-          * which has field `a_field`, which isn't equal to 234
-          * which has field `another_field`, which isn't equal to 123"
-    );
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
@@ -227,27 +203,14 @@ fn has_correct_assertion_failure_message_for_field_and_property() -> Result<()>
         matches_pattern!(&AStruct { get_field(): eq(234), another_field: eq(123) })
     );
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = indoc!(
         "
     Value of: actual
     Expected: is & AStruct which has all the following properties:
-      * has property `get_field ()`, which is equal to 234
-      * has field `another_field`, which is equal to 123
-    Actual: AStruct { a_field: 123, another_field: 234 },
-      * whose property `get_field ()` is `123`, which isn't equal to 234
-      * which has field `another_field`, which isn't equal to 123"
-    );
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = indoc!(
-        "
-    Value of: actual
-    Expected: is &AStruct which has all the following properties:
-      * has property `get_field ()`, which is equal to 234
+      * has property `get_field()`, which is equal to 234
       * has field `another_field`, which is equal to 123
     Actual: AStruct { a_field: 123, another_field: 234 },
-      * whose property `get_field ()` is `123`, which isn't equal to 234
+      * whose property `get_field()` is `123`, which isn't equal to 234
       * which has field `another_field`, which isn't equal to 123"
     );
 
@@ -484,7 +447,8 @@ fn matches_enum_without_field() -> Result<()> {
     }
     let actual = AnEnum::A;
 
-    verify_that!(actual, matches_pattern!(&AnEnum::A))
+    verify_that!(actual, matches_pattern!(&AnEnum::A))?;
+    verify_that!(actual, matches_pattern!(&AnEnum::A,))
 }
 
 #[test]
@@ -495,7 +459,8 @@ fn matches_enum_without_field_ref_binding_mode() -> Result<()> {
     }
     let actual = AnEnum::A;
 
-    verify_that!(actual, matches_pattern!(AnEnum::A))
+    verify_that!(actual, matches_pattern!(AnEnum::A))?;
+    verify_that!(actual, matches_pattern!(AnEnum::A,))
 }
 
 #[test]
@@ -506,7 +471,43 @@ fn matches_enum_without_field_copy() -> Result<()> {
     }
     let actual = AnEnum::A;
 
-    verify_that!(actual, matches_pattern!(AnEnum::A))
+    verify_that!(actual, matches_pattern!(AnEnum::A))?;
+    verify_that!(actual, matches_pattern!(AnEnum::A,))
+}
+
+#[test]
+fn matches_match_pattern_literal() -> Result<()> {
+    let actual = false;
+    #[allow(clippy::redundant_pattern_matching)]
+    verify_that!(actual, matches_pattern!(false))?;
+    #[allow(clippy::redundant_pattern_matching)]
+    verify_that!(actual, matches_pattern!(false,))?;
+    let actual = 1;
+    verify_that!(actual, matches_pattern!(1))?;
+    verify_that!(actual, matches_pattern!(1,))?;
+    let actual = "test";
+    verify_that!(actual, matches_pattern!(&"test"))?;
+    verify_that!(actual, matches_pattern!(&"test",))
+}
+
+#[test]
+fn matches_match_pattern_struct() -> Result<()> {
+    #[allow(dead_code)]
+    #[derive(Debug)]
+    struct AStruct {
+        a: u32,
+    }
+    let actual = AStruct { a: 123 };
+    verify_that!(actual, matches_pattern!(AStruct { .. }))
+}
+
+#[test]
+fn matches_match_pattern_tuple() -> Result<()> {
+    #[allow(dead_code)]
+    #[derive(Debug)]
+    struct AStruct(u32);
+    let actual = AStruct(123);
+    verify_that!(actual, matches_pattern!(AStruct(_)))
 }
 
 #[test]
@@ -521,12 +522,7 @@ fn generates_correct_failure_output_when_enum_variant_without_field_is_not_match
 
     let result = verify_that!(actual, matches_pattern!(&AnEnum::A));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "is not & AnEnum :: A";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "is not &AnEnum::A";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -539,12 +535,7 @@ fn generates_correct_failure_output_when_enum_variant_without_field_is_matched()
 
     let result = verify_that!(actual, not(matches_pattern!(&AnEnum::A)));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "is & AnEnum :: A";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "is &AnEnum::A";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -579,12 +570,7 @@ fn includes_enum_variant_in_description_with_field() -> Result<()> {
 
     let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234))));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AnEnum :: A which has field `0`";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AnEnum::A which has field `0`";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -597,12 +583,7 @@ fn includes_enum_variant_in_negative_description_with_field() -> Result<()> {
 
     let result = verify_that!(actual, not(matches_pattern!(&AnEnum::A(eq(123)))));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is not & AnEnum :: A which has field `0`, which is equal to";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is not &AnEnum::A which has field `0`, which is equal to";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -615,12 +596,7 @@ fn includes_enum_variant_in_description_with_two_fields() -> Result<()> {
 
     let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234), eq(234))));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AnEnum::A which has all the following properties";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -633,12 +609,7 @@ fn includes_enum_variant_in_description_with_three_fields() -> Result<()> {
 
     let result = verify_that!(actual, matches_pattern!(&AnEnum::A(eq(234), eq(234), eq(345))));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AnEnum::A which has all the following properties";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -651,12 +622,7 @@ fn includes_enum_variant_in_description_with_named_field() -> Result<()> {
 
     let result = verify_that!(actual, matches_pattern!(&AnEnum::A { field: eq(234) }));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AnEnum :: A which has field `field`";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AnEnum::A which has field `field`";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -672,12 +638,7 @@ fn includes_enum_variant_in_description_with_two_named_fields() -> Result<()> {
         matches_pattern!(&AnEnum::A { field: eq(234), another_field: eq(234) })
     );
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AnEnum :: A which has all the following properties";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AnEnum::A which has all the following properties";
-
     verify_that!(&result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -695,12 +656,7 @@ fn includes_struct_name_in_description_with_property() -> Result<()> {
 
     let result = verify_that!(actual, matches_pattern!(&AStruct { get_field(): eq(234) }));
 
-    #[rustversion::before(1.76)]
-    const EXPECTED: &str = "Expected: is & AStruct which has property `get_field ()`";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AStruct which has property `get_field ()`";
-
+    const EXPECTED: &str = "Expected: is & AStruct which has property `get_field()`";
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
@@ -718,12 +674,7 @@ fn includes_struct_name_in_description_with_ref_property() -> Result<()> {
 
     let result = verify_that!(actual, matches_pattern!(&AStruct { get_field(): eq(&234) }));
 
-    #[rustversion::before(1.76)]
-    const EXPECTED: &str = "Expected: is & AStruct which has property `get_field ()`";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AStruct which has property `get_field ()`";
-
+    const EXPECTED: &str = "Expected: is & AStruct which has property `get_field()`";
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
@@ -743,12 +694,7 @@ fn includes_struct_name_in_description_with_property_after_field() -> Result<()>
     let result =
         verify_that!(actual, matches_pattern!(&AStruct { field: eq(123), get_field(): eq(234) }));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AStruct which has all the following properties";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AStruct which has all the following properties";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 
@@ -768,12 +714,7 @@ fn includes_struct_name_in_description_with_ref_property_after_field() -> Result
     let result =
         verify_that!(actual, matches_pattern!(&AStruct { field: eq(123), get_field(): eq(&234) }));
 
-    #[rustversion::before(1.76)]
     const EXPECTED: &str = "Expected: is & AStruct which has all the following properties";
-
-    #[rustversion::since(1.76)]
-    const EXPECTED: &str = "Expected: is &AStruct which has all the following properties";
-
     verify_that!(result, err(displays_as(contains_substring(EXPECTED))))
 }
 #[test]
diff --git a/googletest_macro/src/lib.rs b/googletest_macro/src/lib.rs
index 79e60ee2..1b81eb27 100644
--- a/googletest_macro/src/lib.rs
+++ b/googletest_macro/src/lib.rs
@@ -332,9 +332,22 @@ pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
     .into()
 }
 
+mod matches_pattern;
+
+/// This is an implementation detail of `googletest::matches_pattern!`.
+///
+/// It's not intended to be used directly.
+#[doc(hidden)]
+#[proc_macro]
+pub fn __googletest_macro_matches_pattern(
+    input: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+    matches_pattern::matches_pattern_impl(input)
+}
+
 mod verify_pred;
 
-/// This is an implementation detail of `verify_pred!`.
+/// This is an implementation detail of `googletest::verify_pred!`.
 ///
 /// It's not intended to be used directly.
 #[doc(hidden)]
diff --git a/googletest_macro/src/matches_pattern.rs b/googletest_macro/src/matches_pattern.rs
new file mode 100644
index 00000000..4c6a41a2
--- /dev/null
+++ b/googletest_macro/src/matches_pattern.rs
@@ -0,0 +1,255 @@
+// Copyright 2024 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
+use quote::quote;
+use syn::{
+    parse::{Parse, ParseStream, Parser as _},
+    parse_macro_input,
+    punctuated::Punctuated,
+    Expr, ExprCall, ExprInfer, Pat, Token,
+};
+
+/// This is an implementation detail of `googletest::matches_pattern!`. It
+/// assumes that a few symbols from `googletest::matchers` have been imported
+/// and that `$crate` has been aliased to `googletest` (which might otherwise
+/// have been imported as a different alias), both of which are done
+/// by `googletest::matches_pattern!` before calling this proc macro.
+pub(crate) fn matches_pattern_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
+    let result = parse_macro_input!(input as ParsedMatchPattern).into_matcher_expr();
+    quote! { #result }.into()
+}
+
+/// Represents one of the root-level pseudo-patterns supported by
+/// `match_pattern!`.
+///
+/// Examples with `struct_name` set and `group` being `None`:
+/// * `true`
+/// * `Enum::Variant`
+/// * `&Enum::Variant`
+///
+/// Examples with `group` being non-`None`.
+/// * `Struct { a: eq(1), b: ends_with("foo") }`
+/// * `&Struct(ref eq(&1), ends_with("foo"))`
+#[derive(Debug)]
+struct ParsedMatchPattern {
+    struct_name: TokenStream,
+    group: Option<Group>,
+}
+
+impl Parse for ParsedMatchPattern {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        let mut struct_name: Vec<TokenTree> = vec![];
+        let mut group: Option<Group> = None;
+
+        // Use a TT-muncher (as opposed to parsing `Expr` or `Pat` or such) since:
+        // - The `struct_name` can be a struct/enum type or literal value (`true`, `1`,
+        //   `&"test"`).
+        // - The braced part supports syntax that is not valid rust like `&Foo { a: ref
+        //   eq(1) }`.
+        input.step(|cursor| {
+            let mut rest = *cursor;
+
+            while let Some((tt, next)) = rest.token_tree() {
+                // If we reached a group (`{...}` or `(...)`), that should be the end of the
+                // pattern. Other groups (`[...]`) are not supported in struct names, but that's
+                // checked later.
+                if let TokenTree::Group(g) = tt {
+                    group = Some(g);
+                    return Ok(((), next));
+                }
+
+                // Everything before the group is the struct/enum name, possibly prefixed with
+                // `&`.
+                struct_name.push(tt);
+                rest = next;
+            }
+
+            // If no group found, remove any trailing comma that might have been
+            // incorporated into the struct/enum name.
+            if matches!(struct_name.last(), Some(TokenTree::Punct(p)) if p.as_char() == ',') {
+                struct_name.pop();
+            }
+
+            Ok(((), rest))
+        })?;
+
+        input.parse::<Option<Token![,]>>()?;
+        let struct_name = struct_name.into_iter().collect();
+        Ok(ParsedMatchPattern { struct_name, group })
+    }
+}
+
+impl ParsedMatchPattern {
+    fn into_matcher_expr(self) -> TokenStream {
+        let Self { struct_name, group } = self;
+        // `matcher_pattern` supports both its custom (not necessarily valid rust)
+        // syntax and also native match pattern (like `Struct { .. }` and
+        // `Struct(_)`). So we need to speculatively attempt the first and then
+        // fall back to the latter if the first fails. If both fail, we return
+        // the error from the first attempt.
+        let mut first_err = None;
+
+        // `matcher_pattern` special syntax.
+        if let Some(ref g) = group {
+            let res = match g.delimiter() {
+                Delimiter::Parenthesis => parse_tuple_pattern_args(struct_name.clone(), g.stream()),
+                Delimiter::Brace => parse_braced_pattern_args(struct_name.clone(), g.stream()),
+                Delimiter::Bracket => compile_err(g.span(), "[...] syntax is not meaningful"),
+                Delimiter::None => compile_err(g.span(), "undelimited group not supported"),
+            };
+            match res {
+                Ok(res) => return res,
+                Err(e) => first_err = Some(e),
+            }
+        }
+
+        // Standard `match` pattern (prioritize `first_err` if both fail).
+        into_match_pattern_expr(quote! { #struct_name #group })
+            .map_err(|e| first_err.unwrap_or(e))
+            .unwrap_or_else(syn::Error::into_compile_error)
+    }
+}
+
+/// Returns a pattern match expression as long as `stream` is a valid pattern.
+/// Otherwise, returns failure.
+fn into_match_pattern_expr(stream: TokenStream) -> syn::Result<TokenStream> {
+    // Only produce if stream successfully parses as a pattern. Otherwise, return
+    // failure so that we can instead return the error due to failing to parse
+    // the `matcher_pattern` custom syntax.
+    Pat::parse_multi.parse2(stream.clone())?;
+    Ok(quote! {
+        googletest::matchers::__internal_unstable_do_not_depend_on_these::pattern_only(
+            |v| matches!(v, #stream),
+            concat!("is ", stringify!(#stream)),
+            concat!("is not ", stringify!(#stream)))
+    })
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Parse tuple struct patterns
+
+/// Each part in a tuple matcher pattern that's between the commas for use with
+/// `Punctuated`'s parser.
+struct TupleFieldPattern {
+    ref_token: Option<Token![ref]>,
+    matcher: Expr,
+}
+
+impl Parse for TupleFieldPattern {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        let ref_token = input.parse()?;
+        let matcher = input.parse()?;
+        match matcher {
+            // `_` is an expr in const generics contexts, but is not supported in regular
+            // `Expr` use like in the `matches_pattern` custom syntax. So fail in that case.
+            // That should allow `into_match_expr` above to fall back to `into_match_pattern_expr`
+            // and still attempt to parse `matcher` as a pattern.
+            Expr::Infer(ExprInfer { underscore_token, .. }) => compile_err(
+                underscore_token.spans[0],
+                "unexpected `_` for `matches_pattern!` tuple field matcher",
+            ),
+            _ => Ok(TupleFieldPattern { ref_token, matcher }),
+        }
+    }
+}
+
+/// Parses a tuple struct's fields into a match expression.
+fn parse_tuple_pattern_args(
+    struct_name: TokenStream,
+    group_content: TokenStream,
+) -> syn::Result<TokenStream> {
+    let parser = Punctuated::<TupleFieldPattern, Token![,]>::parse_terminated;
+    let fields = parser.parse2(group_content)?.into_iter().enumerate().map(
+        |(index, TupleFieldPattern { ref_token, matcher })| {
+            let index = syn::Index::from(index);
+            quote! { googletest::matchers::field!(#struct_name.#index, #ref_token #matcher) }
+        },
+    );
+    Ok(quote! {
+        googletest::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!(#struct_name),
+            all!( #(#fields),* )
+        )
+    })
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Parse braced structs patterns
+
+enum FieldOrMethod {
+    Field(Ident),
+    Method(ExprCall),
+}
+
+impl Parse for FieldOrMethod {
+    /// Parses the field name or method call along with the `:` that follows it.
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        let value = if input.peek2(Token![:]) {
+            input.parse().map(FieldOrMethod::Field)
+        } else {
+            input.parse().map(FieldOrMethod::Method)
+        }?;
+        input.parse::<Token![:]>()?;
+        Ok(value)
+    }
+}
+
+/// Either field or method call matcher. E.g.:
+/// * `field: starts_with("something")`
+/// * `property(arg1, arg2): starts_with("something")
+struct FieldOrMethodPattern {
+    ref_token: Option<Token![ref]>,
+    field_or_method: FieldOrMethod,
+    matcher: Expr,
+}
+
+impl Parse for FieldOrMethodPattern {
+    fn parse(input: ParseStream) -> syn::Result<Self> {
+        Ok(FieldOrMethodPattern {
+            field_or_method: input.parse()?,
+            ref_token: input.parse()?,
+            matcher: input.parse()?,
+        })
+    }
+}
+
+/// Parses a struct's fields or method calls into a match expression.
+fn parse_braced_pattern_args(
+    struct_name: TokenStream,
+    group_content: TokenStream,
+) -> syn::Result<TokenStream> {
+    let parser = Punctuated::<FieldOrMethodPattern, Token![,]>::parse_terminated;
+    let fields = parser.parse2(group_content)?.into_iter().map(
+        |FieldOrMethodPattern { ref_token, field_or_method, matcher }| match field_or_method {
+            FieldOrMethod::Field(ident) => {
+                quote! { field!(#struct_name . #ident, #ref_token #matcher) }
+            }
+            FieldOrMethod::Method(call) => {
+                quote! { property!(#struct_name . #call, #ref_token #matcher) }
+            }
+        },
+    );
+
+    Ok(quote! {
+        googletest::matchers::__internal_unstable_do_not_depend_on_these::is(
+            stringify!(#struct_name),
+            all!( #(#fields),* )
+        )
+    })
+}
+
+fn compile_err<T>(span: Span, message: &str) -> syn::Result<T> {
+    Err(syn::Error::new(span, message))
+}