@@ -595,6 +595,68 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
595595 }
596596 }
597597
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+
598660 #[ inline( always) ]
599661 pub fn layout_of_local (
600662 & self ,
0 commit comments