Skip to content

Commit

Permalink
Rollup merge of #65664 - anp:panic-location, r=eddyb
Browse files Browse the repository at this point in the history
`std::panic::Location` is a lang_item, add `core::intrinsics::caller_location` (RFC 2091 3/N)

[Tracking issue](#47809)
[RFC text](https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md)

@eddyb suggested doing this intrinsic implementation ahead of actually implementing the `#[track_caller]` attribute so that there's an easily tested intermediate step between adding the shim and wiring up the attribute.
  • Loading branch information
Centril authored Oct 28, 2019
2 parents c8eefdf + 86e55b1 commit 4728d66
Show file tree
Hide file tree
Showing 25 changed files with 331 additions and 145 deletions.
4 changes: 4 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
35 changes: 34 additions & 1 deletion src/libcore/macros.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/// Panics the current thread.
///
/// For details, see `std::macros`.
#[cfg(bootstrap)]
#[macro_export]
#[allow_internal_unstable(core_panic)]
#[allow_internal_unstable(core_panic, panic_internals)]
#[stable(feature = "core", since = "1.6.0")]
macro_rules! panic {
() => (
Expand All @@ -20,6 +21,38 @@ macro_rules! panic {
});
}

/// Panics the current thread.
///
/// For details, see `std::macros`.
#[cfg(not(bootstrap))]
#[macro_export]
#[allow_internal_unstable(core_panic, panic_internals)]
#[stable(feature = "core", since = "1.6.0")]
macro_rules! panic {
() => (
$crate::panic!("explicit panic")
);
($msg:expr) => ({
const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
$crate::file!(),
$crate::line!(),
$crate::column!(),
);
$crate::panicking::panic($msg, LOC)
});
($msg:expr,) => (
$crate::panic!($msg)
);
($fmt:expr, $($arg:tt)+) => ({
const LOC: &$crate::panic::Location<'_> = &$crate::panic::Location::internal_constructor(
$crate::file!(),
$crate::line!(),
$crate::column!(),
);
$crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+), LOC)
});
}

/// Asserts that two expressions are equal to each other (using [`PartialEq`]).
///
/// On panic, this macro will print the values of the expressions with their
Expand Down
18 changes: 12 additions & 6 deletions src/libcore/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::fmt;
pub struct PanicInfo<'a> {
payload: &'a (dyn Any + Send),
message: Option<&'a fmt::Arguments<'a>>,
location: Location<'a>,
location: &'a Location<'a>,
}

impl<'a> PanicInfo<'a> {
Expand All @@ -45,11 +45,16 @@ impl<'a> PanicInfo<'a> {
issue = "0")]
#[doc(hidden)]
#[inline]
pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
location: Location<'a>)
-> Self {
pub fn internal_constructor(
message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>,
) -> Self {
struct NoPayload;
PanicInfo { payload: &NoPayload, location, message }
PanicInfo {
location,
message,
payload: &NoPayload,
}
}

#[doc(hidden)]
Expand Down Expand Up @@ -162,6 +167,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> {
Expand All @@ -176,7 +182,7 @@ impl<'a> Location<'a> {
and related macros",
issue = "0")]
#[doc(hidden)]
pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
Location { file, line, col }
}

Expand Down
63 changes: 59 additions & 4 deletions src/libcore/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use crate::fmt;
use crate::panic::{Location, PanicInfo};

#[cfg(bootstrap)]
#[cold]
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
Expand All @@ -49,6 +50,27 @@ pub fn panic(expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), &(file, line, col))
}

#[cfg(not(bootstrap))]
#[cold]
// never inline unless panic_immediate_abort to avoid code
// bloat at the call sites as much as possible
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic"]
pub fn panic(expr: &str, location: &Location<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
unsafe { super::intrinsics::abort() }
}

// Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
// reduce size overhead. The format_args! macro uses str's Display trait to
// write expr, which calls Formatter::pad, which must accommodate string
// truncation and padding (even though none is used here). Using
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
// output binary, saving up to a few kilobytes.
panic_fmt(fmt::Arguments::new_v1(&[expr], &[]), location)
}

#[cfg(bootstrap)]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic_bounds_check"]
Expand All @@ -62,6 +84,22 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
len, index), file_line_col)
}

#[cfg(not(bootstrap))]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[lang = "panic_bounds_check"]
fn panic_bounds_check(location: &Location<'_>, index: usize, len: usize) -> ! {
if cfg!(feature = "panic_immediate_abort") {
unsafe { super::intrinsics::abort() }
}

panic_fmt(
format_args!("index out of bounds: the len is {} but the index is {}", len, index),
location
)
}

#[cfg(bootstrap)]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[cfg_attr( feature="panic_immediate_abort" ,inline)]
Expand All @@ -77,9 +115,26 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>, file_line_col: &(&'static str, u32, u3
}

let (file, line, col) = *file_line_col;
let pi = PanicInfo::internal_constructor(
Some(&fmt),
Location::internal_constructor(file, line, col),
);
let location = Location::internal_constructor(file, line, col);
let pi = PanicInfo::internal_constructor(Some(&fmt), &location);
unsafe { panic_impl(&pi) }
}

#[cfg(not(bootstrap))]
#[cold]
#[cfg_attr(not(feature="panic_immediate_abort"),inline(never))]
#[cfg_attr( feature="panic_immediate_abort" ,inline)]
pub fn panic_fmt(fmt: fmt::Arguments<'_>, location: &Location<'_>) -> ! {
if cfg!(feature = "panic_immediate_abort") {
unsafe { super::intrinsics::abort() }
}

// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
extern "Rust" {
#[lang = "panic_impl"]
fn panic_impl(pi: &PanicInfo<'_>) -> !;
}

let pi = PanicInfo::internal_constructor(Some(&fmt), location);
unsafe { panic_impl(&pi) }
}
1 change: 1 addition & 0 deletions src/librustc/middle/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,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;
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,12 @@ rustc_queries! {
no_force
desc { "extract field of const" }
}

query const_caller_location(key: (syntax_pos::Symbol, u32, u32)) -> &'tcx ty::Const<'tcx> {
eval_always
no_force
desc { "get a &core::panic::Location referring to a span" }
}
}

TypeChecking {
Expand Down
10 changes: 10 additions & 0 deletions src/librustc/ty/query/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,13 @@ impl<'tcx, T> Key for Canonical<'tcx, T> {
DUMMY_SP
}
}

impl Key for (Symbol, u32, u32) {
fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}

fn default_span(&self, _tcx: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}
31 changes: 0 additions & 31 deletions src/librustc_codegen_llvm/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use std::ffi::CStr;
use std::ops::{Deref, Range};
use std::ptr;
use std::iter::TrustedLen;
use syntax::symbol::Symbol;

// All Builders must have an llfn associated with them
#[must_use]
Expand Down Expand Up @@ -1067,36 +1066,6 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
// Forward to the `get_static` method of `CodegenCx`
self.cx().get_static(def_id)
}

fn static_panic_msg(
&mut self,
msg: Option<Symbol>,
filename: Symbol,
line: Self::Value,
col: Self::Value,
kind: &str,
) -> Self::Value {
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);

let filename = self.const_str_slice(filename);

let with_msg_components;
let without_msg_components;

let components = if let Some(msg) = msg {
let msg = self.const_str_slice(msg);
with_msg_components = [msg, filename, line, col];
&with_msg_components as &[_]
} else {
without_msg_components = [filename, line, col];
&without_msg_components as &[_]
};

let struct_ = self.const_struct(&components, false);
self.static_addr_of(struct_, align, Some(kind))
}
}

impl Builder<'a, 'll, 'tcx> {
Expand Down
25 changes: 7 additions & 18 deletions src/librustc_codegen_llvm/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
//! Code that is useful in various codegen modules.
use crate::llvm::{self, True, False, Bool, BasicBlock, OperandBundleDef, ConstantInt};
use crate::abi;
use crate::consts;
use crate::type_::Type;
use crate::type_of::LayoutLlvmExt;
Expand Down Expand Up @@ -96,16 +95,6 @@ impl BackendTypes for CodegenCx<'ll, 'tcx> {
}

impl CodegenCx<'ll, 'tcx> {
pub fn const_fat_ptr(
&self,
ptr: &'ll Value,
meta: &'ll Value
) -> &'ll Value {
assert_eq!(abi::FAT_PTR_ADDR, 0);
assert_eq!(abi::FAT_PTR_EXTRA, 1);
self.const_struct(&[ptr, meta], false)
}

pub fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
unsafe {
return llvm::LLVMConstArray(ty, elts.as_ptr(), elts.len() as c_uint);
Expand Down Expand Up @@ -150,13 +139,6 @@ impl CodegenCx<'ll, 'tcx> {
}
}

pub fn const_str_slice(&self, s: Symbol) -> &'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)));
self.const_fat_ptr(cs, self.const_usize(len as u64))
}

pub fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
unsafe {
assert_eq!(idx as c_uint as u64, idx);
Expand Down Expand Up @@ -237,6 +219,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],
Expand Down
Loading

0 comments on commit 4728d66

Please sign in to comment.