Skip to content

Commit 24af0c9

Browse files
authored
Rollup merge of rust-lang#65973 - eddyb:caller-location-panic, r=petrochenkov
caller_location: point to macro invocation sites, like file!/line!, and use in core::panic!. The main change here is to `core::panic!`, trying to fix this remaining regression: rust-lang#65927 (comment) However, in order for `caller_location` to be usable from macros the same way `file!()`/`line!()` are, it needs to have the same behavior (of extracting the macro invocation site `Span` and using that). Arguably we would've had to do this at some point anyway, if we want to use `#[track_caller]` to replace the `file!()`/`line!()` uses from macros, but I'm not sure the RFC mentions this at all. r? @petrochenkov cc @anp @nnethercote
2 parents a0b4b4d + 49f9626 commit 24af0c9

File tree

6 files changed

+51
-33
lines changed

6 files changed

+51
-33
lines changed

src/libcore/macros.rs

+15-17
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,29 @@ macro_rules! panic {
2626
/// For details, see `std::macros`.
2727
#[cfg(not(bootstrap))]
2828
#[macro_export]
29-
#[allow_internal_unstable(core_panic, panic_internals)]
29+
#[allow_internal_unstable(core_panic,
30+
// FIXME(anp, eddyb) `core_intrinsics` is used here to allow calling
31+
// the `caller_location` intrinsic, but once `#[track_caller]` is implemented,
32+
// `panicking::{panic, panic_fmt}` can use that instead of a `Location` argument.
33+
core_intrinsics,
34+
)]
3035
#[stable(feature = "core", since = "1.6.0")]
3136
macro_rules! panic {
3237
() => (
3338
$crate::panic!("explicit panic")
3439
);
35-
($msg:expr) => ({
36-
const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
37-
$crate::file!(),
38-
$crate::line!(),
39-
$crate::column!(),
40-
);
41-
$crate::panicking::panic($msg, LOC)
42-
});
40+
($msg:expr) => (
41+
$crate::panicking::panic($msg, $crate::intrinsics::caller_location())
42+
);
4343
($msg:expr,) => (
4444
$crate::panic!($msg)
4545
);
46-
($fmt:expr, $($arg:tt)+) => ({
47-
const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
48-
$crate::file!(),
49-
$crate::line!(),
50-
$crate::column!(),
51-
);
52-
$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), LOC)
53-
});
46+
($fmt:expr, $($arg:tt)+) => (
47+
$crate::panicking::panic_fmt(
48+
$crate::format_args!($fmt, $($arg)+),
49+
$crate::intrinsics::caller_location(),
50+
)
51+
);
5452
}
5553

5654
/// Asserts that two expressions are equal to each other (using [`PartialEq`]).

src/librustc_codegen_ssa/mir/block.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -995,7 +995,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
995995
bx: &mut Bx,
996996
span: Span,
997997
) -> OperandRef<'tcx, Bx::Value> {
998-
let caller = bx.tcx().sess.source_map().lookup_char_pos(span.lo());
998+
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
999+
let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo());
9991000
let const_loc = bx.tcx().const_caller_location((
10001001
Symbol::intern(&caller.file.name.to_string()),
10011002
caller.line as u32,

src/librustc_mir/interpret/intrinsics.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9898
let intrinsic_name = &*self.tcx.item_name(instance.def_id()).as_str();
9999
match intrinsic_name {
100100
"caller_location" => {
101-
let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo());
101+
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
102+
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
102103
let location = self.alloc_caller_location(
103104
Symbol::intern(&caller.file.name.to_string()),
104105
caller.line as u32,

src/libsyntax_expand/base.rs

+1-12
Original file line numberDiff line numberDiff line change
@@ -953,18 +953,7 @@ impl<'a> ExtCtxt<'a> {
953953
///
954954
/// Stops backtracing at include! boundary.
955955
pub fn expansion_cause(&self) -> Option<Span> {
956-
let mut expn_id = self.current_expansion.id;
957-
let mut last_macro = None;
958-
loop {
959-
let expn_data = expn_id.expn_data();
960-
// Stop going up the backtrace once include! is encountered
961-
if expn_data.is_root() || expn_data.kind.descr() == sym::include {
962-
break;
963-
}
964-
expn_id = expn_data.call_site.ctxt().outer_expn();
965-
last_macro = Some(expn_data.call_site);
966-
}
967-
last_macro
956+
self.current_expansion.id.expansion_cause()
968957
}
969958

970959
pub fn struct_span_warn<S: Into<MultiSpan>>(&self,

src/libsyntax_pos/hygiene.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
use crate::GLOBALS;
2929
use crate::{Span, DUMMY_SP};
3030
use crate::edition::Edition;
31-
use crate::symbol::{kw, Symbol};
31+
use crate::symbol::{kw, sym, Symbol};
3232

3333
use rustc_serialize::{Encodable, Decodable, Encoder, Decoder};
3434
use rustc_data_structures::fx::FxHashMap;
@@ -119,6 +119,23 @@ impl ExpnId {
119119
pub fn outer_expn_is_descendant_of(self, ctxt: SyntaxContext) -> bool {
120120
HygieneData::with(|data| data.is_descendant_of(self, data.outer_expn(ctxt)))
121121
}
122+
123+
/// Returns span for the macro which originally caused this expansion to happen.
124+
///
125+
/// Stops backtracing at include! boundary.
126+
pub fn expansion_cause(mut self) -> Option<Span> {
127+
let mut last_macro = None;
128+
loop {
129+
let expn_data = self.expn_data();
130+
// Stop going up the backtrace once include! is encountered
131+
if expn_data.is_root() || expn_data.kind.descr() == sym::include {
132+
break;
133+
}
134+
self = expn_data.call_site.ctxt().outer_expn();
135+
last_macro = Some(expn_data.call_site);
136+
}
137+
last_macro
138+
}
122139
}
123140

124141
#[derive(Debug)]
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
// run-pass
22

33
#![feature(core_intrinsics)]
4+
5+
macro_rules! caller_location_from_macro {
6+
() => (core::intrinsics::caller_location());
7+
}
8+
49
fn main() {
510
let loc = core::intrinsics::caller_location();
611
assert_eq!(loc.file(), file!());
7-
assert_eq!(loc.line(), 5);
12+
assert_eq!(loc.line(), 10);
813
assert_eq!(loc.column(), 15);
14+
15+
// `caller_location()` in a macro should behave similarly to `file!` and `line!`,
16+
// i.e. point to where the macro was invoked, instead of the macro itself.
17+
let loc2 = caller_location_from_macro!();
18+
assert_eq!(loc2.file(), file!());
19+
assert_eq!(loc2.line(), 17);
20+
assert_eq!(loc2.column(), 16);
921
}

0 commit comments

Comments
 (0)