Skip to content

Commit 29f48cc

Browse files
committed
Auto merge of #50338 - japaric:panic-impl, r=alexcrichton
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
2 parents be5f17c + 8ad15de commit 29f48cc

32 files changed

+492
-64
lines changed

src/doc/unstable-book/src/language-features/lang-items.md

+11-14
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ sugar for dynamic allocations via `malloc` and `free`:
1919
#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
2020
#![no_std]
2121
use core::intrinsics;
22+
use core::panic::PanicInfo;
2223
2324
extern crate libc;
2425
@@ -50,7 +51,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
5051
}
5152
5253
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
53-
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
54+
#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }
5455
#[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
5556
#[no_mangle] pub extern fn rust_eh_register_frames () {}
5657
#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
@@ -110,6 +111,7 @@ in the same format as C:
110111
#![feature(start)]
111112
#![no_std]
112113
use core::intrinsics;
114+
use core::panic::PanicInfo;
113115
114116
// Pull in the system libc library for what crt0.o likely requires.
115117
extern crate libc;
@@ -134,12 +136,9 @@ pub extern fn rust_eh_personality() {
134136
pub extern fn rust_eh_unwind_resume() {
135137
}
136138
137-
#[lang = "panic_fmt"]
139+
#[lang = "panic_impl"]
138140
#[no_mangle]
139-
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
140-
_file: &'static str,
141-
_line: u32,
142-
_column: u32) -> ! {
141+
pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
143142
unsafe { intrinsics::abort() }
144143
}
145144
```
@@ -155,6 +154,7 @@ compiler's name mangling too:
155154
#![no_std]
156155
#![no_main]
157156
use core::intrinsics;
157+
use core::panic::PanicInfo;
158158
159159
// Pull in the system libc library for what crt0.o likely requires.
160160
extern crate libc;
@@ -179,12 +179,9 @@ pub extern fn rust_eh_personality() {
179179
pub extern fn rust_eh_unwind_resume() {
180180
}
181181
182-
#[lang = "panic_fmt"]
182+
#[lang = "panic_impl"]
183183
#[no_mangle]
184-
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
185-
_file: &'static str,
186-
_line: u32,
187-
_column: u32) -> ! {
184+
pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
188185
unsafe { intrinsics::abort() }
189186
}
190187
```
@@ -215,7 +212,7 @@ called. The language item's name is `eh_personality`.
215212

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

221218
A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume`
@@ -259,8 +256,8 @@ the source code.
259256
- `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
260257
- `panic`: `libcore/panicking.rs`
261258
- `panic_bounds_check`: `libcore/panicking.rs`
262-
- `panic_fmt`: `libcore/panicking.rs`
263-
- `panic_fmt`: `libstd/panicking.rs`
259+
- `panic_impl`: `libcore/panicking.rs`
260+
- `panic_impl`: `libstd/panicking.rs`
264261
- Allocations
265262
- `owned_box`: `liballoc/boxed.rs`
266263
- `exchange_malloc`: `liballoc/heap.rs`

src/doc/unstable-book/src/language-features/used.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,13 @@ This condition can be met using `#[used]` and `#[link_section]` plus a linker
8787
script.
8888

8989
``` rust,ignore
90-
#![feature(lang_items)]
90+
#![feature(panic_implementation)]
9191
#![feature(used)]
9292
#![no_main]
9393
#![no_std]
9494
95+
use core::panic::PanicInfo;
96+
9597
extern "C" fn reset_handler() -> ! {
9698
loop {}
9799
}
@@ -100,8 +102,10 @@ extern "C" fn reset_handler() -> ! {
100102
#[used]
101103
static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
102104
103-
#[lang = "panic_fmt"]
104-
fn panic_fmt() {}
105+
#[panic_implementation]
106+
fn panic_impl(info: &PanicInfo) -> ! {
107+
loop {}
108+
}
105109
```
106110

107111
``` text

src/libcore/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
//! dictate the panic message, the file at which panic was invoked, and the
4242
//! line and column inside the file. It is up to consumers of this core
4343
//! library to define this panic function; it is only required to never
44-
//! return. This requires a `lang` attribute named `panic_fmt`.
44+
//! return. This requires a `lang` attribute named `panic_impl`.
4545
//!
4646
//! * `rust_eh_personality` - is used by the failure mechanisms of the
4747
//! compiler. This is often mapped to GCC's personality function, but crates

src/libcore/panic.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use fmt;
3535
///
3636
/// panic!("Normal panic");
3737
/// ```
38+
#[cfg_attr(not(stage0), lang = "panic_info")]
3839
#[stable(feature = "panic_hooks", since = "1.10.0")]
3940
#[derive(Debug)]
4041
pub struct PanicInfo<'a> {
@@ -53,7 +54,8 @@ impl<'a> PanicInfo<'a> {
5354
pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
5455
location: Location<'a>)
5556
-> Self {
56-
PanicInfo { payload: &(), location, message }
57+
struct NoPayload;
58+
PanicInfo { payload: &NoPayload, location, message }
5759
}
5860

5961
#[doc(hidden)]
@@ -121,7 +123,7 @@ impl<'a> PanicInfo<'a> {
121123
#[stable(feature = "panic_hooks", since = "1.10.0")]
122124
pub fn location(&self) -> Option<&Location> {
123125
// NOTE: If this is changed to sometimes return None,
124-
// deal with that case in std::panicking::default_hook.
126+
// deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
125127
Some(&self.location)
126128
}
127129
}

src/libcore/panicking.rs

+21
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
issue = "0")]
3838

3939
use fmt;
40+
#[cfg(not(stage0))]
41+
use panic::{Location, PanicInfo};
4042

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

64+
#[cfg(stage0)]
6265
#[cold] #[inline(never)]
6366
pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! {
6467
#[allow(improper_ctypes)]
@@ -70,3 +73,21 @@ pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32))
7073
let (file, line, col) = *file_line_col;
7174
unsafe { panic_impl(fmt, file, line, col) }
7275
}
76+
77+
#[cfg(not(stage0))]
78+
#[cold] #[inline(never)]
79+
pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! {
80+
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
81+
#[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe
82+
extern "Rust" {
83+
#[lang = "panic_impl"]
84+
fn panic_impl(pi: &PanicInfo) -> !;
85+
}
86+
87+
let (file, line, col) = *file_line_col;
88+
let pi = PanicInfo::internal_constructor(
89+
Some(&fmt),
90+
Location::internal_constructor(file, line, col),
91+
);
92+
unsafe { panic_impl(&pi) }
93+
}

src/librustc/diagnostics.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,8 @@ Erroneous code example:
637637
```compile_fail,E0152
638638
#![feature(lang_items)]
639639
640-
#[lang = "panic_fmt"]
641-
struct Foo; // error: duplicate lang item found: `panic_fmt`
640+
#[lang = "panic_impl"]
641+
struct Foo; // error: duplicate lang item found: `panic_impl`
642642
```
643643
644644
Lang items are already implemented in the standard library. Unless you are
@@ -824,7 +824,7 @@ A list of available external lang items is available in
824824
#![feature(lang_items)]
825825
826826
extern "C" {
827-
#[lang = "panic_fmt"] // ok!
827+
#[lang = "panic_impl"] // ok!
828828
fn cake();
829829
}
830830
```

src/librustc/middle/dead.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
284284
fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt,
285285
id: ast::NodeId,
286286
attrs: &[ast::Attribute]) -> bool {
287-
if attr::contains_name(attrs, "lang") {
287+
if attr::contains_name(attrs, "lang") || attr::contains_name(attrs, "panic_implementation") {
288288
return true;
289289
}
290290

src/librustc/middle/lang_items.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
185185
if let Some(value) = attribute.value_str() {
186186
return Some((value, attribute.span));
187187
}
188+
} else if attribute.check_name("panic_implementation") {
189+
return Some((Symbol::intern("panic_impl"), attribute.span))
188190
}
189191
}
190192

@@ -299,7 +301,8 @@ language_item_table! {
299301
// lang item, but do not have it defined.
300302
PanicFnLangItem, "panic", panic_fn;
301303
PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn;
302-
PanicFmtLangItem, "panic_fmt", panic_fmt;
304+
PanicInfoLangItem, "panic_info", panic_info;
305+
PanicImplLangItem, "panic_impl", panic_impl;
303306

304307
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
305308
BoxFreeFnLangItem, "box_free", box_free_fn;

src/librustc/middle/weak_lang_items.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
148148
) }
149149

150150
weak_lang_items! {
151-
panic_fmt, PanicFmtLangItem, rust_begin_unwind;
151+
panic_impl, PanicImplLangItem, rust_begin_unwind;
152152
eh_personality, EhPersonalityLangItem, rust_eh_personality;
153153
eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume;
154154
oom, OomLangItem, rust_oom;

src/librustc_typeck/check/mod.rs

+56-2
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ use rustc::middle::region;
9696
use rustc::mir::interpret::{GlobalId};
9797
use rustc::ty::subst::{UnpackedKind, Subst, Substs};
9898
use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
99-
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate};
99+
use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind};
100100
use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
101101
use rustc::ty::fold::TypeFoldable;
102102
use rustc::ty::maps::Providers;
@@ -130,7 +130,7 @@ use syntax_pos::{self, BytePos, Span, MultiSpan};
130130
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
131131
use rustc::hir::itemlikevisit::ItemLikeVisitor;
132132
use rustc::hir::map::Node;
133-
use rustc::hir::{self, PatKind};
133+
use rustc::hir::{self, PatKind, Item_};
134134
use rustc::middle::lang_items;
135135

136136
mod autoderef;
@@ -1129,6 +1129,60 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
11291129
}
11301130
}
11311131

1132+
// Check that a function marked as `#[panic_implementation]` has signature `fn(&PanicInfo) -> !`
1133+
if let Some(panic_impl_did) = fcx.tcx.lang_items().panic_impl() {
1134+
if panic_impl_did == fn_hir_id.owner_def_id() {
1135+
if let Some(panic_info_did) = fcx.tcx.lang_items().panic_info() {
1136+
if declared_ret_ty.sty != ty::TyNever {
1137+
fcx.tcx.sess.span_err(
1138+
decl.output.span(),
1139+
"return type should be `!`",
1140+
);
1141+
}
1142+
1143+
let inputs = fn_sig.inputs();
1144+
let span = fcx.tcx.hir.span(fn_id);
1145+
if inputs.len() == 1 {
1146+
let arg_is_panic_info = match inputs[0].sty {
1147+
ty::TyRef(region, ty, mutbl) => match ty.sty {
1148+
ty::TyAdt(ref adt, _) => {
1149+
adt.did == panic_info_did &&
1150+
mutbl == hir::Mutability::MutImmutable &&
1151+
*region != RegionKind::ReStatic
1152+
},
1153+
_ => false,
1154+
},
1155+
_ => false,
1156+
};
1157+
1158+
if !arg_is_panic_info {
1159+
fcx.tcx.sess.span_err(
1160+
decl.inputs[0].span,
1161+
"argument should be `&PanicInfo`",
1162+
);
1163+
}
1164+
1165+
if let Node::NodeItem(item) = fcx.tcx.hir.get(fn_id) {
1166+
if let Item_::ItemFn(_, _, _, _, ref generics, _) = item.node {
1167+
if !generics.params.is_empty() {
1168+
fcx.tcx.sess.span_err(
1169+
span,
1170+
"`#[panic_implementation]` function should have no type \
1171+
parameters",
1172+
);
1173+
}
1174+
}
1175+
}
1176+
} else {
1177+
fcx.tcx.sess.span_err(span, "function should have one argument");
1178+
}
1179+
} else {
1180+
fcx.tcx.sess.err("language item required, but not found: `panic_info`");
1181+
}
1182+
}
1183+
1184+
}
1185+
11321186
(fcx, gen_ty)
11331187
}
11341188

src/libstd/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@
317317
#![cfg_attr(windows, feature(used))]
318318
#![feature(doc_alias)]
319319
#![feature(float_internals)]
320+
#![feature(panic_info_message)]
321+
#![cfg_attr(not(stage0), feature(panic_implementation))]
320322

321323
#![default_lib_allocator]
322324

0 commit comments

Comments
 (0)