Skip to content

Commit 90eb610

Browse files
authored
Rollup merge of #91737 - Manishearth:panic-immediate-stdlib, r=joshtriplett
Make certain panicky stdlib functions behave better under panic_immediate_abort The stdlib has a `panic_immediate_abort` feature that turns panics into immediate aborts, without any formatting/display logic. This feature was [introduced](#55011) primarily for codesize-constrained situations. Unfortunately, this win doesn't quite propagate to `Result::expect()` and `Result::unwrap()`, while the formatting machinery is reduced, `expect()` and `unwrap()` both call `unwrap_failed("msg", &err)` which has a signature of `fn unwrap_failed(msg: &str, error: &dyn fmt::Debug)` and is `#[inline(never)]`. This means that `unwrap_failed` will unconditionally construct a `dyn Debug` trait object even though the object is never used in the function. Constructing a trait object (even if you never call a method on it!) forces rust to include the vtable and any dependencies. This means that in `panic_immediate_abort` mode, calling expect/unwrap on a Result will pull in a whole bunch of formatting code for the error type even if it's completely unused. This PR swaps out the function with one that won't require a trait object such that it won't force the inclusion of vtables in the code. It also gates off `#[inline(never)]` in a bunch of other places where allowing the inlining of an abort may be useful (this kind of thing is already done elsewhere in the stdlib). I don't know how to write a test for this; we don't really seem to have any tests for `panic_immediate_abort` anyway so perhaps it's fine as is.
2 parents 443ed7c + 917dafc commit 90eb610

File tree

3 files changed

+25
-6
lines changed

3 files changed

+25
-6
lines changed

library/core/src/option.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1671,7 +1671,8 @@ impl<T, E> Option<Result<T, E>> {
16711671
}
16721672

16731673
// This is a separate function to reduce the code size of .expect() itself.
1674-
#[inline(never)]
1674+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
1675+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
16751676
#[cold]
16761677
#[track_caller]
16771678
const fn expect_failed(msg: &str) -> ! {

library/core/src/result.rs

+13
Original file line numberDiff line numberDiff line change
@@ -1653,13 +1653,26 @@ impl<T> Result<T, T> {
16531653
}
16541654

16551655
// This is a separate function to reduce the code size of the methods
1656+
#[cfg(not(feature = "panic_immediate_abort"))]
16561657
#[inline(never)]
16571658
#[cold]
16581659
#[track_caller]
16591660
fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! {
16601661
panic!("{}: {:?}", msg, error)
16611662
}
16621663

1664+
// This is a separate function to avoid constructing a `dyn Debug`
1665+
// that gets immediately thrown away, since vtables don't get cleaned up
1666+
// by dead code elimination if a trait object is constructed even if it goes
1667+
// unused
1668+
#[cfg(feature = "panic_immediate_abort")]
1669+
#[inline]
1670+
#[cold]
1671+
#[track_caller]
1672+
fn unwrap_failed<T>(_msg: &str, _error: &T) -> ! {
1673+
panic!()
1674+
}
1675+
16631676
/////////////////////////////////////////////////////////////////////////////
16641677
// Trait implementations
16651678
/////////////////////////////////////////////////////////////////////////////

library/core/src/slice/index.rs

+10-5
Original file line numberDiff line numberDiff line change
@@ -27,35 +27,40 @@ where
2727
}
2828
}
2929

30-
#[inline(never)]
30+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
31+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
3132
#[cold]
3233
#[track_caller]
3334
fn slice_start_index_len_fail(index: usize, len: usize) -> ! {
3435
panic!("range start index {} out of range for slice of length {}", index, len);
3536
}
3637

37-
#[inline(never)]
38+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
39+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
3840
#[cold]
3941
#[track_caller]
4042
fn slice_end_index_len_fail(index: usize, len: usize) -> ! {
4143
panic!("range end index {} out of range for slice of length {}", index, len);
4244
}
4345

44-
#[inline(never)]
46+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
47+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
4548
#[cold]
4649
#[track_caller]
4750
fn slice_index_order_fail(index: usize, end: usize) -> ! {
4851
panic!("slice index starts at {} but ends at {}", index, end);
4952
}
5053

51-
#[inline(never)]
54+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
55+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
5256
#[cold]
5357
#[track_caller]
5458
fn slice_start_index_overflow_fail() -> ! {
5559
panic!("attempted to index slice from after maximum usize");
5660
}
5761

58-
#[inline(never)]
62+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
63+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
5964
#[cold]
6065
#[track_caller]
6166
fn slice_end_index_overflow_fail() -> ! {

0 commit comments

Comments
 (0)