Implement #[track_caller] in const.

This commit is contained in:
Adam Perry 2019-11-11 08:45:52 -08:00
parent 234c9f21d9
commit 9ab065dcda
5 changed files with 63 additions and 13 deletions

View File

@ -116,6 +116,10 @@ pub fn requires_local(&self, tcx: TyCtxt<'tcx>) -> bool {
}
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 @@ pub fn resolve_for_fn_ptr(
) -> Option<Instance<'tcx>> {
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);
}

View File

@ -112,6 +112,7 @@ pub fn emulate_intrinsic(
// `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)?;
}

View File

@ -6,6 +6,28 @@
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,

View File

@ -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 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()
};
nested_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);
}

View File

@ -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