Skip to content

Commit 38797f8

Browse files
committed
Implement #[track_caller]
Fixes #848
1 parent fed3b26 commit 38797f8

File tree

8 files changed

+114
-18
lines changed

8 files changed

+114
-18
lines changed

example/track-caller-attribute.rs

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
2+
3+
// run-pass
4+
5+
#![feature(track_caller)]
6+
7+
use std::panic::Location;
8+
9+
#[track_caller]
10+
fn tracked() -> &'static Location<'static> {
11+
Location::caller()
12+
}
13+
14+
fn nested_intrinsic() -> &'static Location<'static> {
15+
Location::caller()
16+
}
17+
18+
fn nested_tracked() -> &'static Location<'static> {
19+
tracked()
20+
}
21+
22+
fn main() {
23+
let location = Location::caller();
24+
assert_eq!(location.file(), file!());
25+
assert_eq!(location.line(), 23);
26+
assert_eq!(location.column(), 20);
27+
28+
let tracked = tracked();
29+
assert_eq!(tracked.file(), file!());
30+
assert_eq!(tracked.line(), 28);
31+
assert_eq!(tracked.column(), 19);
32+
33+
let nested = nested_intrinsic();
34+
assert_eq!(nested.file(), file!());
35+
assert_eq!(nested.line(), 15);
36+
assert_eq!(nested.column(), 5);
37+
38+
let contained = nested_tracked();
39+
assert_eq!(contained.file(), file!());
40+
assert_eq!(contained.line(), 19);
41+
assert_eq!(contained.column(), 5);
42+
}

src/abi/comments.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,34 @@ pub fn add_args_header_comment(fx: &mut FunctionCx<impl Backend>) {
1414
pub fn add_arg_comment<'tcx>(
1515
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
1616
kind: &str,
17-
local: mir::Local,
17+
local: Option<mir::Local>,
1818
local_field: Option<usize>,
1919
params: EmptySinglePair<Value>,
2020
pass_mode: PassMode,
2121
ty: Ty<'tcx>,
2222
) {
23+
let local = if let Some(local) = local {
24+
Cow::Owned(format!("{:?}", local))
25+
} else {
26+
Cow::Borrowed("???")
27+
};
2328
let local_field = if let Some(local_field) = local_field {
2429
Cow::Owned(format!(".{}", local_field))
2530
} else {
2631
Cow::Borrowed("")
2732
};
33+
2834
let params = match params {
2935
Empty => Cow::Borrowed("-"),
3036
Single(param) => Cow::Owned(format!("= {:?}", param)),
3137
Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)),
3238
};
39+
3340
let pass_mode = format!("{:?}", pass_mode);
3441
fx.add_global_comment(format!(
3542
"{kind:5}{local:>3}{local_field:<5} {params:10} {pass_mode:36} {ty:?}",
3643
kind = kind,
37-
local = format!("{:?}", local),
44+
local = local,
3845
local_field = local_field,
3946
params = params,
4047
pass_mode = pass_mode,

src/abi/mod.rs

+45-11
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ fn clif_sig_from_fn_sig<'tcx>(
8080
triple: &target_lexicon::Triple,
8181
sig: FnSig<'tcx>,
8282
is_vtable_fn: bool,
83+
requires_caller_location: bool,
8384
) -> Signature {
8485
let abi = match sig.abi {
8586
Abi::System => {
@@ -125,7 +126,7 @@ fn clif_sig_from_fn_sig<'tcx>(
125126
})
126127
.flatten();
127128

128-
let (params, returns) = match get_pass_mode(
129+
let (mut params, returns): (Vec<_>, Vec<_>) = match get_pass_mode(
129130
tcx,
130131
tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap(),
131132
) {
@@ -150,6 +151,10 @@ fn clif_sig_from_fn_sig<'tcx>(
150151
}
151152
};
152153

154+
if requires_caller_location {
155+
params.push(AbiParam::new(pointer_ty(tcx)));
156+
}
157+
153158
Signature {
154159
params,
155160
returns,
@@ -169,7 +174,7 @@ pub fn get_function_name_and_sig<'tcx>(
169174
if fn_sig.c_variadic && !support_vararg {
170175
unimpl!("Variadic function definitions are not yet supported");
171176
}
172-
let sig = clif_sig_from_fn_sig(tcx, triple, fn_sig, false);
177+
let sig = clif_sig_from_fn_sig(tcx, triple, fn_sig, false, inst.def.requires_caller_location(tcx));
173178
(tcx.symbol_name(inst).name.as_str().to_string(), sig)
174179
}
175180

@@ -316,18 +321,24 @@ pub fn codegen_fn_prelude(fx: &mut FunctionCx<'_, '_, impl Backend>, start_ebb:
316321

317322
let mut params = Vec::new();
318323
for (i, arg_ty) in tupled_arg_tys.types().enumerate() {
319-
let param = cvalue_for_param(fx, start_ebb, local, Some(i), arg_ty);
324+
let param = cvalue_for_param(fx, start_ebb, Some(local), Some(i), arg_ty);
320325
params.push(param);
321326
}
322327

323328
(local, ArgKind::Spread(params), arg_ty)
324329
} else {
325-
let param = cvalue_for_param(fx, start_ebb, local, None, arg_ty);
330+
let param = cvalue_for_param(fx, start_ebb, Some(local), None, arg_ty);
326331
(local, ArgKind::Normal(param), arg_ty)
327332
}
328333
})
329334
.collect::<Vec<(Local, ArgKind, Ty)>>();
330335

336+
assert!(fx.caller_location.is_none());
337+
if fx.instance.def.requires_caller_location(fx.tcx) {
338+
// Store caller location for `#[track_caller]`.
339+
fx.caller_location = Some(cvalue_for_param(fx, start_ebb, None, None, fx.tcx.caller_location_ty()).unwrap());
340+
}
341+
331342
fx.bcx.switch_to_block(start_ebb);
332343
fx.bcx.ins().nop();
333344

@@ -403,10 +414,10 @@ pub fn codegen_fn_prelude(fx: &mut FunctionCx<'_, '_, impl Backend>, start_ebb:
403414

404415
pub fn codegen_terminator_call<'tcx>(
405416
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
417+
span: Span,
406418
func: &Operand<'tcx>,
407419
args: &[Operand<'tcx>],
408420
destination: &Option<(Place<'tcx>, BasicBlock)>,
409-
span: Span,
410421
) {
411422
let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
412423
let sig = fx
@@ -472,6 +483,7 @@ pub fn codegen_terminator_call<'tcx>(
472483

473484
codegen_call_inner(
474485
fx,
486+
span,
475487
Some(func),
476488
fn_ty,
477489
args,
@@ -488,6 +500,7 @@ pub fn codegen_terminator_call<'tcx>(
488500

489501
fn codegen_call_inner<'tcx>(
490502
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
503+
span: Span,
491504
func: Option<&Operand<'tcx>>,
492505
fn_ty: Ty<'tcx>,
493506
args: Vec<CValue<'tcx>>,
@@ -558,7 +571,7 @@ fn codegen_call_inner<'tcx>(
558571

559572
let (call_inst, call_args) =
560573
self::returning::codegen_with_call_return_arg(fx, fn_sig, ret_place, |fx, return_ptr| {
561-
let call_args: Vec<Value> = return_ptr
574+
let mut call_args: Vec<Value> = return_ptr
562575
.into_iter()
563576
.chain(first_arg.into_iter())
564577
.chain(
@@ -569,9 +582,20 @@ fn codegen_call_inner<'tcx>(
569582
)
570583
.collect::<Vec<_>>();
571584

585+
if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
586+
// Pass the caller location for `#[track_caller]`.
587+
let caller_location = fx.get_caller_location(span);
588+
call_args.extend(adjust_arg_for_abi(fx, caller_location).into_iter());
589+
}
590+
572591
let call_inst = if let Some(func_ref) = func_ref {
573-
let sig =
574-
clif_sig_from_fn_sig(fx.tcx, fx.triple(), fn_sig, is_virtual_call);
592+
let sig = clif_sig_from_fn_sig(
593+
fx.tcx,
594+
fx.triple(),
595+
fn_sig,
596+
is_virtual_call,
597+
false, // calls through function pointers never pass the caller location
598+
);
575599
let sig = fx.bcx.import_signature(sig);
576600
fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
577601
} else {
@@ -604,7 +628,11 @@ fn codegen_call_inner<'tcx>(
604628
}
605629
}
606630

607-
pub fn codegen_drop<'tcx>(fx: &mut FunctionCx<'_, 'tcx, impl Backend>, drop_place: CPlace<'tcx>) {
631+
pub fn codegen_drop<'tcx>(
632+
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
633+
span: Span,
634+
drop_place: CPlace<'tcx>,
635+
) {
608636
let ty = drop_place.layout().ty;
609637
let drop_fn = Instance::resolve_drop_in_place(fx.tcx, ty);
610638

@@ -625,7 +653,13 @@ pub fn codegen_drop<'tcx>(fx: &mut FunctionCx<'_, 'tcx, impl Backend>, drop_plac
625653

626654
assert_eq!(fn_sig.output(), fx.tcx.mk_unit());
627655

628-
let sig = clif_sig_from_fn_sig(fx.tcx, fx.triple(), fn_sig, true);
656+
let sig = clif_sig_from_fn_sig(
657+
fx.tcx,
658+
fx.triple(),
659+
fn_sig,
660+
true,
661+
false, // `drop_in_place` is never `#[track_caller]`
662+
);
629663
let sig = fx.bcx.import_signature(sig);
630664
fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
631665
}
@@ -642,7 +676,7 @@ pub fn codegen_drop<'tcx>(fx: &mut FunctionCx<'_, 'tcx, impl Backend>, drop_plac
642676
);
643677
drop_place.write_place_ref(fx, arg_place);
644678
let arg_value = arg_place.to_cvalue(fx);
645-
codegen_call_inner(fx, None, drop_fn_ty, vec![arg_value], None);
679+
codegen_call_inner(fx, span, None, drop_fn_ty, vec![arg_value], None);
646680
}
647681
}
648682
}

src/abi/pass_mode.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ pub fn adjust_arg_for_abi<'tcx>(
126126
pub fn cvalue_for_param<'tcx>(
127127
fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
128128
start_ebb: Ebb,
129-
local: mir::Local,
129+
local: Option<mir::Local>,
130130
local_field: Option<usize>,
131131
arg_ty: Ty<'tcx>,
132132
) -> Option<CValue<'tcx>> {

src/abi/returning.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub fn codegen_return_param(
4646
crate::abi::comments::add_arg_comment(
4747
fx,
4848
"ret",
49-
RETURN_PLACE,
49+
Some(RETURN_PLACE),
5050
None,
5151
ret_param,
5252
ret_pass_mode,

src/base.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub fn trans_fn<'clif, 'tcx, B: Backend + 'static>(
4848
bcx,
4949
ebb_map,
5050
local_map: HashMap::new(),
51+
caller_location: None, // set by `codegen_fn_prelude`
5152

5253
clif_comments,
5354
constants_cx: &mut cx.constants_cx,
@@ -236,10 +237,10 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Backend>) {
236237
} => {
237238
fx.tcx.sess.time("codegen call", || crate::abi::codegen_terminator_call(
238239
fx,
240+
bb_data.terminator().source_info.span,
239241
func,
240242
args,
241243
destination,
242-
bb_data.terminator().source_info.span,
243244
));
244245
}
245246
TerminatorKind::Resume | TerminatorKind::Abort => {
@@ -261,7 +262,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, impl Backend>) {
261262
unwind: _,
262263
} => {
263264
let drop_place = trans_place(fx, location);
264-
crate::abi::codegen_drop(fx, drop_place);
265+
crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
265266

266267
let target_ebb = fx.get_ebb(*target);
267268
fx.bcx.ins().jump(target_ebb, &[]);
@@ -370,7 +371,7 @@ fn trans_stmt<'tcx>(
370371
match from_ty.kind {
371372
ty::FnDef(def_id, substs) => {
372373
let func_ref = fx.get_function_ref(
373-
Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs)
374+
Instance::resolve_for_fn_ptr(fx.tcx, ParamEnv::reveal_all(), def_id, substs)
374375
.unwrap(),
375376
);
376377
let func_addr = fx.bcx.ins().func_addr(fx.pointer_type, func_ref);

src/common.rs

+8
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,9 @@ pub struct FunctionCx<'clif, 'tcx, B: Backend + 'static> {
267267
pub ebb_map: IndexVec<BasicBlock, Ebb>,
268268
pub local_map: HashMap<Local, CPlace<'tcx>>,
269269

270+
/// When `#[track_caller]` is used, the implicit caller location is stored in this variable.
271+
pub caller_location: Option<CValue<'tcx>>,
272+
270273
pub clif_comments: crate::pretty_clif::CommentWriter,
271274
pub constants_cx: &'clif mut crate::constant::ConstantCx,
272275
pub vtables: &'clif mut HashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), DataId>,
@@ -355,6 +358,11 @@ impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> {
355358
}
356359

357360
pub fn get_caller_location(&mut self, span: Span) -> CValue<'tcx> {
361+
if let Some(loc) = self.caller_location {
362+
// `#[track_caller]` is used; return caller location instead of current location.
363+
return loc;
364+
}
365+
358366
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
359367
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
360368
let const_loc = self.tcx.const_caller_location((

test.sh

+4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ echo "[AOT] subslice-patterns-const-eval"
6464
$RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort
6565
./target/out/subslice-patterns-const-eval
6666

67+
echo "[AOT] track-caller-attribute"
68+
$RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort
69+
./target/out/track-caller-attribute
70+
6771
echo "[BUILD] mod_bench"
6872
$RUSTC example/mod_bench.rs --crate-type bin
6973

0 commit comments

Comments
 (0)