about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs3
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs3
-rw-r--r--src/libsyntax_expand/base.rs13
-rw-r--r--src/libsyntax_pos/hygiene.rs19
-rw-r--r--src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs14
5 files changed, 36 insertions, 16 deletions
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<Span> {
-        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<S: Into<MultiSpan>>(&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<Span> {
+        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);
 }