@@ -237,14 +237,14 @@ mod sysroot {
237237 /// Rewrites function contract annotations (`requires`, `ensures`) by lifing
238238 /// the condition into a separate function. As an example: (using `ensures`)
239239 ///
240- /// ```rs
240+ /// ```ignore
241241 /// #[kani::ensures(x < result)]
242242 /// fn foo(x: u32) -> u32 { .. }
243243 /// ```
244244 ///
245245 /// Is rewritten to
246246 ///
247- /// ```rs
247+ /// ```ignore
248248 /// fn foo_ensures_<hash of foo>(x: u32, result: u32) {
249249 /// x < result
250250 /// }
@@ -258,66 +258,68 @@ mod sysroot {
258258 ///
259259 /// This macro is supposed to be called with the name of the procedural
260260 /// macro it should generate, e.g. `requires_ensures(requires)`
261- macro_rules! requires_ensures {
262- ( $name: ident) => {
263- pub fn $name( attr: TokenStream , item: TokenStream ) -> TokenStream {
264- use syn:: { FnArg , PatType , PatIdent , Pat , Signature , Token , ReturnType , TypeTuple , punctuated:: Punctuated , Type } ;
265- use proc_macro2:: Span ;
266- let attr = proc_macro2:: TokenStream :: from( attr) ;
261+ fn handle_requires_ensures ( name : & str , attr : TokenStream , item : TokenStream ) -> TokenStream {
262+ use proc_macro2:: Span ;
263+ use syn:: {
264+ punctuated:: Punctuated , FnArg , Pat , PatIdent , PatType , ReturnType , Signature , Token ,
265+ Type , TypeTuple ,
266+ } ;
267+ let attr = proc_macro2:: TokenStream :: from ( attr) ;
267268
268- let a_short_hash = short_hash_of_token_stream( & item) ;
269+ let a_short_hash = short_hash_of_token_stream ( & item) ;
269270
270- let item_fn @ ItemFn { sig, .. } = & parse_macro_input!( item as ItemFn ) ;
271- let Signature { inputs, output , .. } = sig;
271+ let item_fn @ ItemFn { sig, .. } = & parse_macro_input ! ( item as ItemFn ) ;
272+ let Signature { inputs, output, .. } = sig;
272273
273- let gen_fn_name = identifier_for_generated_function( item_fn, stringify!( $name) , a_short_hash) ;
274- let attribute = format_ident!( "{}" , stringify!( $name) ) ;
275- let kani_attributes = quote!(
276- #[ allow( dead_code) ]
277- #[ kanitool:: #attribute = stringify!( #gen_fn_name) ]
278- ) ;
279-
280- let typ = match output {
281- ReturnType :: Type ( _, t) => t. clone( ) ,
282- _ => Box :: new( TypeTuple { paren_token: Default :: default ( ) , elems: Punctuated :: new( ) } . into( ) ) ,
283- } ;
284-
285- let mut gen_fn_inputs = inputs. clone( ) ;
286- gen_fn_inputs. push(
287- FnArg :: Typed ( PatType {
288- attrs: vec![ ] ,
289- pat: Box :: new( Pat :: Ident ( PatIdent {
290- attrs: vec![ ] ,
291- by_ref: None ,
292- mutability: None ,
293- ident: Ident :: new( "result" , Span :: call_site( ) ) ,
294- subpat: None ,
295- } ) ) ,
296- colon_token: Token ![ : ] ( Span :: call_site( ) ) ,
297- ty: typ,
298- } )
299- ) ;
300-
301- assert!( sig. variadic. is_none( ) , "Varaidic signatures are not supported" ) ;
302-
303- let mut gen_sig = sig. clone( ) ;
304- gen_sig. inputs = gen_fn_inputs;
305- gen_sig. output = ReturnType :: Type ( Default :: default ( ) , Box :: new( Type :: Verbatim ( quote!( bool ) ) ) ) ;
306- gen_sig. ident = gen_fn_name;
274+ let gen_fn_name = identifier_for_generated_function ( item_fn, name, a_short_hash) ;
275+ let attribute = format_ident ! ( "{name}" ) ;
276+ let kani_attributes = quote ! (
277+ #[ allow( dead_code) ]
278+ #[ kanitool:: #attribute = stringify!( #gen_fn_name) ]
279+ ) ;
307280
308- quote!(
309- #gen_sig {
310- #attr
311- }
312-
313- #kani_attributes
314- #item_fn
315- )
316- . into( )
281+ let typ = match output {
282+ ReturnType :: Type ( _, t) => t. clone ( ) ,
283+ _ => Box :: new (
284+ TypeTuple { paren_token : Default :: default ( ) , elems : Punctuated :: new ( ) } . into ( ) ,
285+ ) ,
286+ } ;
287+
288+ let mut gen_fn_inputs = inputs. clone ( ) ;
289+ gen_fn_inputs. push ( FnArg :: Typed ( PatType {
290+ attrs : vec ! [ ] ,
291+ pat : Box :: new ( Pat :: Ident ( PatIdent {
292+ attrs : vec ! [ ] ,
293+ by_ref : None ,
294+ mutability : None ,
295+ ident : Ident :: new ( "result" , Span :: call_site ( ) ) ,
296+ subpat : None ,
297+ } ) ) ,
298+ colon_token : Token ! [ : ] ( Span :: call_site ( ) ) ,
299+ ty : typ,
300+ } ) ) ;
301+
302+ assert ! ( sig. variadic. is_none( ) , "Variadic signatures are not supported" ) ;
303+
304+ let mut gen_sig = sig. clone ( ) ;
305+ gen_sig. inputs = gen_fn_inputs;
306+ gen_sig. output =
307+ ReturnType :: Type ( Default :: default ( ) , Box :: new ( Type :: Verbatim ( quote ! ( bool ) ) ) ) ;
308+ gen_sig. ident = gen_fn_name;
309+
310+ quote ! (
311+ #gen_sig {
312+ #attr
317313 }
318- }
314+
315+ #kani_attributes
316+ #item_fn
317+ )
318+ . into ( )
319319 }
320320
321+ /// Hash this `TokenStream` and return an integer that is at most digits
322+ /// long when hex formatted.
321323 fn short_hash_of_token_stream ( stream : & proc_macro:: TokenStream ) -> u64 {
322324 use std:: hash:: Hasher ;
323325 let mut hasher = std:: collections:: hash_map:: DefaultHasher :: default ( ) ;
@@ -326,6 +328,9 @@ mod sysroot {
326328 long_hash % 0x1_000_000 // six hex digits
327329 }
328330
331+ /// Makes consistent names for a generated function which was created for
332+ /// `purpose`, from an attribute that decorates `related_function` with the
333+ /// hash `hash`.
329334 fn identifier_for_generated_function (
330335 related_function : & ItemFn ,
331336 purpose : & str ,
@@ -335,8 +340,13 @@ mod sysroot {
335340 Ident :: new ( & identifier, proc_macro2:: Span :: mixed_site ( ) )
336341 }
337342
338- requires_ensures ! ( requires) ;
339- requires_ensures ! ( ensures) ;
343+ pub fn requires ( attr : TokenStream , item : TokenStream ) -> TokenStream {
344+ handle_requires_ensures ( "requires" , attr, item)
345+ }
346+
347+ pub fn ensures ( attr : TokenStream , item : TokenStream ) -> TokenStream {
348+ handle_requires_ensures ( "ensures" , attr, item)
349+ }
340350
341351 kani_attribute ! ( should_panic, no_args) ;
342352 kani_attribute ! ( solver) ;
0 commit comments