about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-07 21:14:39 +0000
committerbors <bors@rust-lang.org>2019-12-07 21:14:39 +0000
commitde17464b14e503edca6625daa9cd4c338ffafee2 (patch)
tree88969c0d7bbddc53c7fa798ae477efad19f2147c /src
parent5c5c8eb864e56ce905742b8e97df5506bba6aeef (diff)
parent15d1f7cffdc0b111123a6d34a356eae95af04676 (diff)
downloadrust-de17464b14e503edca6625daa9cd4c338ffafee2.tar.gz
rust-de17464b14e503edca6625daa9cd4c338ffafee2.zip
Auto merge of #65881 - anp:implicit-caller-location, r=eddyb,oli-obk
Implement #[track_caller] attribute. (RFC 2091 4/N)

Implements the `#[track_caller]` attribute in both const and codegen contexts.

The const implementation walks up the stack to find the nearest untracked callsite.

The codegen implementation adds an implicit argument to tracked function calls, and populates it with either a call to the previously-landed intrinsic or if the caller has `#[track_caller]` with a copy of the location passed to the current function.

Also includes a little cleanup and a few comments in the other caller location areas.

[Depends on: 65664](https://github.com/rust-lang/rust/pull/65664)
[RFC 2091 text](https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md)
[Tracking issue](https://github.com/rust-lang/rust/issues/47809)
[Tracking doc](https://paper.dropbox.com/doc/track_rfc_2091_impl-notes--Anf1NwnIb0xcRv31YLIadyj0Ag-rwCdRc2fi2yvRZ7syGZ9q#:uid=863513134494965680023183&h2=TODO-actually-pass-location-to)
Diffstat (limited to 'src')
-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);
+}