@@ -359,40 +359,38 @@ pub(crate) fn rewrite_verus_spec_on_fun_or_loop(
359359 AnyFnOrLoop :: Fn ( mut fun) => {
360360 // Note: trait default methods appear in this case,
361361 // since they look syntactically like non-trait functions
362- replace_block ( erase, fun. block_mut ( ) . unwrap ( ) ) ;
363362 let spec_attr =
364363 syn_verus:: parse_macro_input!( outer_attr_tokens as syn_verus:: SignatureSpecAttr ) ;
365364
366365 fun. attrs . push ( mk_verus_attr_syn ( fun. span ( ) , quote ! { verus_macro } ) ) ;
367366
367+ let mut new_stream = TokenStream :: new ( ) ;
368+
368369 // Create a copy of unverified function.
369370 // To avoid misuse of the unverified function,
370371 // we add `requires false` and thus prevent verified function to use it.
371372 // Allow unverified code to use the function without changing in/output.
372- let mut new_stream = TokenStream :: new ( ) ;
373373 if let Some ( with) = & spec_attr. spec . with {
374- let unverified_fun = rewrite_unverified_func ( & mut fun, with. with . span ( ) ) ;
375- unverified_fun . to_tokens ( & mut new_stream) ;
374+ let extra_funs = rewrite_unverified_func ( & mut fun, with. with . span ( ) ) ;
375+ extra_funs . iter ( ) . for_each ( |f| f . to_tokens ( & mut new_stream) ) ;
376376 }
377+
378+ // Update function signature based on verus_spec.
379+ let spec_stmts = syntax:: sig_specs_attr ( erase, spec_attr, & mut fun. sig ) ;
380+
381+ // Create const proxy function if it is a const function.
377382 if fun. sig . constness . is_some ( ) {
378- let mut const_fun = fun. clone ( ) ;
379- let span = fun. sig . constness . unwrap ( ) . span ( ) ;
380- // It seems that we do not need to erase anything.
381- // But just do it to be safe and consistent with verus macro.
382- replace_block ( EraseGhost :: Erase , const_fun. block_mut ( ) . unwrap ( ) ) ;
383- const_fun. attrs . push ( mk_verifier_attr_syn ( span, quote ! { external } ) ) ;
384- const_fun. attrs . push ( mk_verus_attr_syn ( span, quote ! { uses_unerased_proxy } ) ) ;
385- const_fun. attrs . push ( mk_verus_attr_syn ( span, quote ! { encoded_const } ) ) ;
386- const_fun. to_tokens ( & mut new_stream) ;
387- fun. sig . ident = syn:: Ident :: new (
388- & format ! ( "{VERUS_UNERASED_PROXY}{}" , fun. sig. ident) ,
389- fun. sig . ident . span ( ) ,
390- ) ;
391- fun. attrs . push ( mk_verus_attr_syn ( span, quote ! { unerased_proxy } ) ) ;
383+ let proxy = rewrite_const_ret_proxy ( & mut fun) ;
384+ fun. to_tokens ( & mut new_stream) ;
385+ fun = proxy; // Add proof and spec on proxy func.
392386 }
393- let spec_stmts = syntax:: sig_specs_attr ( erase, spec_attr, & mut fun. sig ) ;
387+
388+ // Add the spec/proof (requires/ensures) to the function body.
394389 let new_stmts = spec_stmts. into_iter ( ) . map ( |s| parse2 ( quote ! { #s } ) . unwrap ( ) ) ;
395390 let _ = fun. block_mut ( ) . unwrap ( ) . stmts . splice ( 0 ..0 , new_stmts) ;
391+
392+ // Parse and replace proof_xxx!() inside function and replace panic.
393+ replace_block ( erase, fun. block_mut ( ) . unwrap ( ) ) ;
396394 fun. to_tokens ( & mut new_stream) ;
397395 proc_macro:: TokenStream :: from ( new_stream)
398396 }
@@ -644,11 +642,40 @@ fn rewrite_with_expr(
644642 x_declares
645643}
646644
645+ /// Rewrite the const function and return a proxy function.
646+ fn rewrite_const_ret_proxy ( const_fun : & mut syn:: ItemFn ) -> syn:: ItemFn {
647+ // This function is used to rewrite a const function to link it to a proxy function
648+ // that can be used to verify code.
649+ // It seems that we do not need to erase anything.
650+ // But just do it to be safe and consistent with verus macro.
651+ let span = const_fun. sig . constness . unwrap ( ) . span ( ) ;
652+ let mut proxy_fun = const_fun. clone ( ) ;
653+ replace_block ( EraseGhost :: Erase , const_fun. block_mut ( ) . unwrap ( ) ) ;
654+ const_fun. attrs . push ( mk_verifier_attr_syn ( span, quote ! { external } ) ) ;
655+ const_fun. attrs . push ( mk_verus_attr_syn ( span, quote ! { uses_unerased_proxy } ) ) ;
656+ const_fun. attrs . push ( mk_verus_attr_syn ( span, quote ! { encoded_const } ) ) ;
657+
658+ proxy_fun. sig . ident = syn:: Ident :: new (
659+ & format ! ( "{VERUS_UNERASED_PROXY}{}" , const_fun. sig. ident) ,
660+ const_fun. sig . ident . span ( ) ,
661+ ) ;
662+ proxy_fun. attrs . push ( mk_verus_attr_syn ( span, quote ! { unerased_proxy } ) ) ;
663+ proxy_fun
664+ }
665+
647666// Create a copy of function with unverified function signature without a
648667// function body, to enable seamless use of unverified call to the function in
649668// verification.
650- fn rewrite_unverified_func ( fun : & mut syn:: ItemFn , span : proc_macro2:: Span ) -> syn:: ItemFn {
669+ // If the function is const, it will be rewritten to a proxy function and a verified function.
670+ fn rewrite_unverified_func ( fun : & mut syn:: ItemFn , span : proc_macro2:: Span ) -> Vec < syn:: ItemFn > {
671+ let mut ret = vec ! [ ] ;
651672 let mut unverified_fun = fun. clone ( ) ;
673+ if fun. sig . constness . is_some ( ) {
674+ // Create a proxy function to include requires/ensures.
675+ let proxy = rewrite_const_ret_proxy ( & mut unverified_fun) ;
676+ ret. push ( unverified_fun) ;
677+ unverified_fun = proxy;
678+ }
652679 let stmts = vec ! [
653680 syn:: Stmt :: Expr (
654681 syn:: Expr :: Verbatim (
@@ -669,5 +696,6 @@ fn rewrite_unverified_func(fun: &mut syn::ItemFn, span: proc_macro2::Span) -> sy
669696 // change name to verified_{fname}
670697 let x = & fun. sig . ident ;
671698 fun. sig . ident = syn:: Ident :: new ( & format ! ( "{VERIFIED}_{x}" ) , x. span ( ) ) ;
672- unverified_fun
699+ ret. push ( unverified_fun) ;
700+ ret
673701}
0 commit comments