about summary refs log tree commit diff
path: root/src/libcore/panic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcore/panic.rs')
-rw-r--r--src/libcore/panic.rs251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs
new file mode 100644
index 00000000000..4e72eaa57c7
--- /dev/null
+++ b/src/libcore/panic.rs
@@ -0,0 +1,251 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Panic support in the standard library.
+
+#![unstable(feature = "core_panic_info",
+            reason = "newly available in libcore",
+            issue = "44489")]
+
+use any::Any;
+use fmt;
+
+/// A struct providing information about a panic.
+///
+/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
+/// function.
+///
+/// [`set_hook`]: ../../std/panic/fn.set_hook.html
+///
+/// # Examples
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// panic::set_hook(Box::new(|panic_info| {
+///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
+/// }));
+///
+/// panic!("Normal panic");
+/// ```
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+#[derive(Debug)]
+pub struct PanicInfo<'a> {
+    payload: &'a (Any + Send),
+    message: Option<&'a fmt::Arguments<'a>>,
+    location: Location<'a>,
+}
+
+impl<'a> PanicInfo<'a> {
+    #![unstable(feature = "panic_internals",
+                reason = "internal details of the implementation of the `panic!` \
+                          and related macros",
+                issue = "0")]
+    #[doc(hidden)]
+    pub fn internal_constructor(payload: &'a (Any + Send),
+                                message: Option<&'a fmt::Arguments<'a>>,
+                                location: Location<'a>)
+                                -> Self {
+        PanicInfo { payload, location, message }
+    }
+
+    /// Returns the payload associated with the panic.
+    ///
+    /// This will commonly, but not always, be a `&'static str` or [`String`].
+    ///
+    /// [`String`]: ../../std/string/struct.String.html
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// use std::panic;
+    ///
+    /// panic::set_hook(Box::new(|panic_info| {
+    ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
+    /// }));
+    ///
+    /// panic!("Normal panic");
+    /// ```
+    #[stable(feature = "panic_hooks", since = "1.10.0")]
+    pub fn payload(&self) -> &(Any + Send) {
+        self.payload
+    }
+
+    /// If the `panic!` macro from the `core` crate (not from `std`)
+    /// was used with a formatting string and some additional arguments,
+    /// returns that message ready to be used for example with [`fmt::write`]
+    ///
+    /// [`fmt::write`]: ../fmt/fn.write.html
+    #[unstable(feature = "panic_info_message", issue = "44489")]
+    pub fn message(&self) -> Option<&fmt::Arguments> {
+        self.message
+    }
+
+    /// Returns information about the location from which the panic originated,
+    /// if available.
+    ///
+    /// This method will currently always return [`Some`], but this may change
+    /// in future versions.
+    ///
+    /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// use std::panic;
+    ///
+    /// panic::set_hook(Box::new(|panic_info| {
+    ///     if let Some(location) = panic_info.location() {
+    ///         println!("panic occurred in file '{}' at line {}", location.file(),
+    ///             location.line());
+    ///     } else {
+    ///         println!("panic occurred but can't get location information...");
+    ///     }
+    /// }));
+    ///
+    /// panic!("Normal panic");
+    /// ```
+    #[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.
+        Some(&self.location)
+    }
+}
+
+impl<'a> fmt::Display for PanicInfo<'a> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        formatter.write_str("panicked at ")?;
+        if let Some(message) = self.message {
+            write!(formatter, "'{}', ", message)?
+        } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
+            write!(formatter, "'{}', ", payload)?
+        }
+        // NOTE: we cannot use downcast_ref::<String>() here
+        // since String is not available in libcore!
+        // The payload is a String when `std::panic!` is called with multiple arguments,
+        // but in that case the message is also available.
+
+        self.location.fmt(formatter)
+    }
+}
+
+/// A struct containing information about the location of a panic.
+///
+/// This structure is created by the [`location`] method of [`PanicInfo`].
+///
+/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
+/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
+///
+/// # Examples
+///
+/// ```should_panic
+/// use std::panic;
+///
+/// panic::set_hook(Box::new(|panic_info| {
+///     if let Some(location) = panic_info.location() {
+///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
+///     } else {
+///         println!("panic occurred but can't get location information...");
+///     }
+/// }));
+///
+/// panic!("Normal panic");
+/// ```
+#[derive(Debug)]
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+pub struct Location<'a> {
+    file: &'a str,
+    line: u32,
+    col: u32,
+}
+
+impl<'a> Location<'a> {
+    #![unstable(feature = "panic_internals",
+                reason = "internal details of the implementation of the `panic!` \
+                          and related macros",
+                issue = "0")]
+    #[doc(hidden)]
+    pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
+        Location { file, line, col }
+    }
+
+    /// Returns the name of the source file from which the panic originated.
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// use std::panic;
+    ///
+    /// panic::set_hook(Box::new(|panic_info| {
+    ///     if let Some(location) = panic_info.location() {
+    ///         println!("panic occurred in file '{}'", location.file());
+    ///     } else {
+    ///         println!("panic occurred but can't get location information...");
+    ///     }
+    /// }));
+    ///
+    /// panic!("Normal panic");
+    /// ```
+    #[stable(feature = "panic_hooks", since = "1.10.0")]
+    pub fn file(&self) -> &str {
+        self.file
+    }
+
+    /// Returns the line number from which the panic originated.
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// use std::panic;
+    ///
+    /// panic::set_hook(Box::new(|panic_info| {
+    ///     if let Some(location) = panic_info.location() {
+    ///         println!("panic occurred at line {}", location.line());
+    ///     } else {
+    ///         println!("panic occurred but can't get location information...");
+    ///     }
+    /// }));
+    ///
+    /// panic!("Normal panic");
+    /// ```
+    #[stable(feature = "panic_hooks", since = "1.10.0")]
+    pub fn line(&self) -> u32 {
+        self.line
+    }
+
+    /// Returns the column from which the panic originated.
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// use std::panic;
+    ///
+    /// panic::set_hook(Box::new(|panic_info| {
+    ///     if let Some(location) = panic_info.location() {
+    ///         println!("panic occurred at column {}", location.column());
+    ///     } else {
+    ///         println!("panic occurred but can't get location information...");
+    ///     }
+    /// }));
+    ///
+    /// panic!("Normal panic");
+    /// ```
+    #[stable(feature = "panic_col", since = "1.25.0")]
+    pub fn column(&self) -> u32 {
+        self.col
+    }
+}
+
+impl<'a> fmt::Display for Location<'a> {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+        write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
+    }
+}