about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libcore/lib.rs1
-rw-r--r--src/libcore/panic.rs54
-rw-r--r--src/librustc/ty/context.rs10
-rw-r--r--src/librustc/ty/instance.rs9
-rw-r--r--src/librustc/ty/layout.rs13
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs30
-rw-r--r--src/librustc_codegen_ssa/mir/mod.rs32
-rw-r--r--src/librustc_feature/active.rs1
-rw-r--r--src/librustc_mir/const_eval.rs15
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs1
-rw-r--r--src/librustc_mir/interpret/intrinsics/caller_location.rs15
-rw-r--r--src/librustc_mir/transform/inline.rs5
-rw-r--r--src/librustc_typeck/check/intrinsic.rs11
-rw-r--r--src/librustc_typeck/collect.rs2
-rw-r--r--src/test/ui/consts/const-eval/const_caller_location.rs23
-rw-r--r--src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs18
-rw-r--r--src/test/ui/rfc-2091-track-caller/const-caller-location.rs41
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-odd-syntax.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-odd-syntax.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.rs5
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-invalid-abi.stderr10
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-naked.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-naked.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-decl.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-decl.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-default-impl.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/error-with-trait-fn-impl.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/intrinsic-wrapper.rs21
-rw-r--r--src/test/ui/rfc-2091-track-caller/only-for-fns.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/only-for-fns.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/pass.rs2
-rw-r--r--src/test/ui/rfc-2091-track-caller/pass.stderr8
-rw-r--r--src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs40
35 files changed, 286 insertions, 141 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 188ea1a9631..8a514f1e78e 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 99b372d92c8..e924ee20369 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -177,6 +177,60 @@ pub struct Location<'a> {
 }
 
 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!` \
                           and related macros",
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 6a0002cd80f..bf6c10dd3c9 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 801dfa81ef1..366951bc9f4 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<Instance<'tcx>> {
         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 7f93e8c91e9..6c921134ab8 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<Ty<'tcx>>,
         mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> 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<Ty<'tcx>>,
         mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> 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 ce703f24335..e68349660ba 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -774,6 +774,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),
@@ -1010,14 +1022,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 3a157ca24a4..33e343de86b 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<IndexVec<mir::Local, Vec<&'tcx mir::VarDebugInfo<'tcx>>>>,
+
+    /// Caller location propagated if this function has `#[track_caller]`.
+    caller_location: Option<OperandRef<'tcx, Bx::Value>>,
 }
 
 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<mir::Local>,
 ) -> Vec<LocalRef<'tcx, Bx::Value>> {
     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::<Vec<_>>();
+
+    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 b1ae7c6ca33..363621b3ca4 100644
--- a/src/librustc_feature/active.rs
+++ b/src/librustc_feature/active.rs
@@ -541,5 +541,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 968a8a71ba0..0123d68d878 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 ad5df5aff1a..67f0aed243d 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 ecf4b7a39b7..ec843ef7a4d 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<Span> {
+        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 79cb7fb0b76..6462672c010 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 b967c6e36e3..cec831147c4 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 6d6e7685fa0..b9829793cbe 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 c63822f052b..00000000000
--- 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 1c4d4666fa1..0a79aea376f 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 00000000000..0614c52c660
--- /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 d400db8575e..d6560231871 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 a53a8ee2bed..8906fa59506 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 162c6387088..20d29619ba4 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 ad89b142f0e..2a3a4385c8b 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 bbbcec30e8d..dd9e5d04135 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 93e6f7a4cd3..2f5003cfdb7 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 4fd768d640a..ef037ab62aa 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 72ed6f89faa..ded721d2782 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 2139ba5de10..17e4bf41ddb 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 05689c9468b..867eb918b6e 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 b565e11f55b..75f20f76e66 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 707b367484c..fafceefbfd8 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 00000000000..76e62b89ab8
--- /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 01ebf13b521..0fd59b4bf49 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 3301da7ff47..7becb9c5b60 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 f2c3f0dc59e..eef83b3d68f 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 b1fd23a6a9d..00000000000
--- 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 00000000000..8436ee510a5
--- /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);
+}