Panicking infra uses &core::panic::Location.

This allows us to remove `static_panic_msg` from the SSA<->LLVM
boundary, along with its fat pointer representation for &str.

Also changes the signature of PanicInfo::internal_contructor to
avoid copying.

Closes #65856.
This commit is contained in:
Adam Perry 2019-10-23 19:30:21 -07:00
parent 743964ad3f
commit aec97e050e
10 changed files with 130 additions and 127 deletions

View file

@ -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 {
() => (
@ -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

View file

@ -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> {
@ -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)]
@ -177,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 }
}

View file

@ -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
@ -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"]
@ -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)]
@ -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) }
}

View file

@ -1082,36 +1082,6 @@ impl StaticBuilderMethods for Builder<'a, 'll, 'tcx> {
// 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>,
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> {

View file

@ -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;
@ -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);
@ -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);

View file

@ -16,7 +16,6 @@ use crate::traits::*;
use std::borrow::Cow;
use syntax::symbol::Symbol;
use syntax_pos::Pos;
use super::{FunctionCx, LocalRef};
use super::place::PlaceRef;
@ -422,37 +421,19 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
// Get the location information.
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
let filename = Symbol::intern(&loc.file.name.to_string());
let line = bx.const_u32(loc.line as u32);
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
let location = bx.static_panic_location(&loc);
// Put together the arguments to the panic entry point.
let (lang_item, args) = match msg {
PanicInfo::BoundsCheck { ref len, ref index } => {
let len = self.codegen_operand(&mut bx, len).immediate();
let index = self.codegen_operand(&mut bx, index).immediate();
let file_line_col = bx.static_panic_msg(
None,
filename,
line,
col,
"panic_bounds_check_loc",
);
(lang_items::PanicBoundsCheckFnLangItem,
vec![file_line_col, index, len])
(lang_items::PanicBoundsCheckFnLangItem, vec![location, index, len])
}
_ => {
let msg_str = Symbol::intern(msg.description());
let msg_file_line_col = bx.static_panic_msg(
Some(msg_str),
filename,
line,
col,
"panic_loc",
);
(lang_items::PanicFnLangItem,
vec![msg_file_line_col])
let msg = bx.const_str(msg_str);
(lang_items::PanicFnLangItem, vec![msg.0, msg.1, location])
}
};
@ -554,22 +535,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let layout = bx.layout_of(ty);
if layout.abi.is_uninhabited() {
let loc = bx.sess().source_map().lookup_char_pos(span.lo());
let filename = Symbol::intern(&loc.file.name.to_string());
let line = bx.const_u32(loc.line as u32);
let col = bx.const_u32(loc.col.to_usize() as u32 + 1);
let str = format!(
"Attempted to instantiate uninhabited type {}",
ty
);
let msg_str = Symbol::intern(&str);
let msg_file_line_col = bx.static_panic_msg(
Some(msg_str),
filename,
line,
col,
"panic_loc",
);
let msg_str = format!("Attempted to instantiate uninhabited type {}", ty);
let msg = bx.const_str(Symbol::intern(&msg_str));
let location = bx.static_panic_location(&loc);
// Obtain the panic entry point.
let def_id =
@ -587,7 +556,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&mut bx,
fn_ty,
llfn,
&[msg_file_line_col],
&[msg.0, msg.1, location],
destination.as_ref().map(|(_, bb)| (ReturnDest::Nothing, *bb)),
cleanup,
);

View file

@ -1,6 +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;
@ -12,12 +11,4 @@ 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>,
filename: Symbol,
line: Self::Value,
col: Self::Value,
kind: &str,
) -> Self::Value;
}

View file

@ -301,18 +301,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> InterpResult<'tcx, bool> {
let def_id = instance.def_id();
if Some(def_id) == self.tcx.lang_items().panic_fn() {
assert!(args.len() == 1);
// &(&'static str, &'static str, u32, u32)
let place = self.deref_operand(args[0])?;
let (msg, file, line, col) = (
self.mplace_field(place, 0)?,
self.mplace_field(place, 1)?,
self.mplace_field(place, 2)?,
self.mplace_field(place, 3)?,
// &'static str, &core::panic::Location { &'static str, u32, u32 }
assert!(args.len() == 2);
let msg_place = self.deref_operand(args[0])?;
let msg = Symbol::intern(self.read_str(msg_place)?);
let location = self.deref_operand(args[1])?;
let (file, line, col) = (
self.mplace_field(location, 0)?,
self.mplace_field(location, 1)?,
self.mplace_field(location, 2)?,
);
let msg_place = self.deref_operand(msg.into())?;
let msg = Symbol::intern(self.read_str(msg_place)?);
let file_place = self.deref_operand(file.into())?;
let file = Symbol::intern(self.read_str(file_place)?);
let line = self.read_scalar(line.into())?.to_u32()?;

View file

@ -323,10 +323,8 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
}
let (file, line, col) = *file_line_col;
let info = PanicInfo::internal_constructor(
Some(msg),
Location::internal_constructor(file, line, col),
);
let location = Location::internal_constructor(file, line, col);
let info = PanicInfo::internal_constructor(Some(msg), &location);
continue_panic_fmt(&info)
}
@ -453,10 +451,8 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
}
unsafe {
let mut info = PanicInfo::internal_constructor(
message,
Location::internal_constructor(file, line, col),
);
let location = Location::internal_constructor(file, line, col);
let mut info = PanicInfo::internal_constructor(message, &location);
HOOK_LOCK.read();
match HOOK {
// Some platforms know that printing to stderr won't ever actually

View file

@ -22,7 +22,7 @@
//[thin]compile-flags: -C lto=thin
//[fat]compile-flags: -C lto=fat
#![feature(core_panic)]
#![feature(core_panic, panic_internals)]
// (For some reason, reproducing the LTO issue requires pulling in std
// explicitly this way.)
@ -51,7 +51,8 @@ fn main() {
let _guard = Droppable;
let s = "issue-64655-allow-unwind-when-calling-panic-directly.rs";
core::panicking::panic(&("???", s, 17, 4));
let location = core::panic::Location::internal_constructor(s, 17, 4);
core::panicking::panic("???", &location);
});
let wait = handle.join();