From 3d39b9c78d0c2117e6e55d8cc68dc46be4e95ac2 Mon Sep 17 00:00:00 2001 From: Adam Perry <lol@anp.lol> Date: Sat, 18 Jul 2020 16:04:18 -0700 Subject: [PATCH] WIP Support `#[track_caller]` on closures.Closes #74042. --- src/librustc_codegen_ssa/mir/block.rs | 11 ++-- src/librustc_passes/check_attr.rs | 2 +- src/librustc_typeck/collect.rs | 2 +- .../track-caller-closure.rs | 54 +++++++++++++++++++ 4 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/rfc-2091-track-caller/track-caller-closure.rs diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 7116bb8c92517..e603a3f722bef 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -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", + // ); let location = self.get_caller_location(&mut bx, fn_span); debug!( "codegen_call_terminator({:?}): location={:?} (fn_span {:?})", diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 3e63a63d9d0f9..bf9f6b4b339b0 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -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, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index ec534aa925d4f..365d5061c6b33 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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(); } diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-closure.rs b/src/test/ui/rfc-2091-track-caller/track-caller-closure.rs new file mode 100644 index 0000000000000..13de16fe994d2 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/track-caller-closure.rs @@ -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); +}