diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 8ccd31c95d510..131fb52e2d22b 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -26,31 +26,29 @@ macro_rules! panic { /// For details, see `std::macros`. #[cfg(not(bootstrap))] #[macro_export] -#[allow_internal_unstable(core_panic, panic_internals)] +#[allow_internal_unstable(core_panic, + // FIXME(anp, eddyb) `core_intrinsics` is used here to allow calling + // the `caller_location` intrinsic, but once `#[track_caller]` is implemented, + // `panicking::{panic, panic_fmt}` can use that instead of a `Location` argument. + core_intrinsics, +)] #[stable(feature = "core", since = "1.6.0")] macro_rules! panic { () => ( $crate::panic!("explicit panic") ); - ($msg:expr) => ({ - const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor( - $crate::file!(), - $crate::line!(), - $crate::column!(), - ); - $crate::panicking::panic($msg, LOC) - }); + ($msg:expr) => ( + $crate::panicking::panic($msg, $crate::intrinsics::caller_location()) + ); ($msg:expr,) => ( $crate::panic!($msg) ); - ($fmt:expr, $($arg:tt)+) => ({ - const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor( - $crate::file!(), - $crate::line!(), - $crate::column!(), - ); - $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), LOC) - }); + ($fmt:expr, $($arg:tt)+) => ( + $crate::panicking::panic_fmt( + $crate::format_args!($fmt, $($arg)+), + $crate::intrinsics::caller_location(), + ) + ); } /// Asserts that two expressions are equal to each other (using [`PartialEq`]). diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 79855311f370a..43a9ae9ba5d83 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 519f4f0322228..abbf430f21eb2 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 a66263a9a028a..e8be57dfd4ce9 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 e28d93267579a..2a48f8e44aa12 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 ab6c59384c43b..1c4d4666fa180 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); }