Skip to content

Commit cee2f00

Browse files
committed
Implement #[track_caller] in const.
1 parent c36a2d7 commit cee2f00

File tree

5 files changed

+77
-26
lines changed

5 files changed

+77
-26
lines changed

src/librustc/ty/instance.rs

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ impl<'tcx> InstanceDef<'tcx> {
175175
}
176176
tcx.codegen_fn_attrs(self.def_id()).requests_inline()
177177
}
178+
179+
pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
180+
tcx.codegen_fn_attrs(self.def_id()).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
181+
}
178182
}
179183

180184
impl<'tcx> fmt::Display for Instance<'tcx> {
@@ -313,23 +317,16 @@ impl<'tcx> Instance<'tcx> {
313317
substs: SubstsRef<'tcx>,
314318
) -> Option<Instance<'tcx>> {
315319
debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
316-
Instance::resolve(tcx, param_env, def_id, substs).map(|mut resolved| {
317-
let has_track_caller = |def| tcx.codegen_fn_attrs(def).flags
318-
.contains(CodegenFnAttrFlags::TRACK_CALLER);
319-
320-
match resolved.def {
321-
InstanceDef::Item(def_id) if has_track_caller(def_id) => {
322-
debug!(" => fn pointer created for function with #[track_caller]");
323-
resolved.def = InstanceDef::ReifyShim(def_id);
324-
}
325-
InstanceDef::Virtual(def_id, _) => {
326-
debug!(" => fn pointer created for virtual call");
327-
resolved.def = InstanceDef::ReifyShim(def_id);
320+
Instance::resolve(tcx, param_env, def_id, substs).map(|resolved| {
321+
if resolved.def.requires_caller_location(tcx) {
322+
debug!(" => fn pointer created for function with #[track_caller]");
323+
Instance {
324+
def: InstanceDef::ReifyShim(def_id),
325+
substs,
328326
}
329-
_ => {}
327+
} else {
328+
resolved
330329
}
331-
332-
resolved
333330
})
334331
}
335332

src/librustc_mir/interpret/intrinsics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ 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 span = self.find_closest_untracked_caller_location(span);
101102
let caller = self.tcx.sess.source_map().lookup_char_pos(span.lo());
102103
let location = self.alloc_caller_location(
103104
Symbol::intern(&caller.file.name.to_string()),

src/librustc_mir/interpret/intrinsics/caller_location.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,33 @@ use rustc::middle::lang_items::PanicLocationLangItem;
22
use rustc::mir::interpret::{Pointer, PointerArithmetic, Scalar};
33
use rustc::ty::subst::Subst;
44
use rustc_target::abi::{LayoutOf, Size};
5-
use syntax_pos::Symbol;
5+
use syntax_pos::{Span, Symbol};
66

77
use crate::interpret::{MemoryKind, MPlaceTy, intrinsics::{InterpCx, InterpResult, Machine}};
88

99
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10+
/// Walks up the callstack from the intrinsic's callsite, searching for the first frame which is
11+
/// not `#[track_caller]`. Returns the (passed) span of the intrinsic's callsite if the first
12+
/// frame in the stack is untracked so that we can display the callsite of the intrinsic within
13+
/// that function.
14+
crate fn find_closest_untracked_caller_location(
15+
&self,
16+
intrinsic_loc: Span,
17+
) -> Span {
18+
debug!("finding closest untracked caller relative to {:?}", intrinsic_loc);
19+
20+
let mut caller_span = intrinsic_loc;
21+
for next_caller in self.stack.iter().rev() {
22+
if !next_caller.instance.def.requires_caller_location(*self.tcx) {
23+
return caller_span;
24+
}
25+
caller_span = next_caller.span;
26+
}
27+
28+
intrinsic_loc
29+
}
30+
31+
/// Allocate a `const core::panic::Location` with the provided filename and line/column numbers.
1032
pub fn alloc_caller_location(
1133
&mut self,
1234
filename: Symbol,
@@ -19,17 +41,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1941
let ptr_size = self.pointer_size();
2042
let u32_size = Size::from_bits(32);
2143

44+
// we can't use TyCtxt::caller_location_ty because that returns `&'static Location`
45+
let static_subst = self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter());
2246
let loc_ty = self.tcx.type_of(self.tcx.require_lang_item(PanicLocationLangItem, None))
23-
.subst(*self.tcx, self.tcx.mk_substs([self.tcx.lifetimes.re_static.into()].iter()));
47+
.subst(*self.tcx, static_subst);
2448
let loc_layout = self.layout_of(loc_ty)?;
2549

50+
// we have all our sizes and layouts, start allocating
2651
let file_alloc = self.tcx.allocate_bytes(filename.as_str().as_bytes());
2752
let file_ptr = Pointer::new(file_alloc, Size::ZERO);
2853
let file = Scalar::Ptr(self.tag_static_base_pointer(file_ptr));
2954
let file_len = Scalar::from_uint(filename.as_str().len() as u128, ptr_size);
3055

3156
let location = self.allocate(loc_layout, MemoryKind::Stack);
3257

58+
// now that the struct is allocated, we need to get field offsets
3359
let file_out = self.mplace_field(location, 0)?;
3460
let file_ptr_out = self.force_ptr(self.mplace_field(file_out, 0)?.ptr)?;
3561
let file_len_out = self.force_ptr(self.mplace_field(file_out, 1)?.ptr)?;
@@ -39,6 +65,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
3965
let layout = &self.tcx.data_layout;
4066
let alloc = self.memory.get_mut(file_ptr_out.alloc_id)?;
4167

68+
// finally write into the field offsets
4269
alloc.write_scalar(layout, file_ptr_out, file.into(), ptr_size)?;
4370
alloc.write_scalar(layout, file_len_out, file_len.into(), ptr_size)?;
4471
alloc.write_scalar(layout, line_out, line.into(), u32_size)?;
Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,41 @@
11
// run-pass
22

3-
#![feature(const_fn, core_intrinsics)]
3+
#![feature(const_fn, core_intrinsics, track_caller)]
44

55
use std::{intrinsics::caller_location, panic::Location};
66

77
const LOCATION: &Location = caller_location();
8-
const NESTED: &Location = {
9-
const fn nested_location() -> &'static Location<'static> {
10-
caller_location()
11-
};
12-
nested_location()
13-
};
8+
9+
const TRACKED: &Location = tracked();
10+
#[track_caller]
11+
const fn tracked() -> &'static Location <'static> {
12+
caller_location()
13+
}
14+
15+
const NESTED: &Location = nested_location();
16+
const fn nested_location() -> &'static Location<'static> {
17+
caller_location()
18+
}
19+
20+
const CONTAINED: &Location = contained();
21+
const fn contained() -> &'static Location<'static> {
22+
tracked()
23+
}
1424

1525
fn main() {
1626
assert_eq!(LOCATION.file(), file!());
1727
assert_eq!(LOCATION.line(), 7);
1828
assert_eq!(LOCATION.column(), 29);
1929

30+
assert_eq!(TRACKED.file(), file!());
31+
assert_eq!(TRACKED.line(), 9);
32+
assert_eq!(TRACKED.column(), 28);
33+
2034
assert_eq!(NESTED.file(), file!());
21-
assert_eq!(NESTED.line(), 10);
22-
assert_eq!(NESTED.column(), 9);
35+
assert_eq!(NESTED.line(), 17);
36+
assert_eq!(NESTED.column(), 5);
37+
38+
assert_eq!(CONTAINED.file(), file!());
39+
assert_eq!(CONTAINED.line(), 22);
40+
assert_eq!(CONTAINED.column(), 5);
2341
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
warning: the feature `track_caller` is incomplete and may cause the compiler to crash
2+
--> $DIR/const_caller_location.rs:3:39
3+
|
4+
LL | #![feature(const_fn, core_intrinsics, track_caller)]
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(incomplete_features)]` on by default
8+

0 commit comments

Comments
 (0)