diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 89e032b222fec..10e9bde0d972b 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -597,6 +597,14 @@ impl Span { if !expn_data.is_root() { Some(expn_data.call_site) } else { None } } + /// Walk down the expansion ancestors to find a span that's contained within `outer`. + pub fn find_ancestor_inside(mut self, outer: Span) -> Option { + while !outer.contains(self) { + self = self.parent()?; + } + Some(self) + } + /// Edition of the crate from which this span came. pub fn edition(self) -> edition::Edition { self.ctxt().edition() diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 75fd545060c4a..a25d0f8064404 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -680,15 +680,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { migrated_variables_concat ); - let mut closure_body_span = self.tcx.hir().span(body_id.hir_id); - // If the body was entirely expanded from a macro // invocation, i.e. the body is not contained inside the // closure span, then we walk up the expansion until we // find the span before the expansion. - while !closure_body_span.is_dummy() && !closure_span.contains(closure_body_span) { - closure_body_span = closure_body_span.parent().unwrap_or(DUMMY_SP); - } + let closure_body_span = self.tcx.hir().span(body_id.hir_id) + .find_ancestor_inside(closure_span) + .unwrap_or(DUMMY_SP); if let Ok(s) = self.tcx.sess.source_map().span_to_snippet(closure_body_span) { let mut lines = s.lines();