From 9ab065dcda070680e18ca0da4366ad45e1665f0f Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 11 Nov 2019 08:45:52 -0800 Subject: [PATCH] Implement #[track_caller] in const. --- src/librustc/ty/instance.rs | 9 ++--- src/librustc_mir/interpret/intrinsics.rs | 1 + .../interpret/intrinsics/caller_location.rs | 22 ++++++++++++ .../const-eval/const_caller_location.rs | 36 ++++++++++++++----- .../const_caller_location.stderr | 8 +++++ 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/rfc-2091-track-caller/const_caller_location.stderr diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 801dfa81ef1..366951bc9f4 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -116,6 +116,10 @@ impl<'tcx> InstanceDef<'tcx> { } tcx.codegen_fn_attrs(self.def_id()).requests_inline() } + + pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { + tcx.codegen_fn_attrs(self.def_id()).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) + } } impl<'tcx> fmt::Display for Instance<'tcx> { @@ -255,11 +259,8 @@ impl<'tcx> Instance<'tcx> { ) -> Option> { debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| { - let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags - .contains(CodegenFnAttrFlags::TRACK_CALLER); - match resolved.def { - InstanceDef::Item(def_id) if has_track_caller(def_id) => { + InstanceDef::Item(def_id) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); resolved.def = InstanceDef::ReifyShim(def_id); } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ad5df5aff1a..20f1a1d7c48 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -112,6 +112,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `src/librustc/ty/constness.rs` match intrinsic_name { sym::caller_location => { + let span = self.find_closest_untracked_caller_location(span); let location = self.alloc_caller_location_for_span(span); self.write_scalar(location.ptr, dest)?; } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index ecf4b7a39b7..391c0c30bde 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -6,6 +6,28 @@ use syntax_pos::{Symbol, Span}; use crate::interpret::{Scalar, MemoryKind, MPlaceTy, intrinsics::{InterpCx, Machine}}; impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + /// Walks up the callstack from the intrinsic's callsite, searching for the first frame which is + /// not `#[track_caller]`. Returns the (passed) span of the intrinsic's callsite if the first + /// frame in the stack is untracked so that we can display the callsite of the intrinsic within + /// that function. + crate fn find_closest_untracked_caller_location( + &self, + intrinsic_loc: Span, + ) -> Span { + debug!("finding closest untracked caller relative to {:?}", intrinsic_loc); + + let mut caller_span = intrinsic_loc; + for next_caller in self.stack.iter().rev() { + if !next_caller.instance.def.requires_caller_location(*self.tcx) { + return caller_span; + } + caller_span = next_caller.span; + } + + intrinsic_loc + } + + /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. crate fn alloc_caller_location( &mut self, filename: Symbol, diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs index c63822f052b..e36790505e8 100644 --- a/src/test/ui/consts/const-eval/const_caller_location.rs +++ b/src/test/ui/consts/const-eval/const_caller_location.rs @@ -1,23 +1,41 @@ // run-pass -#![feature(const_fn, core_intrinsics)] +#![feature(const_fn, core_intrinsics, track_caller)] use std::{intrinsics::caller_location, panic::Location}; const LOCATION: &Location = caller_location(); -const NESTED: &Location = { - const fn nested_location() -> &'static Location<'static> { - caller_location() - }; - nested_location() -}; + +const TRACKED: &Location = tracked(); +#[track_caller] +const fn tracked() -> &'static Location <'static> { + caller_location() +} + +const NESTED: &Location = nested_location(); +const fn nested_location() -> &'static Location<'static> { + caller_location() +} + +const CONTAINED: &Location = contained(); +const fn contained() -> &'static Location<'static> { + tracked() +} fn main() { assert_eq!(LOCATION.file(), file!()); assert_eq!(LOCATION.line(), 7); assert_eq!(LOCATION.column(), 29); + assert_eq!(TRACKED.file(), file!()); + assert_eq!(TRACKED.line(), 9); + assert_eq!(TRACKED.column(), 28); + assert_eq!(NESTED.file(), file!()); - assert_eq!(NESTED.line(), 10); - assert_eq!(NESTED.column(), 9); + assert_eq!(NESTED.line(), 17); + assert_eq!(NESTED.column(), 5); + + assert_eq!(CONTAINED.file(), file!()); + assert_eq!(CONTAINED.line(), 22); + assert_eq!(CONTAINED.column(), 5); } diff --git a/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr b/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr new file mode 100644 index 00000000000..01a00dd28fd --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr @@ -0,0 +1,8 @@ +warning: the feature `track_caller` is incomplete and may cause the compiler to crash + --> $DIR/const_caller_location.rs:3:39 + | +LL | #![feature(const_fn, core_intrinsics, track_caller)] + | ^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default +