Skip to content

Commit

Permalink
Auto merge of #50338 - japaric:panic-impl, r=alexcrichton
Browse files Browse the repository at this point in the history
implement #[panic_implementation]

This implements the `#[panic_implementation]` attribute as instructed in #44489 (comment)

I haven't run the full test suite yet but at least all the compile-fail tests pass.

r? @nagisa
  • Loading branch information
bors committed Jun 3, 2018
2 parents be5f17c + 8ad15de commit 29f48cc
Show file tree
Hide file tree
Showing 32 changed files with 492 additions and 64 deletions.
25 changes: 11 additions & 14 deletions src/doc/unstable-book/src/language-features/lang-items.md
Expand Up @@ -19,6 +19,7 @@ sugar for dynamic allocations via `malloc` and `free`:
#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
#![no_std]
use core::intrinsics;
use core::panic::PanicInfo;
extern crate libc;
Expand Down Expand Up @@ -50,7 +51,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
}
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }
#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
#[no_mangle] pub extern fn rust_eh_register_frames () {}
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
Expand Down Expand Up @@ -110,6 +111,7 @@ in the same format as C:
#![feature(start)]
#![no_std]
use core::intrinsics;
use core::panic::PanicInfo;
// Pull in the system libc library for what crt0.o likely requires.
extern crate libc;
Expand All @@ -134,12 +136,9 @@ pub extern fn rust_eh_personality() {
pub extern fn rust_eh_unwind_resume() {
}
#[lang = "panic_fmt"]
#[lang = "panic_impl"]
#[no_mangle]
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
_file: &'static str,
_line: u32,
_column: u32) -> ! {
pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
```
Expand All @@ -155,6 +154,7 @@ compiler's name mangling too:
#![no_std]
#![no_main]
use core::intrinsics;
use core::panic::PanicInfo;
// Pull in the system libc library for what crt0.o likely requires.
extern crate libc;
Expand All @@ -179,12 +179,9 @@ pub extern fn rust_eh_personality() {
pub extern fn rust_eh_unwind_resume() {
}
#[lang = "panic_fmt"]
#[lang = "panic_impl"]
#[no_mangle]
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
_file: &'static str,
_line: u32,
_column: u32) -> ! {
pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
unsafe { intrinsics::abort() }
}
```
Expand Down Expand Up @@ -215,7 +212,7 @@ called. The language item's name is `eh_personality`.

The second function, `rust_begin_panic`, is also used by the failure mechanisms of the
compiler. When a panic happens, this controls the message that's displayed on
the screen. While the language item's name is `panic_fmt`, the symbol name is
the screen. While the language item's name is `panic_impl`, the symbol name is
`rust_begin_panic`.

A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume`
Expand Down Expand Up @@ -259,8 +256,8 @@ the source code.
- `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
- `panic`: `libcore/panicking.rs`
- `panic_bounds_check`: `libcore/panicking.rs`
- `panic_fmt`: `libcore/panicking.rs`
- `panic_fmt`: `libstd/panicking.rs`
- `panic_impl`: `libcore/panicking.rs`
- `panic_impl`: `libstd/panicking.rs`
- Allocations
- `owned_box`: `liballoc/boxed.rs`
- `exchange_malloc`: `liballoc/heap.rs`
Expand Down
10 changes: 7 additions & 3 deletions src/doc/unstable-book/src/language-features/used.md
Expand Up @@ -87,11 +87,13 @@ This condition can be met using `#[used]` and `#[link_section]` plus a linker
script.

``` rust,ignore
#![feature(lang_items)]
#![feature(panic_implementation)]
#![feature(used)]
#![no_main]
#![no_std]
use core::panic::PanicInfo;
extern "C" fn reset_handler() -> ! {
loop {}
}
Expand All @@ -100,8 +102,10 @@ extern "C" fn reset_handler() -> ! {
#[used]
static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
#[lang = "panic_fmt"]
fn panic_fmt() {}
#[panic_implementation]
fn panic_impl(info: &PanicInfo) -> ! {
loop {}
}
```

``` text
Expand Down
2 changes: 1 addition & 1 deletion src/libcore/lib.rs
Expand Up @@ -41,7 +41,7 @@
//! dictate the panic message, the file at which panic was invoked, and the
//! line and column inside the file. It is up to consumers of this core
//! library to define this panic function; it is only required to never
//! return. This requires a `lang` attribute named `panic_fmt`.
//! return. This requires a `lang` attribute named `panic_impl`.
//!
//! * `rust_eh_personality` - is used by the failure mechanisms of the
//! compiler. This is often mapped to GCC's personality function, but crates
Expand Down
6 changes: 4 additions & 2 deletions src/libcore/panic.rs
Expand Up @@ -35,6 +35,7 @@ use fmt;
///
/// panic!("Normal panic");
/// ```
#[cfg_attr(not(stage0), lang = "panic_info")]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
Expand All @@ -53,7 +54,8 @@ impl<'a> PanicInfo<'a> {
pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
location: Location<'a>)
-> Self {
PanicInfo { payload: &(), location, message }
struct NoPayload;
PanicInfo { payload: &NoPayload, location, message }
}

#[doc(hidden)]
Expand Down Expand Up @@ -121,7 +123,7 @@ impl<'a> PanicInfo<'a> {
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub fn location(&self) -> Option<&Location> {
// NOTE: If this is changed to sometimes return None,
// deal with that case in std::panicking::default_hook.
// deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
Some(&self.location)
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/libcore/panicking.rs
Expand Up @@ -37,6 +37,8 @@
issue = "0")]

use fmt;
#[cfg(not(stage0))]
use panic::{Location, PanicInfo};

#[cold] #[inline(never)] // this is the slow path, always
#[lang = "panic"]
Expand All @@ -59,6 +61,7 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32),
len, index), file_line_col)
}

#[cfg(stage0)]
#[cold] #[inline(never)]
pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! {
#[allow(improper_ctypes)]
Expand All @@ -70,3 +73,21 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32))
let (file, line, col) = *file_line_col;
unsafe { panic_impl(fmt, file, line, col) }
}

#[cfg(not(stage0))]
#[cold] #[inline(never)]
pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! {
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
#[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe
extern "Rust" {
#[lang = "panic_impl"]
fn panic_impl(pi: &PanicInfo) -> !;
}

let (file, line, col) = *file_line_col;
let pi = PanicInfo::internal_constructor(
Some(&fmt),
Location::internal_constructor(file, line, col),
);
unsafe { panic_impl(&pi) }
}
6 changes: 3 additions & 3 deletions src/librustc/diagnostics.rs
Expand Up @@ -637,8 +637,8 @@ Erroneous code example:
```compile_fail,E0152
#![feature(lang_items)]
#[lang = "panic_fmt"]
struct Foo; // error: duplicate lang item found: `panic_fmt`
#[lang = "panic_impl"]
struct Foo; // error: duplicate lang item found: `panic_impl`
```
Lang items are already implemented in the standard library. Unless you are
Expand Down Expand Up @@ -824,7 +824,7 @@ A list of available external lang items is available in
#![feature(lang_items)]
extern "C" {
#[lang = "panic_fmt"] // ok!
#[lang = "panic_impl"] // ok!
fn cake();
}
```
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/dead.rs
Expand Up @@ -284,7 +284,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
id: ast::NodeId,
attrs: &[ast::Attribute]) -> bool {
if attr::contains_name(attrs, "lang") {
if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") {
return true;
}

Expand Down
5 changes: 4 additions & 1 deletion src/librustc/middle/lang_items.rs
Expand Up @@ -185,6 +185,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
if let Some(value) = attribute.value_str() {
return Some((value, attribute.span));
}
} else if attribute.check_name("panic_implementation") {
return Some((Symbol::intern("panic_impl"), attribute.span))
}
}

Expand Down Expand Up @@ -299,7 +301,8 @@ language_item_table! {
// lang item, but do not have it defined.
PanicFnLangItem, "panic", panic_fn;
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn;
PanicFmtLangItem, "panic_fmt", panic_fmt;
PanicInfoLangItem, "panic_info", panic_info;
PanicImplLangItem, "panic_impl", panic_impl;

ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
BoxFreeFnLangItem, "box_free", box_free_fn;
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/weak_lang_items.rs
Expand Up @@ -148,7 +148,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
) }

weak_lang_items! {
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
panic_impl, PanicImplLangItem, rust_begin_unwind;
eh_personality, EhPersonalityLangItem, rust_eh_personality;
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
oom, OomLangItem, rust_oom;
Expand Down
58 changes: 56 additions & 2 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -96,7 +96,7 @@ use rustc::middle::region;
use rustc::mir::interpret::{GlobalId};
use rustc::ty::subst::{UnpackedKind, Subst, Substs};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate};
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::maps::Providers;
Expand Down Expand Up @@ -130,7 +130,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::map::Node;
use rustc::hir::{self, PatKind};
use rustc::hir::{self, PatKind, Item_};
use rustc::middle::lang_items;

mod autoderef;
Expand Down Expand Up @@ -1129,6 +1129,60 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
}
}

// Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !`
if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() {
if panic_impl_did == fn_hir_id.owner_def_id() {
if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() {
if declared_ret_ty.sty != ty::TyNever {
fcx.tcx.sess.span_err(
decl.output.span(),
"return type should be `!`",
);
}

let inputs = fn_sig.inputs();
let span = fcx.tcx.hir.span(fn_id);
if inputs.len() == 1 {
let arg_is_panic_info = match inputs[0].sty {
ty::TyRef(region, ty, mutbl) => match ty.sty {
ty::TyAdt(ref adt, _) => {
adt.did == panic_info_did &&
mutbl == hir::Mutability::MutImmutable &&
*region != RegionKind::ReStatic
},
_ => false,
},
_ => false,
};

if !arg_is_panic_info {
fcx.tcx.sess.span_err(
decl.inputs[0].span,
"argument should be `&PanicInfo`",
);
}

if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
if let Item_::ItemFn(_, _, _, _, ref generics, _) = item.node {
if !generics.params.is_empty() {
fcx.tcx.sess.span_err(
span,
"`#[panic_implementation]` function should have no type \
parameters",
);
}
}
}
} else {
fcx.tcx.sess.span_err(span, "function should have one argument");
}
} else {
fcx.tcx.sess.err("language item required, but not found: `panic_info`");
}
}

}

(fcx, gen_ty)
}

Expand Down
2 changes: 2 additions & 0 deletions src/libstd/lib.rs
Expand Up @@ -317,6 +317,8 @@
#![cfg_attr(windows, feature(used))]
#![feature(doc_alias)]
#![feature(float_internals)]
#![feature(panic_info_message)]
#![cfg_attr(not(stage0), feature(panic_implementation))]

#![default_lib_allocator]

Expand Down

0 comments on commit 29f48cc

Please sign in to comment.