Skip to content

Commit 538f118

Browse files
committed
Auto merge of #102732 - RalfJung:assert_unsafe_precondition2, r=bjorn3
nicer errors from assert_unsafe_precondition This makes the errors shown by cargo-careful nicer, and since `panic_no_unwind` is `nounwind noreturn` it hopefully doesn't have bad codegen impact. Thanks to `@bjorn3` for the hint! Would be nice if we could somehow supply our own (static) message to print, currently it always prints `panic in a function that cannot unwind`. But still, this is better than before.
2 parents 50f6d33 + 38c78a9 commit 538f118

File tree

8 files changed

+90
-71
lines changed

8 files changed

+90
-71
lines changed

Diff for: compiler/rustc_feature/src/builtin_attrs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -536,7 +536,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
536536
// ==========================================================================
537537

538538
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
539-
rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
539+
rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
540540
rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
541541
rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
542542
rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+1-8
Original file line numberDiff line numberDiff line change
@@ -1582,13 +1582,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
15821582
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
15831583
}
15841584

1585-
// The panic_no_unwind function called by TerminatorKind::Abort will never
1586-
// unwind. If the panic handler that it invokes unwind then it will simply
1587-
// call the panic handler again.
1588-
if Some(did.to_def_id()) == tcx.lang_items().panic_no_unwind() {
1589-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
1590-
}
1591-
15921585
let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
15931586

15941587
let mut inline_span = None;
@@ -1649,7 +1642,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
16491642
)
16501643
.emit();
16511644
}
1652-
} else if attr.has_name(sym::rustc_allocator_nounwind) {
1645+
} else if attr.has_name(sym::rustc_nounwind) {
16531646
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
16541647
} else if attr.has_name(sym::rustc_reallocator) {
16551648
codegen_fn_attrs.flags |= CodegenFnAttrFlags::REALLOCATOR;

Diff for: compiler/rustc_span/src/symbol.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1231,7 +1231,6 @@ symbols! {
12311231
rust_oom,
12321232
rustc,
12331233
rustc_allocator,
1234-
rustc_allocator_nounwind,
12351234
rustc_allocator_zeroed,
12361235
rustc_allow_const_fn_unstable,
12371236
rustc_allow_incoherent_impl,
@@ -1278,6 +1277,7 @@ symbols! {
12781277
rustc_mir,
12791278
rustc_must_implement_one_of,
12801279
rustc_nonnull_optimization_guaranteed,
1280+
rustc_nounwind,
12811281
rustc_object_lifetime_default,
12821282
rustc_on_unimplemented,
12831283
rustc_outlives,

Diff for: library/alloc/src/alloc.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,20 @@ extern "Rust" {
2828
// The rustc fork of LLVM 14 and earlier also special-cases these function names to be able to optimize them
2929
// like `malloc`, `realloc`, and `free`, respectively.
3030
#[rustc_allocator]
31-
#[rustc_allocator_nounwind]
31+
#[cfg_attr(not(bootstrap), rustc_nounwind)]
32+
#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
3233
fn __rust_alloc(size: usize, align: usize) -> *mut u8;
3334
#[rustc_deallocator]
34-
#[rustc_allocator_nounwind]
35+
#[cfg_attr(not(bootstrap), rustc_nounwind)]
36+
#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
3537
fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
3638
#[rustc_reallocator]
37-
#[rustc_allocator_nounwind]
39+
#[cfg_attr(not(bootstrap), rustc_nounwind)]
40+
#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
3841
fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
3942
#[rustc_allocator_zeroed]
40-
#[rustc_allocator_nounwind]
43+
#[cfg_attr(not(bootstrap), rustc_nounwind)]
44+
#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
4145
fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
4246
}
4347

Diff for: library/core/src/intrinsics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2210,8 +2210,8 @@ macro_rules! assert_unsafe_precondition {
22102210
#[inline(always)]
22112211
fn runtime$(<$($tt)*>)?($($i:$ty),*) {
22122212
if !$e {
2213-
// abort instead of panicking to reduce impact on code size
2214-
::core::intrinsics::abort();
2213+
// don't unwind to reduce impact on code size
2214+
::core::panicking::panic_str_nounwind("unsafe precondition violated");
22152215
}
22162216
}
22172217
#[allow(non_snake_case)]

Diff for: library/core/src/panicking.rs

+74-52
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,73 @@
2929
use crate::fmt;
3030
use crate::panic::{Location, PanicInfo};
3131

32+
// First we define the two main entry points that all panics go through.
33+
// In the end both are just convenience wrappers around `panic_impl`.
34+
35+
/// The entry point for panicking with a formatted message.
36+
///
37+
/// This is designed to reduce the amount of code required at the call
38+
/// site as much as possible (so that `panic!()` has as low an impact
39+
/// on (e.g.) the inlining of other functions as possible), by moving
40+
/// the actual formatting into this shared place.
41+
#[cold]
42+
// If panic_immediate_abort, inline the abort call,
43+
// otherwise avoid inlining because of it is cold path.
44+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
45+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
46+
#[track_caller]
47+
#[lang = "panic_fmt"] // needed for const-evaluated panics
48+
#[rustc_do_not_const_check] // hooked by const-eval
49+
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
50+
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
51+
if cfg!(feature = "panic_immediate_abort") {
52+
super::intrinsics::abort()
53+
}
54+
55+
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
56+
// that gets resolved to the `#[panic_handler]` function.
57+
extern "Rust" {
58+
#[lang = "panic_impl"]
59+
fn panic_impl(pi: &PanicInfo<'_>) -> !;
60+
}
61+
62+
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
63+
64+
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
65+
unsafe { panic_impl(&pi) }
66+
}
67+
68+
/// Like panic_fmt, but without unwinding and track_caller to reduce the impact on codesize.
69+
/// Also just works on `str`, as a `fmt::Arguments` needs more space to be passed.
70+
#[cold]
71+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
72+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
73+
#[cfg_attr(not(bootstrap), rustc_nounwind)]
74+
#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
75+
pub fn panic_str_nounwind(msg: &'static str) -> ! {
76+
if cfg!(feature = "panic_immediate_abort") {
77+
super::intrinsics::abort()
78+
}
79+
80+
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
81+
// that gets resolved to the `#[panic_handler]` function.
82+
extern "Rust" {
83+
#[lang = "panic_impl"]
84+
fn panic_impl(pi: &PanicInfo<'_>) -> !;
85+
}
86+
87+
// PanicInfo with the `can_unwind` flag set to false forces an abort.
88+
let pieces = [msg];
89+
let fmt = fmt::Arguments::new_v1(&pieces, &[]);
90+
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
91+
92+
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
93+
unsafe { panic_impl(&pi) }
94+
}
95+
96+
// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
97+
// above.
98+
3299
/// The underlying implementation of libcore's `panic!` macro when no formatting is used.
33100
#[cold]
34101
// never inline unless panic_immediate_abort to avoid code
@@ -84,62 +151,17 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
84151
panic!("index out of bounds: the len is {len} but the index is {index}")
85152
}
86153

87-
// This function is called directly by the codegen backend, and must not have
88-
// any extra arguments (including those synthesized by track_caller).
154+
/// Panic because we cannot unwind out of a function.
155+
///
156+
/// This function is called directly by the codegen backend, and must not have
157+
/// any extra arguments (including those synthesized by track_caller).
89158
#[cold]
90159
#[inline(never)]
91160
#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
161+
#[cfg_attr(not(bootstrap), rustc_nounwind)]
162+
#[cfg_attr(bootstrap, rustc_allocator_nounwind)]
92163
fn panic_no_unwind() -> ! {
93-
if cfg!(feature = "panic_immediate_abort") {
94-
super::intrinsics::abort()
95-
}
96-
97-
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
98-
// that gets resolved to the `#[panic_handler]` function.
99-
extern "Rust" {
100-
#[lang = "panic_impl"]
101-
fn panic_impl(pi: &PanicInfo<'_>) -> !;
102-
}
103-
104-
// PanicInfo with the `can_unwind` flag set to false forces an abort.
105-
let fmt = format_args!("panic in a function that cannot unwind");
106-
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
107-
108-
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
109-
unsafe { panic_impl(&pi) }
110-
}
111-
112-
/// The entry point for panicking with a formatted message.
113-
///
114-
/// This is designed to reduce the amount of code required at the call
115-
/// site as much as possible (so that `panic!()` has as low an impact
116-
/// on (e.g.) the inlining of other functions as possible), by moving
117-
/// the actual formatting into this shared place.
118-
#[cold]
119-
// If panic_immediate_abort, inline the abort call,
120-
// otherwise avoid inlining because of it is cold path.
121-
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
122-
#[cfg_attr(feature = "panic_immediate_abort", inline)]
123-
#[track_caller]
124-
#[lang = "panic_fmt"] // needed for const-evaluated panics
125-
#[rustc_do_not_const_check] // hooked by const-eval
126-
#[rustc_const_unstable(feature = "core_panic", issue = "none")]
127-
pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
128-
if cfg!(feature = "panic_immediate_abort") {
129-
super::intrinsics::abort()
130-
}
131-
132-
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
133-
// that gets resolved to the `#[panic_handler]` function.
134-
extern "Rust" {
135-
#[lang = "panic_impl"]
136-
fn panic_impl(pi: &PanicInfo<'_>) -> !;
137-
}
138-
139-
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
140-
141-
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
142-
unsafe { panic_impl(&pi) }
164+
panic_str_nounwind("panic in a function that cannot unwind")
143165
}
144166

145167
/// This function is used instead of panic_fmt in const eval.

Diff for: src/tools/miri/tests/fail/function_calls/exported_symbol_bad_unwind2.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//@revisions: extern_block definition both
22
#![feature(rustc_attrs, c_unwind)]
33

4-
#[cfg_attr(any(definition, both), rustc_allocator_nounwind)]
4+
#[cfg_attr(any(definition, both), rustc_nounwind)]
55
#[no_mangle]
66
extern "C-unwind" fn nounwind() {
77
//[definition]~^ ERROR: abnormal termination: the program aborted execution
@@ -11,7 +11,7 @@ extern "C-unwind" fn nounwind() {
1111

1212
fn main() {
1313
extern "C-unwind" {
14-
#[cfg_attr(any(extern_block, both), rustc_allocator_nounwind)]
14+
#[cfg_attr(any(extern_block, both), rustc_nounwind)]
1515
fn nounwind();
1616
}
1717
unsafe { nounwind() }

Diff for: src/tools/rust-analyzer/crates/hir-def/src/builtin_attr.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
379379
// ==========================================================================
380380

381381
rustc_attr!(rustc_allocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
382-
rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
382+
rustc_attr!(rustc_nounwind, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
383383
gated!(
384384
alloc_error_handler, Normal, template!(Word), WarnFollowing,
385385
experimental!(alloc_error_handler)

0 commit comments

Comments
 (0)