Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support #[track_caller] on closures. #74492

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/librustc_codegen_ssa/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -808,11 +808,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let needs_location =
instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx()));
if needs_location {
assert_eq!(
fn_abi.args.len(),
args.len() + 1,
"#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
);
// FIXME figure out the right number of args for closures
// assert_eq!(
// fn_abi.args.len(),
// args.len() + 1,
// "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR",
// );
Copy link
Member

@bjorn3 bjorn3 Jul 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the abi is "Rust-call" then the argument count is 1 (for the self argument) + the amount of elements in the type of the second argument (the operands bundle, which is a tuple).

let location = self.get_caller_location(&mut bx, fn_span);
debug!(
"codegen_call_terminator({:?}): location={:?} (fn_span {:?})",
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_passes/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl CheckAttrVisitor<'tcx> {
.emit();
false
}
Target::Fn | Target::Method(..) | Target::ForeignFn => true,
Target::Closure | Target::Fn | Target::ForeignFn | Target::Method(..) => true,
_ => {
struct_span_err!(
self.tcx.sess,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_typeck/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2413,7 +2413,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} else if attr.check_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if attr.check_name(sym::track_caller) {
if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
if !tcx.is_closure(id) && tcx.fn_sig(id).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
Expand Down
54 changes: 54 additions & 0 deletions src/test/ui/rfc-2091-track-caller/track-caller-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// run-pass

#![feature(stmt_expr_attributes)]

use std::panic::Location;

#[track_caller]
fn tracked() -> &'static Location<'static> {
let get_location = #[track_caller] || Location::caller();
get_location()
}

fn untracked_wrapper() -> (&'static Location<'static>, u32) {
let get_location = #[track_caller] || Location::caller();
(get_location(), line!())
}

fn nested_tracked() -> (&'static Location<'static>, u32) {
(tracked(), line!())
}

fn main() {
let get_location = #[track_caller] || Location::caller();
let (location, line) = (get_location(), line!());
assert_eq!(location.file(), file!());
assert_eq!(location.line(), line);

let (tracked, tracked_line) = (tracked(), line!());
assert_eq!(tracked.file(), file!());
assert_eq!(tracked.line(), tracked_line);

let (nested, nested_line) = untracked_wrapper();
assert_eq!(nested.file(), file!());
assert_eq!(nested.line(), nested_line);

let (contained, contained_line) = nested_tracked();
assert_eq!(contained.file(), file!());
assert_eq!(contained.line(), contained_line);

fn pass_to_ptr_call<T, R>(f: fn(T) -> R, x: T) -> R {
f(x)
}

let (get_location_w_n, line_from_shim) = (#[track_caller] |_| Location::caller(), line!());

let (location_with_arg, line_with_arg) = (get_location_w_n(3), line!());
assert_eq!(location_with_arg.file(), file!());
assert_eq!(location_with_arg.line(), line_with_arg);

let location_with_shim = pass_to_ptr_call(get_location_w_n, 5);
// FIXME make the closure's "def site" point to this file
assert_eq!(location_with_shim.file(), file!());
assert_eq!(location_with_shim.line(), line_from_shim);
}