Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/ensure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,11 @@ macro_rules! __parse_ensure {
};

(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($const:tt $block:tt $($dup:tt)*) const {$($body:tt)*} $($rest:tt)*) => {
// TODO: this is mostly useless due to https://github.com/rust-lang/rust/issues/86730
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* $const $block) $($parse)*} ($($rest)*) $($rest)*)
// Parenthesized so that the const block is behind a token tree group by
// the time it reaches __fancy_ensure's `:expr` matcher, which does not
// accept a bare const block before the 2024 edition.
// https://github.com/rust-lang/rust/issues/86730
$crate::__parse_ensure!(atom $stack $bail ($($fuel)*) {($($buf)* ($const $block)) $($parse)*} ($($rest)*) $($rest)*)
};

(0 $stack:tt $bail:tt (~$($fuel:tt)*) {($($buf:tt)*) $($parse:tt)*} ($literal:tt $($dup:tt)*) $lit:literal $($rest:tt)*) => {
Expand Down Expand Up @@ -932,4 +935,14 @@ macro_rules! __fallback_ensure {
return $crate::__private::Err($crate::__anyhow!($fmt, $($arg)*));
}
};

// A condition beginning with a const block is not accepted by the `:expr`
// matcher before the 2024 edition, so put it behind a token tree group and
// re-dispatch. https://github.com/rust-lang/rust/issues/86730
//
// This arm goes last so that a malformed invocation such as `ensure!()`
// still reports the `$cond:expr` above as the thing it failed to match.
(const $cond:block $($rest:tt)*) => {
$crate::__fallback_ensure!((const $cond) $($rest)*)
};
}
53 changes: 53 additions & 0 deletions tests/test_ensure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
clippy::match_bool,
clippy::needless_else,
clippy::never_loop,
clippy::nonminimal_bool,
clippy::overly_complex_bool_expr,
clippy::ptr_cast_constness,
clippy::redundant_closure_call,
Expand Down Expand Up @@ -294,6 +295,58 @@ fn test_loop() {
);
}

#[test]
fn test_const_block() {
#[rustfmt::skip]
let test = || Ok(ensure!(const { 1 + 1 } == 3));
assert_err(
test,
"Condition failed: `(const { 1 + 1 }) == 3` (2 vs 3)",
);

#[rustfmt::skip]
let test = || Ok(ensure!(3 == const { 1 + 1 }));
assert_err(
test,
"Condition failed: `3 == (const { 1 + 1 })` (3 vs 2)",
);

#[rustfmt::skip]
let test = || Ok(ensure!(const { 1 } == const { 2 }));
assert_err(
test,
"Condition failed: `(const { 1 }) == (const { 2 })` (1 vs 2)",
);

#[rustfmt::skip]
let test = || Ok(ensure!(1 + const { 1 } == 3));
assert_err(
test,
"Condition failed: `1 + (const { 1 }) == 3` (2 vs 3)",
);

#[rustfmt::skip]
let test = || Ok(ensure!([const { 1 }][0] == 2));
assert_err(
test,
"Condition failed: `[const { 1 }][0] == 2` (1 vs 2)",
);

// Conditions that do not go through the comparison machinery.

#[rustfmt::skip]
let test = || Ok(ensure!(const { false }));
assert_err(test, "Condition failed: `(const { false })`");

#[rustfmt::skip]
let test = || Ok(ensure!(const { false } && true));
assert_err(test, "Condition failed: `(const { false }) && true`");

#[rustfmt::skip]
let test = || Ok(ensure!(true && const { false }));
assert_err(test, "Condition failed: `true && const { false }`");
}

#[test]
fn test_match() {
#[rustfmt::skip]
Expand Down