From 9ab065dcda070680e18ca0da4366ad45e1665f0f Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 11 Nov 2019 08:45:52 -0800 Subject: [PATCH 01/16] Implement #[track_caller] in const. --- src/librustc/ty/instance.rs | 9 ++--- src/librustc_mir/interpret/intrinsics.rs | 1 + .../interpret/intrinsics/caller_location.rs | 22 ++++++++++++ .../const-eval/const_caller_location.rs | 36 ++++++++++++++----- .../const_caller_location.stderr | 8 +++++ 5 files changed, 63 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/rfc-2091-track-caller/const_caller_location.stderr diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index 801dfa81ef178..366951bc9f494 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -116,6 +116,10 @@ impl<'tcx> InstanceDef<'tcx> { } 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 @@ impl<'tcx> Instance<'tcx> { ) -> Option> { 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); } diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ad5df5aff1ac8..20f1a1d7c4844 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -112,6 +112,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `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)?; } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index ecf4b7a39b726..391c0c30bdecc 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -6,6 +6,28 @@ use syntax_pos::{Symbol, Span}; 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, diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs index c63822f052b2f..e36790505e882 100644 --- a/src/test/ui/consts/const-eval/const_caller_location.rs +++ b/src/test/ui/consts/const-eval/const_caller_location.rs @@ -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 fn nested_location() -> &'static Location<'static> { - caller_location() - }; - 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() +} + +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); } diff --git a/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr b/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr new file mode 100644 index 0000000000000..01a00dd28fda3 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr @@ -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 + From de44f09cc38be7b8d2bdc5d3e6426417cbe54a7a Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 27 Oct 2019 16:22:20 -0700 Subject: [PATCH 02/16] Rename test filename to match others. --- .../const-caller-location.rs} | 0 ...onst_caller_location.stderr => const-caller-location.stderr} | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/test/ui/{consts/const-eval/const_caller_location.rs => rfc-2091-track-caller/const-caller-location.rs} (100%) rename src/test/ui/rfc-2091-track-caller/{const_caller_location.stderr => const-caller-location.stderr} (86%) diff --git a/src/test/ui/consts/const-eval/const_caller_location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs similarity index 100% rename from src/test/ui/consts/const-eval/const_caller_location.rs rename to src/test/ui/rfc-2091-track-caller/const-caller-location.rs diff --git a/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr b/src/test/ui/rfc-2091-track-caller/const-caller-location.stderr similarity index 86% rename from src/test/ui/rfc-2091-track-caller/const_caller_location.stderr rename to src/test/ui/rfc-2091-track-caller/const-caller-location.stderr index 01a00dd28fda3..edb57199db85e 100644 --- a/src/test/ui/rfc-2091-track-caller/const_caller_location.stderr +++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.stderr @@ -1,5 +1,5 @@ warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/const_caller_location.rs:3:39 + --> $DIR/const-caller-location.rs:3:39 | LL | #![feature(const_fn, core_intrinsics, track_caller)] | ^^^^^^^^^^^^ From d47043b1c9ad716f8f773c4f03848be232558f6c Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 27 Oct 2019 16:27:32 -0700 Subject: [PATCH 03/16] Add failing test for codegen'd track_caller attribute. --- .../track-caller-attribute.rs | 40 +++++++++++++++++++ .../track-caller-attribute.stderr | 8 ++++ 2 files changed, 48 insertions(+) create mode 100644 src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs create mode 100644 src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs new file mode 100644 index 0000000000000..525c07e1c3ae8 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs @@ -0,0 +1,40 @@ +// run-pass + +#![feature(const_fn, core_intrinsics, track_caller)] + +use std::{intrinsics::caller_location, panic::Location}; + +#[track_caller] +fn tracked() -> &'static Location <'static> { + caller_location() +} + +fn nested_intrinsic() -> &'static Location<'static> { + caller_location() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +fn main() { + let location = caller_location(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 21); + assert_eq!(location.column(), 20); + + let tracked = tracked(); + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 26); + assert_eq!(tracked.column(), 19); + + let nested = nested_intrinsic(); + assert_eq!(nested.file(), file!()); + assert_eq!(nested.line(), 13); + assert_eq!(nested.column(), 5); + + let contained = nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 17); + assert_eq!(contained.column(), 5); +} diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr new file mode 100644 index 0000000000000..7e23c9d1dbedb --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr @@ -0,0 +1,8 @@ +warning: the feature `track_caller` is incomplete and may cause the compiler to crash + --> $DIR/track-caller-attribute.rs:3:39 + | +LL | #![feature(const_fn, core_intrinsics, track_caller)] + | ^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + From f1d942b371278aaca8897050645ac5351735bbb7 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 27 Oct 2019 17:31:12 -0700 Subject: [PATCH 04/16] Add field to FunctionCx for passing caller location. --- src/librustc_codegen_ssa/mir/block.rs | 20 ++++++++++++-------- src/librustc_codegen_ssa/mir/mod.rs | 4 ++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 6dccf329c9f64..4f47d84047d01 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1004,14 +1004,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, span: Span, ) -> OperandRef<'tcx, Bx::Value> { - let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); - let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo()); - let const_loc = bx.tcx().const_caller_location(( - Symbol::intern(&caller.file.name.to_string()), - caller.line as u32, - caller.col_display as u32 + 1, - )); - OperandRef::from_const(bx, const_loc) + if let Some(l) = self.caller_location { + bx.load_operand(l) + } else { + let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); + let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo()); + let const_loc = bx.tcx().const_caller_location(( + Symbol::intern(&caller.file.name.to_string()), + caller.line as u32, + caller.col_display as u32 + 1, + )); + OperandRef::from_const(bx, const_loc) + } } fn get_personality_slot( diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 3a157ca24a470..a6333ef23f5e8 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -77,6 +77,9 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { /// All `VarDebuginfo` from the MIR body, partitioned by `Local`. /// This is `None` if no variable debuginfo/names are needed. per_local_var_debug_info: Option>>>, + + /// Caller location propagated if this function has `#[track_caller]`. + caller_location: Option>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -172,6 +175,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( locals: IndexVec::new(), debug_context, per_local_var_debug_info: debuginfo::per_local_var_debug_info(cx.tcx(), mir_body), + caller_location: None, }; let memory_locals = analyze::non_ssa_locals(&fx); From 4773ded15ba23518cd3ba23ab30a2eaf69d9c20f Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Mon, 28 Oct 2019 20:02:41 -0700 Subject: [PATCH 05/16] Generate &core::panic::Location type in a single place. --- src/librustc/ty/context.rs | 10 ++++++++++ src/librustc_mir/const_eval.rs | 7 +------ src/librustc_typeck/check/intrinsic.rs | 11 +---------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6a0002cd80fd0..bf6c10dd3c956 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -8,6 +8,7 @@ use crate::session::Session; use crate::session::config::{BorrowckMode, OutputFilenames}; use crate::session::config::CrateType; use crate::middle; +use crate::middle::lang_items::PanicLocationLangItem; use crate::hir::{self, TraitCandidate, HirId, ItemKind, ItemLocalId, Node}; use crate::hir::def::{Res, DefKind, Export}; use crate::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; @@ -1588,6 +1589,15 @@ impl<'tcx> TyCtxt<'tcx> { pub fn has_strict_asm_symbol_naming(&self) -> bool { self.sess.target.target.arch.contains("nvptx") } + + /// Returns `&'static core::panic::Location<'static>`. + pub fn caller_location_ty(&self) -> Ty<'tcx> { + self.mk_imm_ref( + self.lifetimes.re_static, + self.type_of(self.require_lang_item(PanicLocationLangItem, None)) + .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), + ) + } } impl<'tcx> GlobalCtxt<'tcx> { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 968a8a71ba0ba..b6a2cc0a9ff51 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -9,7 +9,6 @@ use std::convert::TryInto; use rustc::hir::def::DefKind; use rustc::hir::def_id::DefId; -use rustc::middle::lang_items::PanicLocationLangItem; use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, Ty, TyCtxt, subst::Subst}; @@ -559,11 +558,7 @@ pub fn const_caller_location<'tcx>( trace!("const_caller_location: {}:{}:{}", file, line, col); let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all()); - let loc_ty = tcx.mk_imm_ref( - tcx.lifetimes.re_static, - tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None)) - .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())), - ); + let loc_ty = tcx.caller_location_ty(); let loc_place = ecx.alloc_caller_location(file, line, col); intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap(); let loc_const = ty::Const { diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 9f034e65b6eaa..2e19ee653c39f 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -1,7 +1,6 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. -use rustc::middle::lang_items::PanicLocationLangItem; use rustc::traits::{ObligationCause, ObligationCauseCode}; use rustc::ty::{self, TyCtxt, Ty}; use rustc::ty::subst::Subst; @@ -148,15 +147,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) { ], tcx.types.usize) } "rustc_peek" => (1, vec![param(0)], param(0)), - "caller_location" => ( - 0, - vec![], - tcx.mk_imm_ref( - tcx.lifetimes.re_static, - tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None)) - .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())), - ), - ), + "caller_location" => (0, vec![], tcx.caller_location_ty()), "panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()), "init" => (1, Vec::new(), param(0)), "uninit" => (1, Vec::new(), param(0)), From fa6bb398553200c0bc6ddba488eec43d5a497aef Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Tue, 5 Nov 2019 21:13:17 -0800 Subject: [PATCH 06/16] Add caller_location paramter to FnAbi::new_internal. We pass it in `of_instance` when the instance requires caller location. --- src/librustc/ty/layout.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 7f93e8c91e9d9..6c921134ab895 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -2434,6 +2434,7 @@ where cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>], + caller_location: Option>, mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgAbi<'tcx, Ty<'tcx>>, ) -> Self; fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); @@ -2448,13 +2449,19 @@ where + HasParamEnv<'tcx>, { fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - call::FnAbi::new_internal(cx, sig, extra_args, |ty, _| ArgAbi::new(cx.layout_of(ty))) + call::FnAbi::new_internal(cx, sig, extra_args, None, |ty, _| ArgAbi::new(cx.layout_of(ty))) } fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { let sig = instance.fn_sig_for_fn_abi(cx.tcx()); - call::FnAbi::new_internal(cx, sig, extra_args, |ty, arg_idx| { + let caller_location = if instance.def.requires_caller_location(cx.tcx()) { + Some(cx.tcx().caller_location_ty()) + } else { + None + }; + + call::FnAbi::new_internal(cx, sig, extra_args, caller_location, |ty, arg_idx| { let mut layout = cx.layout_of(ty); // Don't pass the vtable, it's not an argument of the virtual fn. // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` @@ -2512,6 +2519,7 @@ where cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>], + caller_location: Option>, mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgAbi<'tcx, Ty<'tcx>>, ) -> Self { debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args); @@ -2684,6 +2692,7 @@ where .iter() .cloned() .chain(extra_args) + .chain(caller_location) .enumerate() .map(|(i, ty)| arg_of(ty, Some(i))) .collect(), From 207f5208273667c5c72397fdf99390e594a3cdf1 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Thu, 7 Nov 2019 06:04:14 -0800 Subject: [PATCH 07/16] Pass a location to #[track_caller] functions in codegen_call_terminator. --- src/librustc_codegen_ssa/mir/block.rs | 12 ++++++++++++ src/librustc_codegen_ssa/mir/mod.rs | 21 +++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 4f47d84047d01..b33cca2ee8daa 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -770,6 +770,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &fn_abi.args[first_args.len()..]) } + let needs_location = + instance.map(|i| i.def.requires_caller_location(self.cx.tcx())).unwrap_or_default(); + 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", + ); + let location = self.get_caller_location(&mut bx, span); + let last_arg = &fn_abi.args.last().unwrap(); + self.codegen_argument(&mut bx, location, &mut llargs, last_arg); + } + let fn_ptr = match (llfn, instance) { (Some(llfn), _) => llfn, (None, Some(instance)) => bx.get_fn_addr(instance), diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index a6333ef23f5e8..6be6e13cc1d37 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -182,7 +182,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Allocate variable and temp allocas fx.locals = { - let args = arg_local_refs(&mut bx, &fx, &memory_locals); + let args = arg_local_refs(&mut bx, &mut fx, &memory_locals); let mut allocate_local = |local| { let decl = &mir_body.local_decls[local]; @@ -324,14 +324,14 @@ fn create_funclets<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// indirect. fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, - fx: &FunctionCx<'a, 'tcx, Bx>, + fx: &mut FunctionCx<'a, 'tcx, Bx>, memory_locals: &BitSet, ) -> Vec> { let mir = fx.mir; let mut idx = 0; let mut llarg_idx = fx.fn_abi.ret.is_indirect() as usize; - mir.args_iter().enumerate().map(|(arg_index, local)| { + let args = mir.args_iter().enumerate().map(|(arg_index, local)| { let arg_decl = &mir.local_decls[local]; if Some(local) == mir.spread_arg { @@ -427,7 +427,20 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.store_fn_arg(arg, &mut llarg_idx, tmp); LocalRef::Place(tmp) } - }).collect() + }).collect::>(); + + if fx.instance.def.requires_caller_location(bx.tcx()) { + assert_eq!( + fx.fn_abi.args.len(), args.len() + 1, + "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", + ); + let arg = &fx.fn_abi.args.last().unwrap(); + let place = PlaceRef::alloca(bx, arg.layout); + bx.store_fn_arg(arg, &mut llarg_idx, place); + fx.caller_location = Some(place); + } + + args } mod analyze; From ebaebd987f38227fe17cdc3eb23be819e4070429 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Thu, 7 Nov 2019 16:13:44 -0800 Subject: [PATCH 08/16] Remove #[track_caller] from incomplete features list. --- src/librustc_feature/active.rs | 1 - .../ui/rfc-2091-track-caller/const-caller-location.stderr | 8 -------- src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs | 2 +- src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr | 8 -------- .../ui/rfc-2091-track-caller/error-with-invalid-abi.rs | 2 +- .../rfc-2091-track-caller/error-with-invalid-abi.stderr | 8 -------- src/test/ui/rfc-2091-track-caller/error-with-naked.rs | 2 +- src/test/ui/rfc-2091-track-caller/error-with-naked.stderr | 8 -------- .../ui/rfc-2091-track-caller/error-with-trait-decl.rs | 2 +- .../ui/rfc-2091-track-caller/error-with-trait-decl.stderr | 8 -------- .../error-with-trait-default-impl.rs | 2 +- .../error-with-trait-default-impl.stderr | 8 -------- .../ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs | 2 +- .../rfc-2091-track-caller/error-with-trait-fn-impl.stderr | 8 -------- src/test/ui/rfc-2091-track-caller/only-for-fns.rs | 2 +- src/test/ui/rfc-2091-track-caller/only-for-fns.stderr | 8 -------- src/test/ui/rfc-2091-track-caller/pass.rs | 2 +- src/test/ui/rfc-2091-track-caller/pass.stderr | 8 -------- .../rfc-2091-track-caller/track-caller-attribute.stderr | 8 -------- 19 files changed, 8 insertions(+), 89 deletions(-) delete mode 100644 src/test/ui/rfc-2091-track-caller/const-caller-location.stderr delete mode 100644 src/test/ui/rfc-2091-track-caller/pass.stderr delete mode 100644 src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index fc880b9e92951..6f440f2ade552 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -538,5 +538,4 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::or_patterns, sym::let_chains, sym::raw_dylib, - sym::track_caller, ]; diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.stderr b/src/test/ui/rfc-2091-track-caller/const-caller-location.stderr deleted file mode 100644 index edb57199db85e..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/const-caller-location.stderr +++ /dev/null @@ -1,8 +0,0 @@ -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 - diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs index d400db8575e0a..d6560231871c9 100644 --- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs +++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] #[track_caller(1)] fn f() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr index a53a8ee2bedc6..8906fa59506a7 100644 --- a/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr @@ -4,13 +4,5 @@ error: malformed `track_caller` attribute input LL | #[track_caller(1)] | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[track_caller]` -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-odd-syntax.rs:1:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error: aborting due to previous error diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs index 162c6387088e7..4d9618a3bb0bd 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] #[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]` extern "C" fn f() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr index ad89b142f0ec8..bede0ea593c17 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -1,11 +1,3 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-with-invalid-abi.rs:1:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0737]: Rust ABI is required to use `#[track_caller]` --> $DIR/error-with-invalid-abi.rs:3:1 | diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs index bbbcec30e8d51..dd9e5d0413585 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.rs @@ -1,4 +1,4 @@ -#![feature(naked_functions, track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(naked_functions, track_caller)] #[track_caller] #[naked] diff --git a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr index 93e6f7a4cd32c..2f5003cfdb7a5 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-naked.stderr @@ -1,11 +1,3 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-with-naked.rs:1:29 - | -LL | #![feature(naked_functions, track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0736]: cannot use `#[track_caller]` with `#[naked]` --> $DIR/error-with-naked.rs:3:1 | diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs index 4fd768d640a55..ef037ab62aa3e 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] trait Trait { #[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr index 72ed6f89faa96..ded721d278253 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr @@ -1,11 +1,3 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-with-trait-decl.rs:1:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0738]: `#[track_caller]` may not be used on trait methods --> $DIR/error-with-trait-decl.rs:4:5 | diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs index 2139ba5de10c3..17e4bf41ddb53 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] trait Trait { #[track_caller] //~ ERROR: `#[track_caller]` may not be used on trait methods diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr index 05689c9468bec..867eb918b6e08 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr @@ -1,11 +1,3 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-with-trait-default-impl.rs:1:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0738]: `#[track_caller]` may not be used on trait methods --> $DIR/error-with-trait-default-impl.rs:4:5 | diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs index b565e11f55b2a..75f20f76e660d 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs @@ -1,6 +1,6 @@ // check-fail -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] trait Trait { fn unwrap(&self); diff --git a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr index 707b367484c2c..fafceefbfd839 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr @@ -1,11 +1,3 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/error-with-trait-fn-impl.rs:3:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0738]: `#[track_caller]` may not be used on trait methods --> $DIR/error-with-trait-fn-impl.rs:10:5 | diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs index 01ebf13b521b2..0fd59b4bf4918 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.rs +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] #[track_caller] struct S; diff --git a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr index 3301da7ff47bf..7becb9c5b60af 100644 --- a/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr +++ b/src/test/ui/rfc-2091-track-caller/only-for-fns.stderr @@ -1,11 +1,3 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/only-for-fns.rs:1:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error[E0739]: attribute should be applied to function --> $DIR/only-for-fns.rs:3:1 | diff --git a/src/test/ui/rfc-2091-track-caller/pass.rs b/src/test/ui/rfc-2091-track-caller/pass.rs index f2c3f0dc59e01..eef83b3d68f97 100644 --- a/src/test/ui/rfc-2091-track-caller/pass.rs +++ b/src/test/ui/rfc-2091-track-caller/pass.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(track_caller)] //~ WARN the feature `track_caller` is incomplete +#![feature(track_caller)] #[track_caller] fn f() {} diff --git a/src/test/ui/rfc-2091-track-caller/pass.stderr b/src/test/ui/rfc-2091-track-caller/pass.stderr deleted file mode 100644 index b1fd23a6a9ddb..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/pass.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/pass.rs:2:12 - | -LL | #![feature(track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr deleted file mode 100644 index 7e23c9d1dbedb..0000000000000 --- a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: the feature `track_caller` is incomplete and may cause the compiler to crash - --> $DIR/track-caller-attribute.rs:3:39 - | -LL | #![feature(const_fn, core_intrinsics, track_caller)] - | ^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - From bc6e66eb3aa432f422bc61cdb6f0e9c61025a6d5 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 10 Nov 2019 13:11:25 -0800 Subject: [PATCH 09/16] Implement core::panic::Location::caller using #[track_caller]. --- src/libcore/lib.rs | 1 + src/libcore/panic.rs | 54 +++++++++++++++++++ .../caller-location-intrinsic.rs | 8 +-- .../const-caller-location.rs | 10 ++-- .../track-caller-attribute.rs | 12 ++--- 5 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 188ea1a963116..8a514f1e78e80 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -102,6 +102,7 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] +#![cfg_attr(not(bootstrap), feature(track_caller))] #![feature(transparent_unions)] #![feature(unboxed_closures)] #![feature(unsized_locals)] diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 99b372d92c8b6..e924ee2036988 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -176,6 +176,60 @@ pub struct Location<'a> { col: u32, } +impl<'a> Location<'a> { + /// Returns the source location of the caller of this function. If that function's caller is + /// annotated then its call location will be returned, and so on up the stack to the first call + /// within a non-tracked function body. + /// + /// # Examples + /// + /// ``` + /// #![feature(track_caller)] + /// use core::panic::Location; + /// + /// /// Returns the [`Location`] at which it is called. + /// #[track_caller] + /// fn get_caller_location() -> &'static Location<'static> { + /// Location::caller() + /// } + /// + /// /// Returns a [`Location`] from within this function's definition. + /// fn get_just_one_location() -> &'static Location<'static> { + /// get_caller_location() + /// } + /// + /// let fixed_location = get_just_one_location(); + /// assert_eq!(fixed_location.file(), file!()); + /// assert_eq!(fixed_location.line(), 15); + /// assert_eq!(fixed_location.column(), 5); + /// + /// // running the same untracked function in a different location gives us the same result + /// let second_fixed_location = get_just_one_location(); + /// assert_eq!(fixed_location.file(), second_fixed_location.file()); + /// assert_eq!(fixed_location.line(), second_fixed_location.line()); + /// assert_eq!(fixed_location.column(), second_fixed_location.column()); + /// + /// let this_location = get_caller_location(); + /// assert_eq!(this_location.file(), file!()); + /// assert_eq!(this_location.line(), 29); + /// assert_eq!(this_location.column(), 21); + /// + /// // running the tracked function in a different location produces a different value + /// let another_location = get_caller_location(); + /// assert_eq!(this_location.file(), another_location.file()); + /// assert_ne!(this_location.line(), another_location.line()); + /// assert_ne!(this_location.column(), another_location.column()); + /// ``` + #[cfg(not(bootstrap))] + #[unstable(feature = "track_caller", + reason = "uses #[track_caller] which is not yet stable", + issue = "47809")] + #[track_caller] + pub const fn caller() -> &'static Location<'static> { + crate::intrinsics::caller_location() + } +} + impl<'a> Location<'a> { #![unstable(feature = "panic_internals", reason = "internal details of the implementation of the `panic!` \ diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs index 1c4d4666fa180..76e62b89ab818 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs +++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs @@ -1,18 +1,18 @@ // run-pass -#![feature(core_intrinsics)] +#![feature(track_caller)] macro_rules! caller_location_from_macro { - () => (core::intrinsics::caller_location()); + () => (core::panic::Location::caller()); } fn main() { - let loc = core::intrinsics::caller_location(); + let loc = core::panic::Location::caller(); assert_eq!(loc.file(), file!()); assert_eq!(loc.line(), 10); assert_eq!(loc.column(), 15); - // `caller_location()` in a macro should behave similarly to `file!` and `line!`, + // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let loc2 = caller_location_from_macro!(); assert_eq!(loc2.file(), file!()); diff --git a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs index e36790505e882..0614c52c66036 100644 --- a/src/test/ui/rfc-2091-track-caller/const-caller-location.rs +++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs @@ -1,20 +1,20 @@ // run-pass -#![feature(const_fn, core_intrinsics, track_caller)] +#![feature(const_fn, track_caller)] -use std::{intrinsics::caller_location, panic::Location}; +use std::panic::Location; -const LOCATION: &Location = caller_location(); +const LOCATION: &Location = Location::caller(); const TRACKED: &Location = tracked(); #[track_caller] const fn tracked() -> &'static Location <'static> { - caller_location() + Location::caller() } const NESTED: &Location = nested_location(); const fn nested_location() -> &'static Location<'static> { - caller_location() + Location::caller() } const CONTAINED: &Location = contained(); diff --git a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs index 525c07e1c3ae8..8436ee510a5bc 100644 --- a/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs +++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs @@ -1,16 +1,16 @@ // run-pass -#![feature(const_fn, core_intrinsics, track_caller)] +#![feature(const_fn, track_caller)] -use std::{intrinsics::caller_location, panic::Location}; +use std::panic::Location; #[track_caller] -fn tracked() -> &'static Location <'static> { - caller_location() +fn tracked() -> &'static Location<'static> { + Location::caller() } fn nested_intrinsic() -> &'static Location<'static> { - caller_location() + Location::caller() } fn nested_tracked() -> &'static Location<'static> { @@ -18,7 +18,7 @@ fn nested_tracked() -> &'static Location<'static> { } fn main() { - let location = caller_location(); + let location = Location::caller(); assert_eq!(location.file(), file!()); assert_eq!(location.line(), 21); assert_eq!(location.column(), 20); From eb679c9c5d57c88deaa313608af4011befc69605 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Thu, 14 Nov 2019 07:47:35 -0800 Subject: [PATCH 10/16] Add test for Location::caller in a macro. --- .../intrinsic-wrapper.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs diff --git a/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs new file mode 100644 index 0000000000000..76e62b89ab818 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs @@ -0,0 +1,21 @@ +// run-pass + +#![feature(track_caller)] + +macro_rules! caller_location_from_macro { + () => (core::panic::Location::caller()); +} + +fn main() { + let loc = core::panic::Location::caller(); + assert_eq!(loc.file(), file!()); + assert_eq!(loc.line(), 10); + assert_eq!(loc.column(), 15); + + // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, + // i.e. point to where the macro was invoked, instead of the macro itself. + let loc2 = caller_location_from_macro!(); + assert_eq!(loc2.file(), file!()); + assert_eq!(loc2.line(), 17); + assert_eq!(loc2.column(), 16); +} From 28b22571609ef415ef974844982ba5f03c447ab4 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 27 Oct 2019 13:32:18 -0700 Subject: [PATCH 11/16] Error message no longer implies #[track_caller] is a requirement for Rust ABI. --- src/librustc_typeck/collect.rs | 2 +- src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs | 3 ++- .../ui/rfc-2091-track-caller/error-with-invalid-abi.stderr | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 6d6e7685fa053..b9829793cbe50 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2616,7 +2616,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { tcx.sess, attr.span, E0737, - "Rust ABI is required to use `#[track_caller]`" + "`#[track_caller]` requires Rust ABI" ).emit(); } codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs index 4d9618a3bb0bd..20d29619ba404 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs @@ -1,6 +1,7 @@ #![feature(track_caller)] -#[track_caller] //~ ERROR Rust ABI is required to use `#[track_caller]` +#[track_caller] extern "C" fn f() {} +//~^^ ERROR `#[track_caller]` requires Rust ABI fn main() {} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr index bede0ea593c17..2a3a4385c8bf7 100644 --- a/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr +++ b/src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr @@ -1,4 +1,4 @@ -error[E0737]: Rust ABI is required to use `#[track_caller]` +error[E0737]: `#[track_caller]` requires Rust ABI --> $DIR/error-with-invalid-abi.rs:3:1 | LL | #[track_caller] From cc574be985c4932f6f80c6a8a52ece26d5883300 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Sun, 27 Oct 2019 15:16:46 -0700 Subject: [PATCH 12/16] `#[track_caller]` suppresses MIR inlining. --- src/librustc_mir/transform/inline.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 79cb7fb0b7692..6462672c01045 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -230,6 +230,11 @@ impl Inliner<'tcx> { let codegen_fn_attrs = tcx.codegen_fn_attrs(callsite.callee); + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::TRACK_CALLER) { + debug!("`#[track_caller]` present - not inlining"); + return false; + } + let hinted = match codegen_fn_attrs.inline { // Just treat inline(always) as a hint for now, // there are cases that prevent inlining that we From 7afbbf7e8add3c14e5fe30b1b5e4c4a26179b9b7 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 6 Dec 2019 07:11:28 -0800 Subject: [PATCH 13/16] Always call const fns with #[track_caller]. The caller location is passed as an implicit argument, so we must consider it when checking the sizedness of arguments. --- src/librustc_mir/const_eval.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index b6a2cc0a9ff51..0123d68d878d5 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -12,7 +12,7 @@ use rustc::hir::def_id::DefId; use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef}; use rustc::mir; use rustc::ty::{self, Ty, TyCtxt, subst::Subst}; -use rustc::ty::layout::{self, LayoutOf, VariantIdx}; +use rustc::ty::layout::{self, HasTyCtxt, LayoutOf, VariantIdx}; use rustc::traits::Reveal; use rustc_data_structures::fx::FxHashMap; use crate::interpret::eval_nullary_intrinsic; @@ -347,7 +347,11 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // // For the moment we only do this for functions which take no arguments // (or all arguments are ZSTs) so that we don't memoize too much. - if args.iter().all(|a| a.layout.is_zst()) { + // + // Because `#[track_caller]` adds an implicit non-ZST argument, we also cannot + // perform this optimization on items tagged with it. + let no_implicit_args = !instance.def.requires_caller_location(ecx.tcx()); + if args.iter().all(|a| a.layout.is_zst()) && no_implicit_args { let gid = GlobalId { instance, promoted: None }; ecx.eval_const_fn_call(gid, ret)?; return Ok(None); From 99165ce1f76573729530c241036a0514ca1cf232 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 6 Dec 2019 16:09:40 -0800 Subject: [PATCH 14/16] Caller location is propagated via immediates rather than memory. --- src/librustc_codegen_ssa/mir/block.rs | 6 ++---- src/librustc_codegen_ssa/mir/mod.rs | 15 +++++++++++---- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index b33cca2ee8daa..5d25f7022c512 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -1016,9 +1016,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &mut Bx, span: Span, ) -> OperandRef<'tcx, Bx::Value> { - if let Some(l) = self.caller_location { - bx.load_operand(l) - } else { + self.caller_location.unwrap_or_else(|| { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = bx.tcx().sess.source_map().lookup_char_pos(topmost.lo()); let const_loc = bx.tcx().const_caller_location(( @@ -1027,7 +1025,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { caller.col_display as u32 + 1, )); OperandRef::from_const(bx, const_loc) - } + }) } fn get_personality_slot( diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 6be6e13cc1d37..5e4da8f21257d 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -79,7 +79,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> { per_local_var_debug_info: Option>>>, /// Caller location propagated if this function has `#[track_caller]`. - caller_location: Option>, + caller_location: Option>, } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -434,10 +434,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( fx.fn_abi.args.len(), args.len() + 1, "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", ); + let arg = &fx.fn_abi.args.last().unwrap(); - let place = PlaceRef::alloca(bx, arg.layout); - bx.store_fn_arg(arg, &mut llarg_idx, place); - fx.caller_location = Some(place); + match arg.mode { + PassMode::Direct(_) => (), + _ => panic!("caller location must be PassMode::Direct, found {:?}", arg.mode), + } + + fx.caller_location = Some(OperandRef { + val: OperandValue::Immediate(bx.get_param(llarg_idx)), + layout: arg.layout, + }); } args From 1c2483eb6fd679fd7f63cc0c0fb9692a2aa698aa Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 6 Dec 2019 17:05:51 -0800 Subject: [PATCH 15/16] Address review feedback. --- src/librustc_codegen_ssa/mir/block.rs | 4 ++-- src/librustc_codegen_ssa/mir/mod.rs | 4 ++-- src/librustc_mir/interpret/intrinsics.rs | 2 +- .../interpret/intrinsics/caller_location.rs | 17 +++++------------ 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 5d25f7022c512..099ba5b39bb77 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -771,14 +771,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } let needs_location = - instance.map(|i| i.def.requires_caller_location(self.cx.tcx())).unwrap_or_default(); + 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", ); let location = self.get_caller_location(&mut bx, span); - let last_arg = &fn_abi.args.last().unwrap(); + let last_arg = fn_abi.args.last().unwrap(); self.codegen_argument(&mut bx, location, &mut llargs, last_arg); } diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/src/librustc_codegen_ssa/mir/mod.rs index 5e4da8f21257d..33e343de86be1 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/src/librustc_codegen_ssa/mir/mod.rs @@ -435,10 +435,10 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( "#[track_caller] fn's must have 1 more argument in their ABI than in their MIR", ); - let arg = &fx.fn_abi.args.last().unwrap(); + let arg = fx.fn_abi.args.last().unwrap(); match arg.mode { PassMode::Direct(_) => (), - _ => panic!("caller location must be PassMode::Direct, found {:?}", arg.mode), + _ => bug!("caller location must be PassMode::Direct, found {:?}", arg.mode), } fx.caller_location = Some(OperandRef { diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index 20f1a1d7c4844..67f0aed243da1 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -112,7 +112,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // `src/librustc/ty/constness.rs` match intrinsic_name { sym::caller_location => { - let span = self.find_closest_untracked_caller_location(span); + let span = self.find_closest_untracked_caller_location().unwrap_or(span); let location = self.alloc_caller_location_for_span(span); self.write_scalar(location.ptr, dest)?; } diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/src/librustc_mir/interpret/intrinsics/caller_location.rs index 391c0c30bdecc..ec843ef7a4d86 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -7,24 +7,17 @@ use crate::interpret::{Scalar, MemoryKind, MPlaceTy, intrinsics::{InterpCx, Mach 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; + /// not `#[track_caller]`. + crate fn find_closest_untracked_caller_location(&self) -> Option { + let mut caller_span = None; 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; + caller_span = Some(next_caller.span); } - intrinsic_loc + caller_span } /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. From 15d1f7cffdc0b111123a6d34a356eae95af04676 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Fri, 6 Dec 2019 17:10:47 -0800 Subject: [PATCH 16/16] Add additional layer of #[track_caller] to test, avoid const prop. --- .../caller-location-intrinsic.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs index 76e62b89ab818..0a79aea376fbc 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs +++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs @@ -2,20 +2,26 @@ #![feature(track_caller)] +#[inline(never)] +#[track_caller] +fn defeat_const_prop() -> &'static core::panic::Location<'static> { + core::panic::Location::caller() +} + macro_rules! caller_location_from_macro { - () => (core::panic::Location::caller()); + () => (defeat_const_prop()); } fn main() { - let loc = core::panic::Location::caller(); + let loc = defeat_const_prop(); assert_eq!(loc.file(), file!()); - assert_eq!(loc.line(), 10); + assert_eq!(loc.line(), 16); assert_eq!(loc.column(), 15); // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let loc2 = caller_location_from_macro!(); assert_eq!(loc2.file(), file!()); - assert_eq!(loc2.line(), 17); + assert_eq!(loc2.line(), 23); assert_eq!(loc2.column(), 16); }