Skip to content

Commit f381e77

Browse files
committed
Auto merge of #84662 - dtolnay:unwindsafe, r=Amanieu
Move UnwindSafe, RefUnwindSafe, AssertUnwindSafe to core They were previously only available in std::panic, not core::panic. - https://doc.rust-lang.org/1.51.0/std/panic/trait.UnwindSafe.html - https://doc.rust-lang.org/1.51.0/std/panic/trait.RefUnwindSafe.html - https://doc.rust-lang.org/1.51.0/std/panic/struct.AssertUnwindSafe.html Where this is relevant: trait objects! Inside a `#![no_std]` library it's otherwise impossible to have a struct holding a trait object, and at the same time can be used from downstream std crates in a way that doesn't interfere with catch_unwind. ```rust // common library #![no_std] pub struct Thing { pub(crate) x: &'static (dyn SomeTrait + Send + Sync), } pub(crate) trait SomeTrait {...} ``` ```rust // downstream application fn main() { let thing: library::Thing = ...; let _ = std::panic::catch_unwind(|| { let _ = thing; }); // does not work :( } ``` See https://github.com/dtolnay/colorous/blob/a4131708e2f05d2377964981896ff62dbc9b027b/src/gradient.rs#L7-L15 for a real life example of needing to work around this problem. In particular that workaround would not even be viable if implementors of the trait were provided externally by a caller, as the `feature = "std"` would become non-additive in that case. What happens without the UnwindSafe constraints: ```rust fn main() { let gradient = colorous::VIRIDIS; let _ = std::panic::catch_unwind(|| { let _ = gradient; }); } ``` ```console error[E0277]: the type `(dyn colorous::gradient::EvalGradient + Send + Sync + 'static)` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> src/main.rs:3:13 | 3 | let _ = std::panic::catch_unwind(|| { let _ = gradient; }); | ^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn colorous::gradient::EvalGradient + Send + Sync + 'static)` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | ::: .rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:430:40 | 430 | pub fn catch_unwind<F: FnOnce() -> R + UnwindSafe, R>(f: F) -> Result<R> { | ---------- required by this bound in `catch_unwind` | = help: within `Gradient`, the trait `RefUnwindSafe` is not implemented for `(dyn colorous::gradient::EvalGradient + Send + Sync + 'static)` = note: required because it appears within the type `&'static (dyn colorous::gradient::EvalGradient + Send + Sync + 'static)` = note: required because it appears within the type `Gradient` = note: required because of the requirements on the impl of `UnwindSafe` for `&Gradient` = note: required because it appears within the type `[closure@src/main.rs:3:38: 3:62]` ```
2 parents a0a6bab + d1586fc commit f381e77

File tree

7 files changed

+662
-638
lines changed

7 files changed

+662
-638
lines changed

library/alloc/src/rc.rs

+4
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ use core::marker::{self, PhantomData, Unpin, Unsize};
262262
use core::mem::size_of_val;
263263
use core::mem::{self, align_of_val_raw, forget};
264264
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
265+
use core::panic::{RefUnwindSafe, UnwindSafe};
265266
#[cfg(not(no_global_oom_handling))]
266267
use core::pin::Pin;
267268
use core::ptr::{self, NonNull};
@@ -314,6 +315,9 @@ impl<T: ?Sized> !marker::Send for Rc<T> {}
314315
#[stable(feature = "rust1", since = "1.0.0")]
315316
impl<T: ?Sized> !marker::Sync for Rc<T> {}
316317

318+
#[stable(feature = "catch_unwind", since = "1.9.0")]
319+
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Rc<T> {}
320+
317321
#[unstable(feature = "coerce_unsized", issue = "27732")]
318322
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
319323

library/alloc/src/sync.rs

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use core::marker::{PhantomData, Unpin, Unsize};
1919
use core::mem::size_of_val;
2020
use core::mem::{self, align_of_val_raw};
2121
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
22+
use core::panic::{RefUnwindSafe, UnwindSafe};
2223
use core::pin::Pin;
2324
use core::ptr::{self, NonNull};
2425
#[cfg(not(no_global_oom_handling))]
@@ -240,6 +241,9 @@ unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> {}
240241
#[stable(feature = "rust1", since = "1.0.0")]
241242
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
242243

244+
#[stable(feature = "catch_unwind", since = "1.9.0")]
245+
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Arc<T> {}
246+
243247
#[unstable(feature = "coerce_unsized", issue = "27732")]
244248
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
245249

library/core/src/panic.rs

+11-329
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,18 @@
22
33
#![stable(feature = "core_panic_info", since = "1.41.0")]
44

5+
mod location;
6+
mod panic_info;
7+
mod unwind_safe;
8+
59
use crate::any::Any;
6-
use crate::fmt;
10+
11+
#[stable(feature = "panic_hooks", since = "1.10.0")]
12+
pub use self::location::Location;
13+
#[stable(feature = "panic_hooks", since = "1.10.0")]
14+
pub use self::panic_info::PanicInfo;
15+
#[stable(feature = "catch_unwind", since = "1.9.0")]
16+
pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
717

818
#[doc(hidden)]
919
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
@@ -39,334 +49,6 @@ pub macro panic_2021 {
3949
),
4050
}
4151

42-
/// A struct providing information about a panic.
43-
///
44-
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
45-
/// function.
46-
///
47-
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
48-
///
49-
/// # Examples
50-
///
51-
/// ```should_panic
52-
/// use std::panic;
53-
///
54-
/// panic::set_hook(Box::new(|panic_info| {
55-
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
56-
/// println!("panic occurred: {:?}", s);
57-
/// } else {
58-
/// println!("panic occurred");
59-
/// }
60-
/// }));
61-
///
62-
/// panic!("Normal panic");
63-
/// ```
64-
#[lang = "panic_info"]
65-
#[stable(feature = "panic_hooks", since = "1.10.0")]
66-
#[derive(Debug)]
67-
pub struct PanicInfo<'a> {
68-
payload: &'a (dyn Any + Send),
69-
message: Option<&'a fmt::Arguments<'a>>,
70-
location: &'a Location<'a>,
71-
}
72-
73-
impl<'a> PanicInfo<'a> {
74-
#[unstable(
75-
feature = "panic_internals",
76-
reason = "internal details of the implementation of the `panic!` and related macros",
77-
issue = "none"
78-
)]
79-
#[doc(hidden)]
80-
#[inline]
81-
pub fn internal_constructor(
82-
message: Option<&'a fmt::Arguments<'a>>,
83-
location: &'a Location<'a>,
84-
) -> Self {
85-
struct NoPayload;
86-
PanicInfo { location, message, payload: &NoPayload }
87-
}
88-
89-
#[unstable(
90-
feature = "panic_internals",
91-
reason = "internal details of the implementation of the `panic!` and related macros",
92-
issue = "none"
93-
)]
94-
#[doc(hidden)]
95-
#[inline]
96-
pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
97-
self.payload = info;
98-
}
99-
100-
/// Returns the payload associated with the panic.
101-
///
102-
/// This will commonly, but not always, be a `&'static str` or [`String`].
103-
///
104-
/// [`String`]: ../../std/string/struct.String.html
105-
///
106-
/// # Examples
107-
///
108-
/// ```should_panic
109-
/// use std::panic;
110-
///
111-
/// panic::set_hook(Box::new(|panic_info| {
112-
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
113-
/// println!("panic occurred: {:?}", s);
114-
/// } else {
115-
/// println!("panic occurred");
116-
/// }
117-
/// }));
118-
///
119-
/// panic!("Normal panic");
120-
/// ```
121-
#[stable(feature = "panic_hooks", since = "1.10.0")]
122-
pub fn payload(&self) -> &(dyn Any + Send) {
123-
self.payload
124-
}
125-
126-
/// If the `panic!` macro from the `core` crate (not from `std`)
127-
/// was used with a formatting string and some additional arguments,
128-
/// returns that message ready to be used for example with [`fmt::write`]
129-
#[unstable(feature = "panic_info_message", issue = "66745")]
130-
pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
131-
self.message
132-
}
133-
134-
/// Returns information about the location from which the panic originated,
135-
/// if available.
136-
///
137-
/// This method will currently always return [`Some`], but this may change
138-
/// in future versions.
139-
///
140-
/// # Examples
141-
///
142-
/// ```should_panic
143-
/// use std::panic;
144-
///
145-
/// panic::set_hook(Box::new(|panic_info| {
146-
/// if let Some(location) = panic_info.location() {
147-
/// println!("panic occurred in file '{}' at line {}",
148-
/// location.file(),
149-
/// location.line(),
150-
/// );
151-
/// } else {
152-
/// println!("panic occurred but can't get location information...");
153-
/// }
154-
/// }));
155-
///
156-
/// panic!("Normal panic");
157-
/// ```
158-
#[stable(feature = "panic_hooks", since = "1.10.0")]
159-
pub fn location(&self) -> Option<&Location<'_>> {
160-
// NOTE: If this is changed to sometimes return None,
161-
// deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
162-
Some(&self.location)
163-
}
164-
}
165-
166-
#[stable(feature = "panic_hook_display", since = "1.26.0")]
167-
impl fmt::Display for PanicInfo<'_> {
168-
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
169-
formatter.write_str("panicked at ")?;
170-
if let Some(message) = self.message {
171-
write!(formatter, "'{}', ", message)?
172-
} else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
173-
write!(formatter, "'{}', ", payload)?
174-
}
175-
// NOTE: we cannot use downcast_ref::<String>() here
176-
// since String is not available in libcore!
177-
// The payload is a String when `std::panic!` is called with multiple arguments,
178-
// but in that case the message is also available.
179-
180-
self.location.fmt(formatter)
181-
}
182-
}
183-
184-
/// A struct containing information about the location of a panic.
185-
///
186-
/// This structure is created by [`PanicInfo::location()`].
187-
///
188-
/// # Examples
189-
///
190-
/// ```should_panic
191-
/// use std::panic;
192-
///
193-
/// panic::set_hook(Box::new(|panic_info| {
194-
/// if let Some(location) = panic_info.location() {
195-
/// println!("panic occurred in file '{}' at line {}", location.file(), location.line());
196-
/// } else {
197-
/// println!("panic occurred but can't get location information...");
198-
/// }
199-
/// }));
200-
///
201-
/// panic!("Normal panic");
202-
/// ```
203-
///
204-
/// # Comparisons
205-
///
206-
/// Comparisons for equality and ordering are made in file, line, then column priority.
207-
/// Files are compared as strings, not `Path`, which could be unexpected.
208-
/// See [`Location::file`]'s documentation for more discussion.
209-
#[lang = "panic_location"]
210-
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
211-
#[stable(feature = "panic_hooks", since = "1.10.0")]
212-
pub struct Location<'a> {
213-
file: &'a str,
214-
line: u32,
215-
col: u32,
216-
}
217-
218-
impl<'a> Location<'a> {
219-
/// Returns the source location of the caller of this function. If that function's caller is
220-
/// annotated then its call location will be returned, and so on up the stack to the first call
221-
/// within a non-tracked function body.
222-
///
223-
/// # Examples
224-
///
225-
/// ```
226-
/// use std::panic::Location;
227-
///
228-
/// /// Returns the [`Location`] at which it is called.
229-
/// #[track_caller]
230-
/// fn get_caller_location() -> &'static Location<'static> {
231-
/// Location::caller()
232-
/// }
233-
///
234-
/// /// Returns a [`Location`] from within this function's definition.
235-
/// fn get_just_one_location() -> &'static Location<'static> {
236-
/// get_caller_location()
237-
/// }
238-
///
239-
/// let fixed_location = get_just_one_location();
240-
/// assert_eq!(fixed_location.file(), file!());
241-
/// assert_eq!(fixed_location.line(), 14);
242-
/// assert_eq!(fixed_location.column(), 5);
243-
///
244-
/// // running the same untracked function in a different location gives us the same result
245-
/// let second_fixed_location = get_just_one_location();
246-
/// assert_eq!(fixed_location.file(), second_fixed_location.file());
247-
/// assert_eq!(fixed_location.line(), second_fixed_location.line());
248-
/// assert_eq!(fixed_location.column(), second_fixed_location.column());
249-
///
250-
/// let this_location = get_caller_location();
251-
/// assert_eq!(this_location.file(), file!());
252-
/// assert_eq!(this_location.line(), 28);
253-
/// assert_eq!(this_location.column(), 21);
254-
///
255-
/// // running the tracked function in a different location produces a different value
256-
/// let another_location = get_caller_location();
257-
/// assert_eq!(this_location.file(), another_location.file());
258-
/// assert_ne!(this_location.line(), another_location.line());
259-
/// assert_ne!(this_location.column(), another_location.column());
260-
/// ```
261-
#[stable(feature = "track_caller", since = "1.46.0")]
262-
#[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
263-
#[track_caller]
264-
pub const fn caller() -> &'static Location<'static> {
265-
crate::intrinsics::caller_location()
266-
}
267-
}
268-
269-
impl<'a> Location<'a> {
270-
#![unstable(
271-
feature = "panic_internals",
272-
reason = "internal details of the implementation of the `panic!` and related macros",
273-
issue = "none"
274-
)]
275-
#[doc(hidden)]
276-
pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
277-
Location { file, line, col }
278-
}
279-
280-
/// Returns the name of the source file from which the panic originated.
281-
///
282-
/// # `&str`, not `&Path`
283-
///
284-
/// The returned name refers to a source path on the compiling system, but it isn't valid to
285-
/// represent this directly as a `&Path`. The compiled code may run on a different system with
286-
/// a different `Path` implementation than the system providing the contents and this library
287-
/// does not currently have a different "host path" type.
288-
///
289-
/// The most surprising behavior occurs when "the same" file is reachable via multiple paths in
290-
/// the module system (usually using the `#[path = "..."]` attribute or similar), which can
291-
/// cause what appears to be identical code to return differing values from this function.
292-
///
293-
/// # Cross-compilation
294-
///
295-
/// This value is not suitable for passing to `Path::new` or similar constructors when the host
296-
/// platform and target platform differ.
297-
///
298-
/// # Examples
299-
///
300-
/// ```should_panic
301-
/// use std::panic;
302-
///
303-
/// panic::set_hook(Box::new(|panic_info| {
304-
/// if let Some(location) = panic_info.location() {
305-
/// println!("panic occurred in file '{}'", location.file());
306-
/// } else {
307-
/// println!("panic occurred but can't get location information...");
308-
/// }
309-
/// }));
310-
///
311-
/// panic!("Normal panic");
312-
/// ```
313-
#[stable(feature = "panic_hooks", since = "1.10.0")]
314-
pub fn file(&self) -> &str {
315-
self.file
316-
}
317-
318-
/// Returns the line number from which the panic originated.
319-
///
320-
/// # Examples
321-
///
322-
/// ```should_panic
323-
/// use std::panic;
324-
///
325-
/// panic::set_hook(Box::new(|panic_info| {
326-
/// if let Some(location) = panic_info.location() {
327-
/// println!("panic occurred at line {}", location.line());
328-
/// } else {
329-
/// println!("panic occurred but can't get location information...");
330-
/// }
331-
/// }));
332-
///
333-
/// panic!("Normal panic");
334-
/// ```
335-
#[stable(feature = "panic_hooks", since = "1.10.0")]
336-
pub fn line(&self) -> u32 {
337-
self.line
338-
}
339-
340-
/// Returns the column from which the panic originated.
341-
///
342-
/// # Examples
343-
///
344-
/// ```should_panic
345-
/// use std::panic;
346-
///
347-
/// panic::set_hook(Box::new(|panic_info| {
348-
/// if let Some(location) = panic_info.location() {
349-
/// println!("panic occurred at column {}", location.column());
350-
/// } else {
351-
/// println!("panic occurred but can't get location information...");
352-
/// }
353-
/// }));
354-
///
355-
/// panic!("Normal panic");
356-
/// ```
357-
#[stable(feature = "panic_col", since = "1.25.0")]
358-
pub fn column(&self) -> u32 {
359-
self.col
360-
}
361-
}
362-
363-
#[stable(feature = "panic_hook_display", since = "1.26.0")]
364-
impl fmt::Display for Location<'_> {
365-
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
366-
write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
367-
}
368-
}
369-
37052
/// An internal trait used by libstd to pass data from libstd to `panic_unwind`
37153
/// and other panic runtimes. Not intended to be stabilized any time soon, do
37254
/// not use.

0 commit comments

Comments
 (0)