about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAdam Perry <adam.n.perry@gmail.com>2019-10-09 08:25:41 -0700
committerAdam Perry <adam.n.perry@gmail.com>2019-10-27 12:50:52 -0700
commit743964ad3fe566ca2ce5c2de14f8733887d283fd (patch)
tree3f8e84bcab7700d4d5a7c25d330c3338888b9605
parentfcf516d827300d21eb9f6312e799578b6f359d5d (diff)
downloadrust-743964ad3fe566ca2ce5c2de14f8733887d283fd.tar.gz
rust-743964ad3fe566ca2ce5c2de14f8733887d283fd.zip
Implement core::intrinsics::caller_location.
Returns a `&core::panic::Location` corresponding to where it was
called, also making `Location` a lang item.
-rw-r--r--src/libcore/intrinsics.rs4
-rw-r--r--src/libcore/panic.rs1
-rw-r--r--src/librustc/middle/lang_items.rs1
-rw-r--r--src/librustc_codegen_llvm/builder.rs15
-rw-r--r--src/librustc_codegen_llvm/common.rs7
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs16
-rw-r--r--src/librustc_codegen_ssa/traits/consts.rs2
-rw-r--r--src/librustc_codegen_ssa/traits/statics.rs2
-rw-r--r--src/librustc_mir/const_eval.rs23
-rw-r--r--src/librustc_typeck/check/intrinsic.rs18
-rw-r--r--src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs9
11 files changed, 95 insertions, 3 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 4655d39fb8f..4e0f18b88fe 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -696,6 +696,10 @@ extern "rust-intrinsic" {
     /// This will statically either panic, or do nothing.
     pub fn panic_if_uninhabited<T>();
 
+    /// Gets a reference to a static `Location` indicating where it was called.
+    #[cfg(not(bootstrap))]
+    pub fn caller_location() -> &'static crate::panic::Location<'static>;
+
     /// Creates a value initialized to zero.
     ///
     /// `init` is unsafe because it returns a zeroed-out datum,
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
index 989fc96732a..9428ff3ef15 100644
--- a/src/libcore/panic.rs
+++ b/src/libcore/panic.rs
@@ -162,6 +162,7 @@ impl fmt::Display for PanicInfo<'_> {
 ///
 /// panic!("Normal panic");
 /// ```
+#[cfg_attr(not(bootstrap), lang = "panic_location")]
 #[derive(Debug)]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub struct Location<'a> {
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index cab929389d6..a17b5a115b8 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -366,6 +366,7 @@ language_item_table! {
     PanicFnLangItem,             "panic",              panic_fn,                Target::Fn;
     PanicBoundsCheckFnLangItem,  "panic_bounds_check", panic_bounds_check_fn,   Target::Fn;
     PanicInfoLangItem,           "panic_info",         panic_info,              Target::Struct;
+    PanicLocationLangItem,       "panic_location",     panic_location,          Target::Struct;
     PanicImplLangItem,           "panic_impl",         panic_impl,              Target::Fn;
     // Libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanicFnLangItem,        "begin_panic",        begin_panic_fn,          Target::Fn;
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 98be0ae4433..ffaf8050bcb 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -2,6 +2,7 @@ use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope};
 use crate::llvm::{self, False, BasicBlock};
 use crate::common::Funclet;
 use crate::context::CodegenCx;
+use crate::syntax_pos::Pos;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
@@ -1068,6 +1069,20 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
         self.cx().get_static(def_id)
     }
 
+    fn static_panic_location(&mut self, loc: &syntax::source_map::Loc) -> Self::Value {
+        let filename = Symbol::intern(&loc.file.name.to_string());
+        let filename = self.const_str(filename);
+        let line = self.const_u32(loc.line as u32);
+        let col = self.const_u32(loc.col.to_usize() as u32 + 1);
+        let struct_ = self.const_struct(&[filename.0, filename.1, line, col], false);
+
+        let align = self.tcx.data_layout.aggregate_align.abi
+            .max(self.tcx.data_layout.i32_align.abi)
+            .max(self.tcx.data_layout.pointer_align.abi);
+        // FIXME(eddyb) move this into miri, it can be correct if e.g. field order changes
+        self.static_addr_of(struct_, align, Some("panic_loc"))
+    }
+
     fn static_panic_msg(
         &mut self,
         msg: Option<Symbol>,
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index a1a5232d588..b4b82f67c74 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -237,6 +237,13 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         unsafe { llvm::LLVMConstReal(t, val) }
     }
 
+    fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
+        let len = s.as_str().len();
+        let cs = consts::ptrcast(self.const_cstr(s, false),
+            self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)));
+        (cs, self.const_usize(len as u64))
+    }
+
     fn const_struct(
         &self,
         elts: &[&'ll Value],
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index 28441cae26e..22ea6a39552 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -613,6 +613,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             ReturnDest::Nothing
         };
 
+        if intrinsic == Some("caller_location") {
+            if let Some((_, target)) = destination.as_ref() {
+                let loc = bx.sess().source_map().lookup_char_pos(span.lo());
+                let location = bx.static_panic_location(&loc);
+
+                if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
+                    Immediate(location).store(&mut bx, tmp);
+                }
+                self.store_return(&mut bx, ret_dest, &fn_ty.ret, location);
+
+                helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
+                helper.funclet_br(self, &mut bx, *target);
+            }
+            return;
+        }
+
         if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
             let dest = match ret_dest {
                 _ if fn_ty.ret.is_indirect() => llargs[0],
diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/src/librustc_codegen_ssa/traits/consts.rs
index 95ada60fae0..8c462e77d5e 100644
--- a/src/librustc_codegen_ssa/traits/consts.rs
+++ b/src/librustc_codegen_ssa/traits/consts.rs
@@ -3,6 +3,7 @@ use crate::mir::place::PlaceRef;
 use rustc::mir::interpret::Allocation;
 use rustc::mir::interpret::Scalar;
 use rustc::ty::layout;
+use syntax_pos::Symbol;
 
 pub trait ConstMethods<'tcx>: BackendTypes {
     // Constant constructors
@@ -19,6 +20,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
     fn const_u8(&self, i: u8) -> Self::Value;
     fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;
 
+    fn const_str(&self, s: Symbol) -> (Self::Value, Self::Value);
     fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
 
     fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;
diff --git a/src/librustc_codegen_ssa/traits/statics.rs b/src/librustc_codegen_ssa/traits/statics.rs
index 73c4c053979..b51f15b5823 100644
--- a/src/librustc_codegen_ssa/traits/statics.rs
+++ b/src/librustc_codegen_ssa/traits/statics.rs
@@ -1,4 +1,5 @@
 use super::BackendTypes;
+use syntax::source_map::Loc;
 use syntax_pos::symbol::Symbol;
 use rustc::hir::def_id::DefId;
 use rustc::ty::layout::Align;
@@ -10,6 +11,7 @@ pub trait StaticMethods: BackendTypes {
 
 pub trait StaticBuilderMethods: BackendTypes {
     fn get_static(&mut self, def_id: DefId) -> Self::Value;
+    fn static_panic_location(&mut self, loc: &Loc) -> Self::Value;
     fn static_panic_msg(
         &mut self,
         msg: Option<Symbol>,
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index bb02b99dd8d..eeaa3c6792d 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -9,6 +9,7 @@ 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};
@@ -505,6 +506,28 @@ pub fn const_field<'tcx>(
     op_to_const(&ecx, field)
 }
 
+pub fn const_caller_location<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    (file, line, col): (Symbol, u32, u32),
+) -> &'tcx ty::Const<'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_place = ecx.alloc_caller_location(file, line, col).unwrap();
+    intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
+    let loc_const = ty::Const {
+        ty: loc_ty,
+        val: ConstValue::Scalar(loc_place.ptr.into()),
+    };
+
+    tcx.mk_const(loc_const)
+}
+
 // this function uses `unwrap` copiously, because an already validated constant must have valid
 // fields and can thus never fail outside of compiler bugs
 pub fn const_variant_index<'tcx>(
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 72a0fe887b9..2c5757b1c9f 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -1,6 +1,8 @@
 //! Type-checking for the rust-intrinsic and platform-intrinsic
 //! intrinsics that the compiler exposes.
 
+use rustc::hir::{self, Mutability};
+use rustc::middle::lang_items::PanicLocationLangItem;
 use rustc::traits::{ObligationCause, ObligationCauseCode};
 use rustc::ty::{self, TyCtxt, Ty};
 use rustc::ty::subst::Subst;
@@ -9,8 +11,6 @@ use crate::require_same_types;
 use rustc_target::spec::abi::Abi;
 use syntax::symbol::Symbol;
 
-use rustc::hir;
-
 use std::iter;
 
 fn equate_intrinsic_type<'tcx>(
@@ -65,7 +65,7 @@ fn equate_intrinsic_type<'tcx>(
 /// Returns `true` if the given intrinsic is unsafe to call or not.
 pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
     match intrinsic {
-        "size_of" | "min_align_of" | "needs_drop" |
+        "size_of" | "min_align_of" | "needs_drop" | "caller_location" |
         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
         "wrapping_add" | "wrapping_sub" | "wrapping_mul" |
         "saturating_add" | "saturating_sub" |
@@ -143,6 +143,18 @@ 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_ref(
+                    tcx.lifetimes.re_static,
+                    ty::TypeAndMut {
+                        mutbl: Mutability::MutImmutable,
+                        ty: tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
+                            .subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
+                    },
+                ),
+            ),
             "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/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
new file mode 100644
index 00000000000..ab6c59384c4
--- /dev/null
+++ b/src/test/ui/rfc-2091-track-caller/caller-location-intrinsic.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+#![feature(core_intrinsics)]
+fn main() {
+    let loc = core::intrinsics::caller_location();
+    assert_eq!(loc.file(), file!());
+    assert_eq!(loc.line(), 5);
+    assert_eq!(loc.column(), 15);
+}