Skip to content

Commit 743964a

Browse files
committed
Implement core::intrinsics::caller_location.
Returns a `&core::panic::Location` corresponding to where it was called, also making `Location` a lang item.
1 parent fcf516d commit 743964a

File tree

11 files changed

+95
-3
lines changed

11 files changed

+95
-3
lines changed

src/libcore/intrinsics.rs

+4
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,10 @@ extern "rust-intrinsic" {
696696
/// This will statically either panic, or do nothing.
697697
pub fn panic_if_uninhabited<T>();
698698

699+
/// Gets a reference to a static `Location` indicating where it was called.
700+
#[cfg(not(bootstrap))]
701+
pub fn caller_location() -> &'static crate::panic::Location<'static>;
702+
699703
/// Creates a value initialized to zero.
700704
///
701705
/// `init` is unsafe because it returns a zeroed-out datum,

src/libcore/panic.rs

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ impl fmt::Display for PanicInfo<'_> {
162162
///
163163
/// panic!("Normal panic");
164164
/// ```
165+
#[cfg_attr(not(bootstrap), lang = "panic_location")]
165166
#[derive(Debug)]
166167
#[stable(feature = "panic_hooks", since = "1.10.0")]
167168
pub struct Location<'a> {

src/librustc/middle/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ language_item_table! {
366366
PanicFnLangItem, "panic", panic_fn, Target::Fn;
367367
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn, Target::Fn;
368368
PanicInfoLangItem, "panic_info", panic_info, Target::Struct;
369+
PanicLocationLangItem, "panic_location", panic_location, Target::Struct;
369370
PanicImplLangItem, "panic_impl", panic_impl, Target::Fn;
370371
// Libstd panic entry point. Necessary for const eval to be able to catch it
371372
BeginPanicFnLangItem, "begin_panic", begin_panic_fn, Target::Fn;

src/librustc_codegen_llvm/builder.rs

+15
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope};
22
use crate::llvm::{self, False, BasicBlock};
33
use crate::common::Funclet;
44
use crate::context::CodegenCx;
5+
use crate::syntax_pos::Pos;
56
use crate::type_::Type;
67
use crate::type_of::LayoutLlvmExt;
78
use crate::value::Value;
@@ -1068,6 +1069,20 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
10681069
self.cx().get_static(def_id)
10691070
}
10701071

1072+
fn static_panic_location(&mut self, loc: &syntax::source_map::Loc) -> Self::Value {
1073+
let filename = Symbol::intern(&loc.file.name.to_string());
1074+
let filename = self.const_str(filename);
1075+
let line = self.const_u32(loc.line as u32);
1076+
let col = self.const_u32(loc.col.to_usize() as u32 + 1);
1077+
let struct_ = self.const_struct(&[filename.0, filename.1, line, col], false);
1078+
1079+
let align = self.tcx.data_layout.aggregate_align.abi
1080+
.max(self.tcx.data_layout.i32_align.abi)
1081+
.max(self.tcx.data_layout.pointer_align.abi);
1082+
// FIXME(eddyb) move this into miri, it can be correct if e.g. field order changes
1083+
self.static_addr_of(struct_, align, Some("panic_loc"))
1084+
}
1085+
10711086
fn static_panic_msg(
10721087
&mut self,
10731088
msg: Option<Symbol>,

src/librustc_codegen_llvm/common.rs

+7
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,13 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
237237
unsafe { llvm::LLVMConstReal(t, val) }
238238
}
239239

240+
fn const_str(&self, s: Symbol) -> (&'ll Value, &'ll Value) {
241+
let len = s.as_str().len();
242+
let cs = consts::ptrcast(self.const_cstr(s, false),
243+
self.type_ptr_to(self.layout_of(self.tcx.mk_str()).llvm_type(self)));
244+
(cs, self.const_usize(len as u64))
245+
}
246+
240247
fn const_struct(
241248
&self,
242249
elts: &[&'ll Value],

src/librustc_codegen_ssa/mir/block.rs

+16
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,22 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
613613
ReturnDest::Nothing
614614
};
615615

616+
if intrinsic == Some("caller_location") {
617+
if let Some((_, target)) = destination.as_ref() {
618+
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
619+
let location = bx.static_panic_location(&loc);
620+
621+
if let ReturnDest::IndirectOperand(tmp, _) = ret_dest {
622+
Immediate(location).store(&mut bx, tmp);
623+
}
624+
self.store_return(&mut bx, ret_dest, &fn_ty.ret, location);
625+
626+
helper.maybe_sideeffect(self.mir, &mut bx, &[*target]);
627+
helper.funclet_br(self, &mut bx, *target);
628+
}
629+
return;
630+
}
631+
616632
if intrinsic.is_some() && intrinsic != Some("drop_in_place") {
617633
let dest = match ret_dest {
618634
_ if fn_ty.ret.is_indirect() => llargs[0],

src/librustc_codegen_ssa/traits/consts.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::mir::place::PlaceRef;
33
use rustc::mir::interpret::Allocation;
44
use rustc::mir::interpret::Scalar;
55
use rustc::ty::layout;
6+
use syntax_pos::Symbol;
67

78
pub trait ConstMethods<'tcx>: BackendTypes {
89
// Constant constructors
@@ -19,6 +20,7 @@ pub trait ConstMethods<'tcx>: BackendTypes {
1920
fn const_u8(&self, i: u8) -> Self::Value;
2021
fn const_real(&self, t: Self::Type, val: f64) -> Self::Value;
2122

23+
fn const_str(&self, s: Symbol) -> (Self::Value, Self::Value);
2224
fn const_struct(&self, elts: &[Self::Value], packed: bool) -> Self::Value;
2325

2426
fn const_to_opt_uint(&self, v: Self::Value) -> Option<u64>;

src/librustc_codegen_ssa/traits/statics.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::BackendTypes;
2+
use syntax::source_map::Loc;
23
use syntax_pos::symbol::Symbol;
34
use rustc::hir::def_id::DefId;
45
use rustc::ty::layout::Align;
@@ -10,6 +11,7 @@ pub trait StaticMethods: BackendTypes {
1011

1112
pub trait StaticBuilderMethods: BackendTypes {
1213
fn get_static(&mut self, def_id: DefId) -> Self::Value;
14+
fn static_panic_location(&mut self, loc: &Loc) -> Self::Value;
1315
fn static_panic_msg(
1416
&mut self,
1517
msg: Option<Symbol>,

src/librustc_mir/const_eval.rs

+23
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::convert::TryInto;
99

1010
use rustc::hir::def::DefKind;
1111
use rustc::hir::def_id::DefId;
12+
use rustc::middle::lang_items::PanicLocationLangItem;
1213
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
1314
use rustc::mir;
1415
use rustc::ty::{self, Ty, TyCtxt, subst::Subst};
@@ -505,6 +506,28 @@ pub fn const_field<'tcx>(
505506
op_to_const(&ecx, field)
506507
}
507508

509+
pub fn const_caller_location<'tcx>(
510+
tcx: TyCtxt<'tcx>,
511+
(file, line, col): (Symbol, u32, u32),
512+
) -> &'tcx ty::Const<'tcx> {
513+
trace!("const_caller_location: {}:{}:{}", file, line, col);
514+
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::reveal_all());
515+
516+
let loc_ty = tcx.mk_imm_ref(
517+
tcx.lifetimes.re_static,
518+
tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
519+
.subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
520+
);
521+
let loc_place = ecx.alloc_caller_location(file, line, col).unwrap();
522+
intern_const_alloc_recursive(&mut ecx, None, loc_place).unwrap();
523+
let loc_const = ty::Const {
524+
ty: loc_ty,
525+
val: ConstValue::Scalar(loc_place.ptr.into()),
526+
};
527+
528+
tcx.mk_const(loc_const)
529+
}
530+
508531
// this function uses `unwrap` copiously, because an already validated constant must have valid
509532
// fields and can thus never fail outside of compiler bugs
510533
pub fn const_variant_index<'tcx>(

src/librustc_typeck/check/intrinsic.rs

+15-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Type-checking for the rust-intrinsic and platform-intrinsic
22
//! intrinsics that the compiler exposes.
33
4+
use rustc::hir::{self, Mutability};
5+
use rustc::middle::lang_items::PanicLocationLangItem;
46
use rustc::traits::{ObligationCause, ObligationCauseCode};
57
use rustc::ty::{self, TyCtxt, Ty};
68
use rustc::ty::subst::Subst;
@@ -9,8 +11,6 @@ use crate::require_same_types;
911
use rustc_target::spec::abi::Abi;
1012
use syntax::symbol::Symbol;
1113

12-
use rustc::hir;
13-
1414
use std::iter;
1515

1616
fn equate_intrinsic_type<'tcx>(
@@ -65,7 +65,7 @@ fn equate_intrinsic_type<'tcx>(
6565
/// Returns `true` if the given intrinsic is unsafe to call or not.
6666
pub fn intrinsic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
6767
match intrinsic {
68-
"size_of" | "min_align_of" | "needs_drop" |
68+
"size_of" | "min_align_of" | "needs_drop" | "caller_location" |
6969
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
7070
"wrapping_add" | "wrapping_sub" | "wrapping_mul" |
7171
"saturating_add" | "saturating_sub" |
@@ -143,6 +143,18 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem) {
143143
], tcx.types.usize)
144144
}
145145
"rustc_peek" => (1, vec![param(0)], param(0)),
146+
"caller_location" => (
147+
0,
148+
vec![],
149+
tcx.mk_ref(
150+
tcx.lifetimes.re_static,
151+
ty::TypeAndMut {
152+
mutbl: Mutability::MutImmutable,
153+
ty: tcx.type_of(tcx.require_lang_item(PanicLocationLangItem, None))
154+
.subst(tcx, tcx.mk_substs([tcx.lifetimes.re_static.into()].iter())),
155+
},
156+
),
157+
),
146158
"panic_if_uninhabited" => (1, Vec::new(), tcx.mk_unit()),
147159
"init" => (1, Vec::new(), param(0)),
148160
"uninit" => (1, Vec::new(), param(0)),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// run-pass
2+
3+
#![feature(core_intrinsics)]
4+
fn main() {
5+
let loc = core::intrinsics::caller_location();
6+
assert_eq!(loc.file(), file!());
7+
assert_eq!(loc.line(), 5);
8+
assert_eq!(loc.column(), 15);
9+
}

0 commit comments

Comments
 (0)