@@ -357,21 +357,15 @@ impl<'tcx> Body<'tcx> {
357357 //
358358 // FIXME: Use a finer-grained API for this, so only transformations that alter terminators
359359 // invalidate the caches.
360- self . predecessor_cache . invalidate ( ) ;
361- self . switch_source_cache . invalidate ( ) ;
362- self . is_cyclic . invalidate ( ) ;
363- self . postorder_cache . invalidate ( ) ;
360+ self . invalidate_cfg_cache ( ) ;
364361 & mut self . basic_blocks
365362 }
366363
367364 #[ inline]
368365 pub fn basic_blocks_and_local_decls_mut (
369366 & mut self ,
370367 ) -> ( & mut IndexVec < BasicBlock , BasicBlockData < ' tcx > > , & mut LocalDecls < ' tcx > ) {
371- self . predecessor_cache . invalidate ( ) ;
372- self . switch_source_cache . invalidate ( ) ;
373- self . is_cyclic . invalidate ( ) ;
374- self . postorder_cache . invalidate ( ) ;
368+ self . invalidate_cfg_cache ( ) ;
375369 ( & mut self . basic_blocks , & mut self . local_decls )
376370 }
377371
@@ -383,11 +377,43 @@ impl<'tcx> Body<'tcx> {
383377 & mut LocalDecls < ' tcx > ,
384378 & mut Vec < VarDebugInfo < ' tcx > > ,
385379 ) {
380+ self . invalidate_cfg_cache ( ) ;
381+ ( & mut self . basic_blocks , & mut self . local_decls , & mut self . var_debug_info )
382+ }
383+
384+ /// Get mutable access to parts of the Body without invalidating the CFG cache.
385+ ///
386+ /// By calling this method instead of eg [`Body::basic_blocks_mut`], you promise not to change
387+ /// the CFG. This means that
388+ ///
389+ /// 1) The number of basic blocks remains unchanged
390+ /// 2) The set of successors of each terminator remains unchanged.
391+ /// 3) For each `TerminatorKind::SwitchInt`, the `targets` remains the same and the terminator
392+ /// kind is not changed.
393+ ///
394+ /// If any of these conditions cannot be upheld, you should call [`Body::invalidate_cfg_cache`].
395+ #[ inline]
396+ pub fn basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate (
397+ & mut self ,
398+ ) -> (
399+ & mut IndexVec < BasicBlock , BasicBlockData < ' tcx > > ,
400+ & mut LocalDecls < ' tcx > ,
401+ & mut Vec < VarDebugInfo < ' tcx > > ,
402+ ) {
403+ ( & mut self . basic_blocks , & mut self . local_decls , & mut self . var_debug_info )
404+ }
405+
406+ /// Invalidates cached information about the CFG.
407+ ///
408+ /// You will only ever need this if you have also called
409+ /// [`Body::basic_blocks_local_decls_mut_and_var_debug_info_no_invalidate`]. All other methods
410+ /// that allow you to mutate the body also call this method themselves, thereby avoiding any
411+ /// risk of accidentaly cache invalidation.
412+ pub fn invalidate_cfg_cache ( & mut self ) {
386413 self . predecessor_cache . invalidate ( ) ;
387414 self . switch_source_cache . invalidate ( ) ;
388415 self . is_cyclic . invalidate ( ) ;
389416 self . postorder_cache . invalidate ( ) ;
390- ( & mut self . basic_blocks , & mut self . local_decls , & mut self . var_debug_info )
391417 }
392418
393419 /// Returns `true` if a cycle exists in the control-flow graph that is reachable from the
0 commit comments