diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 79855311f37..43a9ae9ba5d 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -995,7 +995,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, span: Span, ) -> OperandRef<'tcx, Bx::Value> { - let caller = bx.tcx().sess.source_map().lookup_char_pos(span.lo()); + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo()); let const_loc = bx.tcx().const_caller_location(( Symbol::intern(&caller.file.name.to_string()), caller.line as u32, diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 519f4f03222..abbf430f21e 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -98,7 +98,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "caller_location" => { - let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo()); + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); let location = self.alloc_caller_location( Symbol::intern(&caller.file.name.to_string()), caller.line as u32, diff --git a/src/libsyntax_expand/base.rs b/src/libsyntax_expand/base.rs index a66263a9a02..e8be57dfd4c 100644 --- a/src/libsyntax_expand/base.rs +++ b/src/libsyntax_expand/base.rs @@ -954,18 +954,7 @@ impl<'a> ExtCtxt<'a> { /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Option { - let mut expn_id = self.current_expansion.id; - let mut last_macro = None; - loop { - let expn_data = expn_id.expn_data(); - // Stop going up the backtrace once include! is encountered - if expn_data.is_root() || expn_data.kind.descr() == sym::include { - break; - } - expn_id = expn_data.call_site.ctxt().outer_expn(); - last_macro = Some(expn_data.call_site); - } - last_macro + self.current_expansion.id.expansion_cause() } pub fn struct_span_warn>(&self, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index e28d9326757..2a48f8e44aa 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -28,7 +28,7 @@ use crate::GLOBALS; use crate::{Span, DUMMY_SP}; use crate::edition::Edition; -use crate::symbol::{kw, Symbol}; +use crate::symbol::{kw, sym, Symbol}; use rustc_serialize::{Encodable, Decodable, Encoder, Decoder}; use rustc_data_structures::fx::FxHashMap; @@ -119,6 +119,23 @@ impl ExpnId { pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool { HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt))) } + + /// Returns span for the macro which originally caused this expansion to happen. + /// + /// Stops backtracing at include! boundary. + pub fn expansion_cause(mut self) -> Option { + let mut last_macro = None; + loop { + let expn_data = self.expn_data(); + // Stop going up the backtrace once include! is encountered + if expn_data.is_root() || expn_data.kind.descr() == sym::include { + break; + } + self = expn_data.call_site.ctxt().outer_expn(); + last_macro = Some(expn_data.call_site); + } + last_macro + } } #[derive(Debug)] diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs index ab6c59384c4..1c4d4666fa1 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs +++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs @@ -1,9 +1,21 @@ // run-pass #![feature(core_intrinsics)] + +macro_rules! caller_location_from_macro { + () => (core::intrinsics::caller_location()); +} + fn main() { let loc = core::intrinsics::caller_location(); assert_eq!(loc.file(), file!()); - assert_eq!(loc.line(), 5); + assert_eq!(loc.line(), 10); assert_eq!(loc.column(), 15); + + // `caller_location()` in a macro should behave similarly to `file!` and `line!`, + // i.e. point to where the macro was invoked, instead of the macro itself. + let loc2 = caller_location_from_macro!(); + assert_eq!(loc2.file(), file!()); + assert_eq!(loc2.line(), 17); + assert_eq!(loc2.column(), 16); }