mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
Rollup merge of #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: https://github.com/rust-lang/rust/pull/65927#issuecomment-547625147 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
This commit is contained in:
commit
24af0c94b3
@ -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`]).
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -953,18 +953,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,
|
||||
|
@ -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)]
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user