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/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/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/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(), diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 6dccf329c9f64..099ba5b39bb77 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_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(); + 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), @@ -1004,14 +1016,16 @@ 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) + 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(( + 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..33e343de86be1 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,13 +175,14 @@ 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); // 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]; @@ -320,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 { @@ -423,7 +427,27 @@ 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(); + match arg.mode { + PassMode::Direct(_) => (), + _ => bug!("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 } mod analyze; 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/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 968a8a71ba0ba..0123d68d878d5 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -9,11 +9,10 @@ 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}; -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; @@ -348,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); @@ -559,11 +562,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_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ad5df5aff1ac8..67f0aed243da1 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().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 ecf4b7a39b726..ec843ef7a4d86 100644 --- a/src/librustc_mir/interpret/intrinsics/caller_location.rs +++ b/src/librustc_mir/interpret/intrinsics/caller_location.rs @@ -6,6 +6,21 @@ 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]`. + 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 = Some(next_caller.span); + } + + caller_span + } + + /// 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/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 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)), 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/consts/const-eval/const_caller_location.rs b/src/test/ui/consts/const-eval/const_caller_location.rs deleted file mode 100644 index c63822f052b2f..0000000000000 --- a/src/test/ui/consts/const-eval/const_caller_location.rs +++ /dev/null @@ -1,23 +0,0 @@ -// run-pass - -#![feature(const_fn, core_intrinsics)] - -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() -}; - -fn main() { - assert_eq!(LOCATION.file(), file!()); - assert_eq!(LOCATION.line(), 7); - assert_eq!(LOCATION.column(), 29); - - assert_eq!(NESTED.file(), file!()); - assert_eq!(NESTED.line(), 10); - assert_eq!(NESTED.column(), 9); -} 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..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 @@ -1,21 +1,27 @@ // run-pass -#![feature(core_intrinsics)] +#![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::intrinsics::caller_location()); + () => (defeat_const_prop()); } fn main() { - let loc = core::intrinsics::caller_location(); + 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); - // `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!()); - assert_eq!(loc2.line(), 17); + assert_eq!(loc2.line(), 23); assert_eq!(loc2.column(), 16); } 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 new file mode 100644 index 0000000000000..0614c52c66036 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/const-caller-location.rs @@ -0,0 +1,41 @@ +// run-pass + +#![feature(const_fn, track_caller)] + +use std::panic::Location; + +const LOCATION: &Location = Location::caller(); + +const TRACKED: &Location = tracked(); +#[track_caller] +const fn tracked() -> &'static Location <'static> { + Location::caller() +} + +const NESTED: &Location = nested_location(); +const fn nested_location() -> &'static Location<'static> { + Location::caller() +} + +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(), 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/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..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)] //~ WARN the feature `track_caller` is incomplete +#![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 ad89b142f0ec8..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,12 +1,4 @@ -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]` +error[E0737]: `#[track_caller]` requires Rust ABI --> $DIR/error-with-invalid-abi.rs:3:1 | LL | #[track_caller] 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/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); +} 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.rs b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs new file mode 100644 index 0000000000000..8436ee510a5bc --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs @@ -0,0 +1,40 @@ +// run-pass + +#![feature(const_fn, track_caller)] + +use std::panic::Location; + +#[track_caller] +fn tracked() -> &'static Location<'static> { + Location::caller() +} + +fn nested_intrinsic() -> &'static Location<'static> { + Location::caller() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +fn main() { + let location = Location::caller(); + 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); +}