1010
1111use crate :: codegen_cprover_gotoc:: GotocCtx ;
1212use crate :: codegen_cprover_gotoc:: codegen:: { PropertyClass , bb_label} ;
13- use crate :: kani_middle:: attributes:: KaniAttributes ;
14- use crate :: kani_middle:: attributes :: matches_diagnostic as matches_function ;
13+ use crate :: kani_middle:: attributes;
14+ use crate :: kani_middle:: kani_functions :: { KaniFunction , KaniHook } ;
1515use crate :: unwrap_or_return_codegen_unimplemented_stmt;
1616use cbmc:: goto_program:: CIntType ;
1717use cbmc:: goto_program:: { BuiltinFn , Expr , Stmt , Type } ;
1818use rustc_middle:: ty:: TyCtxt ;
1919use rustc_smir:: rustc_internal;
20- use rustc_span:: Symbol ;
2120use stable_mir:: mir:: mono:: Instance ;
2221use stable_mir:: mir:: { BasicBlockIdx , Place } ;
2322use stable_mir:: { CrateDef , ty:: Span } ;
23+ use std:: collections:: HashMap ;
2424use std:: rc:: Rc ;
2525use tracing:: debug;
2626
2727pub trait GotocHook {
2828 /// if the hook applies, it means the codegen would do something special to it
29- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool ;
29+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool ;
3030 /// the handler for codegen
3131 fn handle (
3232 & self ,
@@ -48,9 +48,12 @@ pub trait GotocHook {
4848/// <https://github.com/model-checking/kani/blob/main/rfc/src/rfcs/0003-cover-statement.md>
4949/// for more details.
5050struct Cover ;
51+
52+ const UNEXPECTED_CALL : & str = "Hooks from kani library handled as a map" ;
53+
5154impl GotocHook for Cover {
52- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
53- matches_function ( tcx , instance . def , "KaniCover ")
55+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
56+ unreachable ! ( "{UNEXPECTED_CALL} ")
5457 }
5558
5659 fn handle (
@@ -84,8 +87,8 @@ impl GotocHook for Cover {
8487
8588struct Assume ;
8689impl GotocHook for Assume {
87- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
88- matches_function ( tcx , instance . def , "KaniAssume ")
90+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
91+ unreachable ! ( "{UNEXPECTED_CALL} ")
8992 }
9093
9194 fn handle (
@@ -108,8 +111,8 @@ impl GotocHook for Assume {
108111
109112struct Assert ;
110113impl GotocHook for Assert {
111- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
112- matches_function ( tcx , instance . def , "KaniAssert ")
114+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
115+ unreachable ! ( "{UNEXPECTED_CALL} ")
113116 }
114117
115118 fn handle (
@@ -148,8 +151,8 @@ impl GotocHook for Assert {
148151
149152struct Check ;
150153impl GotocHook for Check {
151- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
152- matches_function ( tcx , instance . def , "KaniCheck ")
154+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
155+ unreachable ! ( "{UNEXPECTED_CALL} ")
153156 }
154157
155158 fn handle (
@@ -184,8 +187,8 @@ impl GotocHook for Check {
184187struct Nondet ;
185188
186189impl GotocHook for Nondet {
187- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
188- matches_function ( tcx , instance . def , "KaniAnyRaw ")
190+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
191+ unreachable ! ( "{UNEXPECTED_CALL} ")
189192 }
190193
191194 fn handle (
@@ -229,7 +232,6 @@ impl GotocHook for Panic {
229232 || tcx. has_attr ( def_id, rustc_span:: sym:: rustc_const_panic_str)
230233 || Some ( def_id) == tcx. lang_items ( ) . panic_fmt ( )
231234 || Some ( def_id) == tcx. lang_items ( ) . begin_panic_fn ( )
232- || matches_function ( tcx, instance. def , "KaniPanic" )
233235 }
234236
235237 fn handle (
@@ -248,8 +250,8 @@ impl GotocHook for Panic {
248250/// Encodes __CPROVER_r_ok(ptr, size)
249251struct IsAllocated ;
250252impl GotocHook for IsAllocated {
251- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
252- matches_function ( tcx , instance . def , "KaniIsAllocated ")
253+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
254+ unreachable ! ( "{UNEXPECTED_CALL} ")
253255 }
254256
255257 fn handle (
@@ -285,8 +287,8 @@ impl GotocHook for IsAllocated {
285287/// Encodes __CPROVER_pointer_object(ptr)
286288struct PointerObject ;
287289impl GotocHook for PointerObject {
288- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
289- matches_function ( tcx , instance . def , "KaniPointerObject ")
290+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
291+ unreachable ! ( "{UNEXPECTED_CALL} ")
290292 }
291293
292294 fn handle (
@@ -321,8 +323,8 @@ impl GotocHook for PointerObject {
321323/// Encodes __CPROVER_pointer_offset(ptr)
322324struct PointerOffset ;
323325impl GotocHook for PointerOffset {
324- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
325- matches_function ( tcx , instance . def , "KaniPointerOffset ")
326+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
327+ unreachable ! ( "{UNEXPECTED_CALL} ")
326328 }
327329
328330 fn handle (
@@ -467,8 +469,8 @@ impl GotocHook for MemCmp {
467469struct UntrackedDeref ;
468470
469471impl GotocHook for UntrackedDeref {
470- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
471- matches_function ( tcx , instance . def , "KaniUntrackedDeref ")
472+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
473+ unreachable ! ( "{UNEXPECTED_CALL} ")
472474 }
473475
474476 fn handle (
@@ -515,8 +517,8 @@ struct InitContracts;
515517/// free(NULL);
516518/// ```
517519impl GotocHook for InitContracts {
518- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
519- matches_function ( tcx , instance . def , "KaniInitContracts ")
520+ fn hook_applies ( & self , _tcx : TyCtxt , _instance : Instance ) -> bool {
521+ unreachable ! ( "{UNEXPECTED_CALL} ")
520522 }
521523
522524 fn handle (
@@ -557,9 +559,9 @@ impl GotocHook for InitContracts {
557559pub struct LoopInvariantRegister ;
558560
559561impl GotocHook for LoopInvariantRegister {
560- fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> bool {
561- KaniAttributes :: for_instance ( tcx , instance) . fn_marker ( )
562- == Some ( Symbol :: intern ( "kani_register_loop_contract" ) )
562+ fn hook_applies ( & self , _tcx : TyCtxt , instance : Instance ) -> bool {
563+ attributes :: fn_marker ( instance. def )
564+ . map_or ( false , |marker| marker == "kani_register_loop_contract" )
563565 }
564566
565567 fn handle (
@@ -617,37 +619,50 @@ impl GotocHook for LoopInvariantRegister {
617619}
618620
619621pub fn fn_hooks ( ) -> GotocHooks {
622+ let kani_lib_hooks: [ ( KaniHook , Rc < dyn GotocHook > ) ; 11 ] = [
623+ ( KaniHook :: Assert , Rc :: new ( Assert ) ) ,
624+ ( KaniHook :: Assume , Rc :: new ( Assume ) ) ,
625+ ( KaniHook :: Panic , Rc :: new ( Panic ) ) ,
626+ ( KaniHook :: Check , Rc :: new ( Check ) ) ,
627+ ( KaniHook :: Cover , Rc :: new ( Cover ) ) ,
628+ ( KaniHook :: AnyRaw , Rc :: new ( Nondet ) ) ,
629+ ( KaniHook :: IsAllocated , Rc :: new ( IsAllocated ) ) ,
630+ ( KaniHook :: PointerObject , Rc :: new ( PointerObject ) ) ,
631+ ( KaniHook :: PointerOffset , Rc :: new ( PointerOffset ) ) ,
632+ ( KaniHook :: UntrackedDeref , Rc :: new ( UntrackedDeref ) ) ,
633+ ( KaniHook :: InitContracts , Rc :: new ( InitContracts ) ) ,
634+ ] ;
620635 GotocHooks {
621- hooks : vec ! [
636+ kani_lib_hooks : HashMap :: from ( kani_lib_hooks) ,
637+ other_hooks : vec ! [
622638 Rc :: new( Panic ) ,
623- Rc :: new( Assume ) ,
624- Rc :: new( Assert ) ,
625- Rc :: new( Check ) ,
626- Rc :: new( Cover ) ,
627- Rc :: new( Nondet ) ,
628- Rc :: new( IsAllocated ) ,
629- Rc :: new( PointerObject ) ,
630- Rc :: new( PointerOffset ) ,
631639 Rc :: new( RustAlloc ) ,
632640 Rc :: new( MemCmp ) ,
633- Rc :: new( UntrackedDeref ) ,
634- Rc :: new( InitContracts ) ,
635641 Rc :: new( LoopInvariantRegister ) ,
636642 ] ,
637643 }
638644}
639645
640646pub struct GotocHooks {
641- hooks : Vec < Rc < dyn GotocHook > > ,
647+ /// Match functions that are unique and defined in the Kani library, which we can prefetch
648+ /// using `KaniFunctions`.
649+ kani_lib_hooks : HashMap < KaniHook , Rc < dyn GotocHook > > ,
650+ /// Match functions that are not defined in the Kani library, which we cannot prefetch
651+ /// beforehand.
652+ other_hooks : Vec < Rc < dyn GotocHook > > ,
642653}
643654
644655impl GotocHooks {
645656 pub fn hook_applies ( & self , tcx : TyCtxt , instance : Instance ) -> Option < Rc < dyn GotocHook > > {
646- for h in & self . hooks {
647- if h. hook_applies ( tcx, instance) {
648- return Some ( h. clone ( ) ) ;
657+ if let Ok ( KaniFunction :: Hook ( hook) ) = KaniFunction :: try_from ( instance) {
658+ Some ( self . kani_lib_hooks [ & hook] . clone ( ) )
659+ } else {
660+ for h in & self . other_hooks {
661+ if h. hook_applies ( tcx, instance) {
662+ return Some ( h. clone ( ) ) ;
663+ }
649664 }
665+ None
650666 }
651- None
652667 }
653668}
0 commit comments