19
19
#[ cfg( all( not( kani) , not( test) ) ) ]
20
20
#[ proc_macro_attribute]
21
21
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.
23
23
TokenStream :: new ( )
24
24
}
25
25
@@ -39,73 +39,68 @@ pub fn proof(_attr: TokenStream, item: TokenStream) -> TokenStream {
39
39
// )
40
40
}
41
41
42
+ /// Marks a Kani proof harness
43
+ ///
44
+ /// For async harnesses, this will call [`kani::block_on`] (see its documentation for more information).
42
45
#[ cfg( kani) ]
43
46
#[ proc_macro_attribute]
44
47
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" ) ;
87
48
let fn_item = parse_macro_input ! ( item as ItemFn ) ;
88
49
let attrs = fn_item. attrs ;
89
50
let vis = fn_item. vis ;
90
51
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 ;
98
52
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
+ }
109
104
}
110
105
111
106
#[ cfg( not( kani) ) ]
0 commit comments