Skip to content

Commit ecc410d

Browse files
authored
Use #[kani::proof] for both sync and async functions (instead of #[kani::async_proof] for async) (rust-lang#1471)
1 parent ef7639e commit ecc410d

File tree

4 files changed

+62
-73
lines changed

4 files changed

+62
-73
lines changed

library/kani_macros/src/lib.rs

Lines changed: 55 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use {
1919
#[cfg(all(not(kani), not(test)))]
2020
#[proc_macro_attribute]
2121
pub fn proof(_attr: TokenStream, _item: TokenStream) -> TokenStream {
22-
// Not-Kani, Not-Test means this code shouldn't exist, return nothing.
22+
// Not-Kani, not-test means this code shouldn't exist, return nothing.
2323
TokenStream::new()
2424
}
2525

@@ -39,73 +39,68 @@ pub fn proof(_attr: TokenStream, item: TokenStream) -> TokenStream {
3939
// )
4040
}
4141

42+
/// Marks a Kani proof harness
43+
///
44+
/// For async harnesses, this will call [`kani::block_on`] (see its documentation for more information).
4245
#[cfg(kani)]
4346
#[proc_macro_attribute]
4447
pub fn proof(attr: TokenStream, item: TokenStream) -> TokenStream {
45-
let mut result = TokenStream::new();
46-
47-
assert!(attr.is_empty(), "#[kani::proof] does not take any arguments");
48-
result.extend("#[kanitool::proof]".parse::<TokenStream>().unwrap());
49-
// no_mangle is a temporary hack to make the function "public" so it gets codegen'd
50-
result.extend("#[no_mangle]".parse::<TokenStream>().unwrap());
51-
result.extend(item);
52-
result
53-
// quote!(
54-
// #[kanitool::proof]
55-
// $item
56-
// )
57-
}
58-
59-
#[cfg(not(kani))]
60-
#[proc_macro_attribute]
61-
/// Treats #[kani::async_proof] like a normal #[kani::proof] if Kani is not active
62-
pub fn async_proof(attr: TokenStream, item: TokenStream) -> TokenStream {
63-
proof(attr, item)
64-
}
65-
66-
#[cfg(kani)]
67-
#[proc_macro_attribute]
68-
/// Translates #[kani::async_proof] to a #[kani::proof] harness that calls `kani::block_on`, if Kani is active
69-
///
70-
/// Specifically, it translates
71-
/// ```ignore
72-
/// #[kani::async_proof]
73-
/// #[attribute]
74-
/// pub async fn harness() { ... }
75-
/// ```
76-
/// to
77-
/// ```ignore
78-
/// #[kani::proof]
79-
/// #[attribute]
80-
/// pub fn harness() {
81-
/// async fn harness() { ... }
82-
/// kani::block_on(harness())
83-
/// }
84-
/// ```
85-
pub fn async_proof(attr: TokenStream, item: TokenStream) -> TokenStream {
86-
assert!(attr.is_empty(), "#[kani::async_proof] does not take any arguments for now");
8748
let fn_item = parse_macro_input!(item as ItemFn);
8849
let attrs = fn_item.attrs;
8950
let vis = fn_item.vis;
9051
let sig = fn_item.sig;
91-
assert!(sig.asyncness.is_some(), "#[kani::async_proof] can only be applied to async functions");
92-
assert!(
93-
sig.inputs.is_empty(),
94-
"#[kani::async_proof] can only be applied to functions without inputs"
95-
);
96-
let mut modified_sig = sig.clone();
97-
modified_sig.asyncness = None;
9852
let body = fn_item.block;
99-
let fn_name = &sig.ident;
100-
quote!(
101-
#[kani::proof]
102-
#(#attrs)*
103-
#vis #modified_sig {
104-
#sig #body
105-
kani::block_on(#fn_name())
106-
}
107-
)
108-
.into()
53+
54+
let kani_attributes = quote!(
55+
#[kanitool::proof]
56+
// no_mangle is a temporary hack to make the function "public" so it gets codegen'd
57+
#[no_mangle]
58+
);
59+
60+
assert!(attr.is_empty(), "#[kani::proof] does not take any arguments for now");
61+
62+
if sig.asyncness.is_none() {
63+
// Adds `#[kanitool::proof]` and other attributes
64+
quote!(
65+
#kani_attributes
66+
#(#attrs)*
67+
#vis #sig #body
68+
)
69+
.into()
70+
} else {
71+
// For async functions, it translates to a synchronous function that calls `kani::block_on`.
72+
// Specifically, it translates
73+
// ```ignore
74+
// #[kani::async_proof]
75+
// #[attribute]
76+
// pub async fn harness() { ... }
77+
// ```
78+
// to
79+
// ```ignore
80+
// #[kani::proof]
81+
// #[attribute]
82+
// pub fn harness() {
83+
// async fn harness() { ... }
84+
// kani::block_on(harness())
85+
// }
86+
// ```
87+
assert!(
88+
sig.inputs.is_empty(),
89+
"#[kani::proof] cannot be applied to async functions that take inputs for now"
90+
);
91+
let mut modified_sig = sig.clone();
92+
modified_sig.asyncness = None;
93+
let fn_name = &sig.ident;
94+
quote!(
95+
#kani_attributes
96+
#(#attrs)*
97+
#vis #modified_sig {
98+
#sig #body
99+
kani::block_on(#fn_name())
100+
}
101+
)
102+
.into()
103+
}
109104
}
110105

111106
#[cfg(not(kani))]

tests/expected/async_proof/expected

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
error: custom attribute panicked
2-
#[kani::async_proof] does not take any arguments for now
2+
#[kani::proof] does not take any arguments for now
33

44
error: custom attribute panicked
5-
#[kani::async_proof] can only be applied to async functions
6-
7-
error: custom attribute panicked
8-
#[kani::async_proof] can only be applied to functions without inputs
5+
#[kani::proof] cannot be applied to async functions that take inputs for now

tests/expected/async_proof/main.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@
33
//
44
// compile-flags: --edition 2018
55

6-
// Tests that the #[kani::async_proof] attribute works correctly
6+
// Tests that the #[kani::proof] attribute works correctly for async functions
77

88
fn main() {}
99

10-
#[kani::async_proof(foo)]
10+
#[kani::proof(foo)]
1111
async fn test_async_proof_with_arguments() {}
1212

13-
#[kani::async_proof]
14-
fn test_async_proof_on_sync_function() {}
15-
16-
#[kani::async_proof]
13+
#[kani::proof]
1714
async fn test_async_proof_on_function_with_inputs(_: ()) {}

tests/kani/AsyncAwait/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ use std::{
1313

1414
fn main() {}
1515

16-
#[kani::async_proof]
16+
#[kani::proof]
1717
#[kani::unwind(2)]
1818
async fn test_async_proof_harness() {
1919
let async_block_result = async { 42 }.await;
2020
let async_fn_result = async_fn().await;
2121
assert_eq!(async_block_result, async_fn_result);
2222
}
2323

24-
#[kani::async_proof]
24+
#[kani::proof]
2525
#[kani::unwind(2)]
2626
pub async fn test_async_proof_harness_pub() {
2727
let async_block_result = async { 42 }.await;

0 commit comments

Comments
 (0)