1use 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")]
33pub struct Location<'a> {
34 file: &'a str,
35 line: u32,
36 col: u32,
37}
38
39impl<'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)]
188impl<'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")]
196impl 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}
201