Repository: dtolnay/anyhow
Pull request #194 (2021-11-22 06:59:02)

Add a cap on ensure macro recursion depth
**Before:**

```console
error: recursion limit reached while expanding `$crate::__parse_ensure!`
  --> tests/test_ensure.rs:50:22
   |
50 |       let test = || Ok(ensure!(
   |  ______________________^
51 | |         false | false | false | false | false | false | false | false | false |
52 | |         false | false | false | false | false | false | false | false | false |
53 | |         false | false | false | false | false | false | false | false | false |
...  |
57 | |         false | false | false | false | false | false | false | false | false
58 | |     ));
   | |_____^
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`test_ensure`)
   = note: this error originates in the macro `$crate::__parse_ensure` (in Nightly builds, run with -Z macro-backtrace for more info)
```

<br>

**After:** we recurse to a maximum of 120 macro calls before bailing out and rendering a fallback message without the lhs/rhs.


Patch:
diff --git a/src/ensure.rs b/src/ensure.rs
index 4e868ff..95d60dd 100644
--- a/src/ensure.rs
+++ b/src/ensure.rs
@@ -30,394 +30,394 @@ impl<A, B> NotBothDebug for &(A, B) {
 #[doc(hidden)]
 #[macro_export]
 macro_rules! __parse_ensure {
-    (atom () $bail:tt {($($rhs:tt)+) ($($lhs:tt)+) $op:tt} $(,)?) => {
+    (atom () $bail:tt $fuel:tt {($($rhs:tt)+) ($($lhs:tt)+) $op:tt} $(,)?) => {
         $crate::__fancy_ensure!($($lhs)+, $op, $($rhs)+)
     };
 
     // low precedence control flow constructs
 
-    (0 $stack:tt ($($bail:tt)*) $parse:tt return $($rest:tt)*) => {
+    (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt return $($rest:tt)*) => {
         $crate::__fallback_ensure!($($bail)*)
     };
 
-    (0 $stack:tt ($($bail:tt)*) $parse:tt break $($rest:tt)*) => {
+    (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt break $($rest:tt)*) => {
         $crate::__fallback_ensure!($($bail)*)
     };
 
-    (0 $stack:tt ($($bail:tt)*) $parse:tt continue $($rest:tt)*) => {
+    (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt continue $($rest:tt)*) => {
         $crate::__fallback_ensure!($($bail)*)
     };
 
-    (0 $stack:tt ($($bail:tt)*) $parse:tt yield $($rest:tt)*) => {
+    (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt yield $($rest:tt)*) => {
         $crate::__fallback_ensure!($($bail)*)
     };
 
-    (0 $stack:tt ($($bail:tt)*) $parse:tt move $($rest:tt)*) => {
+    (0 $stack:tt ($($bail:tt)*) $fuel:tt $parse:tt move $($rest:tt)*) => {
         $crate::__fallback_ensure!($($bail)*)
     };
 
     // unary operators
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} * $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* *) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} * $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* *) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ! $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* !) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ! $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* !) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} - $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* -) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} - $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* -) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} let $(|)? $($pat:pat)|+ = $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* let $($pat)|+ =) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} let $(|)? $($pat:pat)|+ = $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* let $($pat)|+ =) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $life:lifetime : $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* $life :) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $life:lifetime : $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* $life :) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} &mut $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* &mut) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} &mut $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* &mut) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} & $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* &) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} & $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* &) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} &&mut $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* &&mut) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} &&mut $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* &&mut) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} && $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* &&) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} && $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* &&) $($parse)*} $($rest)*)
     };
 
     // control flow constructs
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} if $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 (cond $stack) $bail {($($buf)* if) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} if $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* if) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} match $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 (cond $stack) $bail {($($buf)* match) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} match $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* match) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} while $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 (cond $stack) $bail {($($buf)* while) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} while $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* while) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} for $(|)? $($pat:pat)|+ in $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 (cond $stack) $bail {($($buf)* for $($pat)|+ in) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} for $(|)? $($pat:pat)|+ in $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* for $($pat)|+ in) $($parse)*} $($rest)*)
     };
 
-    (atom (cond $stack:tt) $bail:tt {($($buf:tt)*) $($parse:tt)*} {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(cond $stack $bail {($($buf)* {$($block)*}) $($parse)*} $($rest)*)
+    (atom (cond $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(cond $stack $bail ($($fuel)*) {($($buf)* {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (cond $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} else if $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 (cond $stack) $bail {($($buf)* else if) $($parse)*} $($rest)*)
+    (cond $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} else if $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 (cond $stack) $bail ($($fuel)*) {($($buf)* else if) $($parse)*} $($rest)*)
     };
 
-    (cond $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} else {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* else {$($block)*}) $($parse)*} $($rest)*)
+    (cond $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} else {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* else {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (cond $stack:tt $bail:tt $parse:tt $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail $parse $($rest)*)
+    (cond $stack:tt $bail:tt (~$($fuel:tt)*) $parse:tt $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) $parse $($rest)*)
     };
 
     // atomic expressions
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ($($paren:tt)*) $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* ($($paren)*)) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($($paren:tt)*) $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ($($paren)*)) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} [$($array:tt)*] $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* [$($array)*]) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} [$($array:tt)*] $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* [$($array)*]) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* {$($block)*}) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} loop {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* loop {$($block)*}) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} loop {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* loop {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} async {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* async {$($block)*}) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} async {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* async {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} async move {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* async move {$($block)*}) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} async move {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* async move {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} unsafe {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* unsafe {$($block)*}) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} unsafe {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* unsafe {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $lit:literal $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* $lit) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $lit:literal $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $lit) $($parse)*} $($rest)*)
     };
 
     // path expressions
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} :: $($rest:tt)*) => {
-        $crate::__parse_ensure!(path $stack $bail {($($buf)* ::) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} :: $($rest:tt)*) => {
+        $crate::__parse_ensure!(path $stack $bail ($($fuel)*) {($($buf)* ::) $($parse)*} $($rest)*)
     };
 
-    (0 $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $ident:ident $($rest:tt)*) => {
-        $crate::__parse_ensure!(component $stack $bail {($($buf)* $ident) $($parse)*} $($rest)*)
+    (0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $ident:ident $($rest:tt)*) => {
+        $crate::__parse_ensure!(component $stack $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} $($rest)*)
     };
 
-    (path $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $ident:ident $($rest:tt)*) => {
-        $crate::__parse_ensure!(component $stack $bail {($($buf)* $ident) $($parse)*} $($rest)*)
+    (path $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $ident:ident $($rest:tt)*) => {
+        $crate::__parse_ensure!(component $stack $bail ($($fuel)*) {($($buf)* $ident) $($parse)*} $($rest)*)
     };
 
-    (component $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} :: < $($rest:tt)*) => {
-        $crate::__parse_ensure!(generic (component $stack) $bail {($($buf)* :: <) $($parse)*} $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} :: < $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (component $stack) $bail ($($fuel)*) {($($buf)* :: <) $($parse)*} $($rest)*)
     };
 
-    (component $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} :: << $($rest:tt)*) => {
-        $crate::__parse_ensure!(generic (component $stack) $bail {($($buf)* :: <) $($parse)*} < $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} :: << $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (component $stack) $bail ($($fuel)*) {($($buf)* :: <) $($parse)*} < $($rest)*)
     };
 
-    (component $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} :: $($rest:tt)*) => {
-        $crate::__parse_ensure!(path $stack $bail {($($buf)* ::) $($parse)*} $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} :: $($rest:tt)*) => {
+        $crate::__parse_ensure!(path $stack $bail ($($fuel)*) {($($buf)* ::) $($parse)*} $($rest)*)
     };
 
     // macro invocations
 
-    (component $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ! ($($mac:tt)*) $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* ! ($($mac)*)) $($parse)*} $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ! ($($mac:tt)*) $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ! ($($mac)*)) $($parse)*} $($rest)*)
     };
 
-    (component $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ! [$($mac:tt)*] $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* ! [$($mac)*]) $($parse)*} $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ! [$($mac:tt)*] $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ! [$($mac)*]) $($parse)*} $($rest)*)
     };
 
-    (component $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ! {$($mac:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* ! {$($mac)*}) $($parse)*} $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ! {$($mac:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ! {$($mac)*}) $($parse)*} $($rest)*)
     };
 
-    (component $stack:tt $bail:tt $parse:tt $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail $parse $($rest)*)
+    (component $stack:tt $bail:tt (~$($fuel:tt)*) $parse:tt $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) $parse $($rest)*)
     };
 
     // trailer expressions
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ($($call:tt)*) $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* ($($call)*)) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($($call:tt)*) $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ($($call)*)) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} [$($index:tt)*] $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* [$($index)*]) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} [$($index:tt)*] $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* [$($index)*]) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} {$($init:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* {$($init)*}) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} {$($init:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* {$($init)*}) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ? $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* ?) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ? $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ?) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} . $ident:ident :: < $($rest:tt)*) => {
-        $crate::__parse_ensure!(generic (atom $stack) $bail {($($buf)* . $ident :: <) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} . $ident:ident :: < $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* . $ident :: <) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} . $ident:ident :: << $($rest:tt)*) => {
-        $crate::__parse_ensure!(generic (atom $stack) $bail {($($buf)* . $ident :: <) $($parse)*} < $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} . $ident:ident :: << $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic (atom $stack) $bail ($($fuel)*) {($($buf)* . $ident :: <) $($parse)*} < $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} . $ident:ident $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* . $ident) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} . $ident:ident $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* . $ident) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} . $lit:tt $($rest:tt)*) => {
-        $crate::__parse_ensure!(atom $stack $bail {($($buf)* . $lit) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} . $lit:tt $($rest:tt)*) => {
+        $crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* . $lit) $($parse)*} $($rest)*)
     };
 
     // angle bracketed generic arguments
 
-    (generic ($pop:ident $stack:tt) $bail:tt {($($buf:tt)*) $($parse:tt)*} > $($rest:tt)*) => {
-        $crate::__parse_ensure!($pop $stack $bail {($($buf)* >) $($parse)*} $($rest)*)
+    (generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} > $($rest:tt)*) => {
+        $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* >) $($parse)*} $($rest)*)
     };
 
-    (generic $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $lit:literal $($rest:tt)*) => {
-        $crate::__parse_ensure!(arglist $stack $bail {($($buf)* $lit) $($parse)*} $($rest)*)
+    (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $lit:literal $($rest:tt)*) => {
+        $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $lit) $($parse)*} $($rest)*)
     };
 
-    (generic $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} {$($block:tt)*} $($rest:tt)*) => {
-        $crate::__parse_ensure!(arglist $stack $bail {($($buf)* {$($block)*}) $($parse)*} $($rest)*)
+    (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} {$($block:tt)*} $($rest:tt)*) => {
+        $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* {$($block)*}) $($parse)*} $($rest)*)
     };
 
-    (generic $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $life:lifetime $($rest:tt)*) => {
-        $crate::__parse_ensure!(arglist $stack $bail {($($buf)* $life) $($parse)*} $($rest)*)
+    (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $life:lifetime $($rest:tt)*) => {
+        $crate::__parse_ensure!(arglist $stack $bail ($($fuel)*) {($($buf)* $life) $($parse)*} $($rest)*)
     };
 
-    (generic $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} $ty:ty , $($rest:tt)*) => {
-        $crate::__parse_ensure!(generic $stack $bail {($($buf)* $ty ,) $($parse)*} $($rest)*)
+    (generic $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $ty:ty , $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* $ty ,) $($parse)*} $($rest)*)
     };
 
-    (generic ($pop:ident $stack:tt) $bail:tt {($($buf:tt)*) $($parse:tt)*} $ty:ty > $($rest:tt)*) => {
-        $crate::__parse_ensure!($pop $stack $bail {($($buf)* $ty >) $($parse)*} $($rest)*)
+    (generic ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} $ty:ty > $($rest:tt)*) => {
+        $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* $ty >) $($parse)*} $($rest)*)
     };
 
-    (arglist $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} , $($rest:tt)*) => {
-        $crate::__parse_ensure!(generic $stack $bail {($($buf)* ,) $($parse)*} $($rest)*)
+    (arglist $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} , $($rest:tt)*) => {
+        $crate::__parse_ensure!(generic $stack $bail ($($fuel)*) {($($buf)* ,) $($parse)*} $($rest)*)
     };
 
-    (arglist ($pop:ident $stack:tt) $bail:tt {($($buf:tt)*) $($parse:tt)*} > $($rest:tt)*) => {
-        $crate::__parse_ensure!($pop $stack $bail {($($buf)* >) $($parse)*} $($rest)*)
+    (arglist ($pop:ident $stack:tt) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} > $($rest:tt)*) => {
+        $crate::__parse_ensure!($pop $stack $bail ($($fuel)*) {($($buf)* >) $($parse)*} $($rest)*)
     };
 
     // high precedence binary operators
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} + $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* +) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} + $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* +) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} - $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* -) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} - $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* -) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} * $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* *) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} * $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* *) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} / $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* /) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} / $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* /) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} % $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* %) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} % $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* %) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} ^ $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* ^) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ^ $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* ^) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} & $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* &) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} & $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* &) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} | $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* |) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} | $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* |) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} << $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* <<) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} << $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* <<) $($parse)*} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)*) $($parse:tt)*} >> $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* >>) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} >> $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* >>) $($parse)*} $($rest)*)
     };
 
     // comparison binary operators
 
-    (atom () $bail:tt {($($buf:tt)*) $($parse:tt)*} == $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 () $bail {() $($parse)* ($($buf)*) ==} $($rest)*)
+    (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} == $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) ==} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)+) $($parse:tt)*} == $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* ==) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} == $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* ==) $($parse)*} $($rest)*)
     };
 
-    (atom () $bail:tt {($($buf:tt)*) $($parse:tt)*} <= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 () $bail {() $($parse)* ($($buf)*) <=} $($rest)*)
+    (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} <= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) <=} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)+) $($parse:tt)*} <= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* <=) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} <= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* <=) $($parse)*} $($rest)*)
     };
 
-    (atom () $bail:tt {($($buf:tt)*) $($parse:tt)*} < $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 () $bail {() $($parse)* ($($buf)*) <} $($rest)*)
+    (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} < $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) <} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)+) $($parse:tt)*} < $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* <) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} < $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* <) $($parse)*} $($rest)*)
     };
 
-    (atom () $bail:tt {($($buf:tt)*) $($parse:tt)*} != $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 () $bail {() $($parse)* ($($buf)*) !=} $($rest)*)
+    (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} != $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) !=} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)+) $($parse:tt)*} != $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* !=) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} != $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* !=) $($parse)*} $($rest)*)
     };
 
-    (atom () $bail:tt {($($buf:tt)*) $($parse:tt)*} >= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 () $bail {() $($parse)* ($($buf)*) >=} $($rest)*)
+    (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} >= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) >=} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)+) $($parse:tt)*} >= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* >=) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} >= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* >=) $($parse)*} $($rest)*)
     };
 
-    (atom () $bail:tt {($($buf:tt)*) $($parse:tt)*} > $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 () $bail {() $($parse)* ($($buf)*) >} $($rest)*)
+    (atom () $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} > $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 () $bail ($($fuel)*) {() $($parse)* ($($buf)*) >} $($rest)*)
     };
 
-    (atom $stack:tt $bail:tt {($($buf:tt)+) $($parse:tt)*} > $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 $stack $bail {($($buf)* >) $($parse)*} $($rest)*)
+    (atom $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)+) $($parse:tt)*} > $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 $stack $bail ($($fuel)*) {($($buf)* >) $($parse)*} $($rest)*)
     };
 
     // low precedence binary operators
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} && $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* &&) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} && $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* &&) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} || $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* ||) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} || $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* ||) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} = $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* =) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} = $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* =) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} += $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* +=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} += $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* +=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} -= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* -=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} -= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* -=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} *= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* *=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} *= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* *=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} /= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* /=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} /= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* /=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} %= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* %=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} %= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* %=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} ^= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* ^=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ^= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* ^=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} &= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* &=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} &= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* &=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} |= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* |=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} |= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* |=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} <<= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* <<=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} <<= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* <<=) $($parse)*} $($rest)*)
     };
 
-    (atom ($($stack:tt)+) $bail:tt {($($buf:tt)*) $($parse:tt)*} >>= $($rest:tt)*) => {
-        $crate::__parse_ensure!(0 ($($stack)*) $bail {($($buf)* >>=) $($parse)*} $($rest)*)
+    (atom ($($stack:tt)+) $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} >>= $($rest:tt)*) => {
+        $crate::__parse_ensure!(0 ($($stack)*) $bail ($($fuel)*) {($($buf)* >>=) $($parse)*} $($rest)*)
     };
 
     // unrecognized expression
diff --git a/src/macros.rs b/src/macros.rs
index 643b2e5..140b91a 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -164,7 +164,14 @@ macro_rules! ensure {
 #[macro_export]
 macro_rules! ensure {
     ($($tt:tt)*) => {
-        $crate::__parse_ensure!(0 () ($($tt)*) {()} $($tt)*)
+        $crate::__parse_ensure!(
+            /* state */ 0
+            /* stack */ ()
+            /* bail */ ($($tt)*)
+            /* fuel */ (~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~)
+            /* parse */ {()}
+            /* rest */ $($tt)*
+        )
     };
 }
 


Test patch:
diff --git a/tests/test_ensure.rs b/tests/test_ensure.rs
index 18c81b8..3b67413 100644
--- a/tests/test_ensure.rs
+++ b/tests/test_ensure.rs
@@ -43,6 +43,23 @@ fn assert_err<T: Debug>(result: impl FnOnce() -> Result<T>, expected: &'static s
     assert_eq!(actual, expected);
 }
 
+#[test]
+fn test_recursion() {
+    // Must not blow the default #[recursion_limit], which is 128.
+    #[rustfmt::skip]
+    let test = || Ok(ensure!(
+        false | false | false | false | false | false | false | false | false |
+        false | false | false | false | false | false | false | false | false |
+        false | false | false | false | false | false | false | false | false |
+        false | false | false | false | false | false | false | false | false |
+        false | false | false | false | false | false | false | false | false |
+        false | false | false | false | false | false | false | false | false |
+        false | false | false | false | false | false | false | false | false
+    ));
+
+    test().unwrap_err();
+}
+
 #[test]
 fn test_low_precedence_control_flow() {
     #[allow(unreachable_code)]