]> git.lizzy.rs Git - rust.git/blob - library/core/src/panic/location.rs
Rollup merge of #106897 - estebank:issue-99430, r=davidtwco
[rust.git] / library / core / src / panic / location.rs
1 use crate::fmt;
2
3 /// A struct containing information about the location of a panic.
4 ///
5 /// This structure is created by [`PanicInfo::location()`].
6 ///
7 /// [`PanicInfo::location()`]: crate::panic::PanicInfo::location
8 ///
9 /// # Examples
10 ///
11 /// ```should_panic
12 /// use std::panic;
13 ///
14 /// panic::set_hook(Box::new(|panic_info| {
15 ///     if let Some(location) = panic_info.location() {
16 ///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
17 ///     } else {
18 ///         println!("panic occurred but can't get location information...");
19 ///     }
20 /// }));
21 ///
22 /// panic!("Normal panic");
23 /// ```
24 ///
25 /// # Comparisons
26 ///
27 /// Comparisons for equality and ordering are made in file, line, then column priority.
28 /// Files are compared as strings, not `Path`, which could be unexpected.
29 /// See [`Location::file`]'s documentation for more discussion.
30 #[lang = "panic_location"]
31 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
32 #[stable(feature = "panic_hooks", since = "1.10.0")]
33 pub struct Location<'a> {
34     file: &'a str,
35     line: u32,
36     col: u32,
37 }
38
39 impl<'a> Location<'a> {
40     /// Returns the source location of the caller of this function. If that function's caller is
41     /// annotated then its call location will be returned, and so on up the stack to the first call
42     /// within a non-tracked function body.
43     ///
44     /// # Examples
45     ///
46     /// ```
47     /// use std::panic::Location;
48     ///
49     /// /// Returns the [`Location`] at which it is called.
50     /// #[track_caller]
51     /// fn get_caller_location() -> &'static Location<'static> {
52     ///     Location::caller()
53     /// }
54     ///
55     /// /// Returns a [`Location`] from within this function's definition.
56     /// fn get_just_one_location() -> &'static Location<'static> {
57     ///     get_caller_location()
58     /// }
59     ///
60     /// let fixed_location = get_just_one_location();
61     /// assert_eq!(fixed_location.file(), file!());
62     /// assert_eq!(fixed_location.line(), 14);
63     /// assert_eq!(fixed_location.column(), 5);
64     ///
65     /// // running the same untracked function in a different location gives us the same result
66     /// let second_fixed_location = get_just_one_location();
67     /// assert_eq!(fixed_location.file(), second_fixed_location.file());
68     /// assert_eq!(fixed_location.line(), second_fixed_location.line());
69     /// assert_eq!(fixed_location.column(), second_fixed_location.column());
70     ///
71     /// let this_location = get_caller_location();
72     /// assert_eq!(this_location.file(), file!());
73     /// assert_eq!(this_location.line(), 28);
74     /// assert_eq!(this_location.column(), 21);
75     ///
76     /// // running the tracked function in a different location produces a different value
77     /// let another_location = get_caller_location();
78     /// assert_eq!(this_location.file(), another_location.file());
79     /// assert_ne!(this_location.line(), another_location.line());
80     /// assert_ne!(this_location.column(), another_location.column());
81     /// ```
82     #[must_use]
83     #[stable(feature = "track_caller", since = "1.46.0")]
84     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
85     #[track_caller]
86     #[inline]
87     pub const fn caller() -> &'static Location<'static> {
88         crate::intrinsics::caller_location()
89     }
90
91     /// Returns the name of the source file from which the panic originated.
92     ///
93     /// # `&str`, not `&Path`
94     ///
95     /// The returned name refers to a source path on the compiling system, but it isn't valid to
96     /// represent this directly as a `&Path`. The compiled code may run on a different system with
97     /// a different `Path` implementation than the system providing the contents and this library
98     /// does not currently have a different "host path" type.
99     ///
100     /// The most surprising behavior occurs when "the same" file is reachable via multiple paths in
101     /// the module system (usually using the `#[path = "..."]` attribute or similar), which can
102     /// cause what appears to be identical code to return differing values from this function.
103     ///
104     /// # Cross-compilation
105     ///
106     /// This value is not suitable for passing to `Path::new` or similar constructors when the host
107     /// platform and target platform differ.
108     ///
109     /// # Examples
110     ///
111     /// ```should_panic
112     /// use std::panic;
113     ///
114     /// panic::set_hook(Box::new(|panic_info| {
115     ///     if let Some(location) = panic_info.location() {
116     ///         println!("panic occurred in file '{}'", location.file());
117     ///     } else {
118     ///         println!("panic occurred but can't get location information...");
119     ///     }
120     /// }));
121     ///
122     /// panic!("Normal panic");
123     /// ```
124     #[must_use]
125     #[stable(feature = "panic_hooks", since = "1.10.0")]
126     #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")]
127     #[inline]
128     pub const fn file(&self) -> &str {
129         self.file
130     }
131
132     /// Returns the line number from which the panic originated.
133     ///
134     /// # Examples
135     ///
136     /// ```should_panic
137     /// use std::panic;
138     ///
139     /// panic::set_hook(Box::new(|panic_info| {
140     ///     if let Some(location) = panic_info.location() {
141     ///         println!("panic occurred at line {}", location.line());
142     ///     } else {
143     ///         println!("panic occurred but can't get location information...");
144     ///     }
145     /// }));
146     ///
147     /// panic!("Normal panic");
148     /// ```
149     #[must_use]
150     #[stable(feature = "panic_hooks", since = "1.10.0")]
151     #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")]
152     #[inline]
153     pub const fn line(&self) -> u32 {
154         self.line
155     }
156
157     /// Returns the column from which the panic originated.
158     ///
159     /// # Examples
160     ///
161     /// ```should_panic
162     /// use std::panic;
163     ///
164     /// panic::set_hook(Box::new(|panic_info| {
165     ///     if let Some(location) = panic_info.location() {
166     ///         println!("panic occurred at column {}", location.column());
167     ///     } else {
168     ///         println!("panic occurred but can't get location information...");
169     ///     }
170     /// }));
171     ///
172     /// panic!("Normal panic");
173     /// ```
174     #[must_use]
175     #[stable(feature = "panic_col", since = "1.25.0")]
176     #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")]
177     #[inline]
178     pub const fn column(&self) -> u32 {
179         self.col
180     }
181 }
182
183 #[unstable(
184     feature = "panic_internals",
185     reason = "internal details of the implementation of the `panic!` and related macros",
186     issue = "none"
187 )]
188 impl<'a> Location<'a> {
189     #[doc(hidden)]
190     pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
191         Location { file, line, col }
192     }
193 }
194
195 #[stable(feature = "panic_hook_display", since = "1.26.0")]
196 impl fmt::Display for Location<'_> {
197     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
198         write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
199     }
200 }