@@ -595,6 +595,68 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
595
595
}
596
596
}
597
597
598
+ /// Walks up the callstack from the intrinsic's callsite, searching for the first callsite in a
599
+ /// frame which is not `#[track_caller]`. This is the fancy version of `cur_span`.
600
+ pub ( crate ) fn find_closest_untracked_caller_location ( & self ) -> Span {
601
+ for frame in self . stack ( ) . iter ( ) . rev ( ) {
602
+ debug ! ( "find_closest_untracked_caller_location: checking frame {:?}" , frame. instance) ;
603
+
604
+ // Assert that the frame we look at is actually executing code currently
605
+ // (`loc` is `Right` when we are unwinding and the frame does not require cleanup).
606
+ let loc = frame. loc . left ( ) . unwrap ( ) ;
607
+
608
+ // This could be a non-`Call` terminator (such as `Drop`), or not a terminator at all
609
+ // (such as `box`). Use the normal span by default.
610
+ let mut source_info = * frame. body . source_info ( loc) ;
611
+
612
+ // If this is a `Call` terminator, use the `fn_span` instead.
613
+ let block = & frame. body . basic_blocks [ loc. block ] ;
614
+ if loc. statement_index == block. statements . len ( ) {
615
+ debug ! (
616
+ "find_closest_untracked_caller_location: got terminator {:?} ({:?})" ,
617
+ block. terminator( ) ,
618
+ block. terminator( ) . kind,
619
+ ) ;
620
+ if let mir:: TerminatorKind :: Call { fn_span, .. } = block. terminator ( ) . kind {
621
+ source_info. span = fn_span;
622
+ }
623
+ }
624
+
625
+ // Note: this must be kept in sync with get_caller_location from cg_ssa.
626
+
627
+ // Walk up the `SourceScope`s, in case some of them are from MIR inlining.
628
+ // If so, the starting `source_info.span` is in the innermost inlined
629
+ // function, and will be replaced with outer callsite spans as long
630
+ // as the inlined functions were `#[track_caller]`.
631
+ loop {
632
+ let scope_data = & frame. body . source_scopes [ source_info. scope ] ;
633
+
634
+ if let Some ( ( callee, callsite_span) ) = scope_data. inlined {
635
+ // Stop inside the most nested non-`#[track_caller]` function,
636
+ // before ever reaching its caller (which is irrelevant).
637
+ if !callee. def . requires_caller_location ( * self . tcx ) {
638
+ return source_info. span ;
639
+ }
640
+ source_info. span = callsite_span;
641
+ }
642
+
643
+ // Skip past all of the parents with `inlined: None`.
644
+ match scope_data. inlined_parent_scope {
645
+ Some ( parent) => source_info. scope = parent,
646
+ None => break ,
647
+ }
648
+ }
649
+
650
+ // Stop inside the most nested non-`#[track_caller]` function,
651
+ // before ever reaching its caller (which is irrelevant).
652
+ if !frame. instance . def . requires_caller_location ( * self . tcx ) {
653
+ return source_info. span ;
654
+ }
655
+ }
656
+
657
+ span_bug ! ( self . cur_span( ) , "no non-`#[track_caller]` frame found" )
658
+ }
659
+
598
660
#[ inline( always) ]
599
661
pub fn layout_of_local (
600
662
& self ,
0 commit comments