|
| 1 | +use crate::ffi::CStr; |
1 | 2 | use crate::fmt;
|
2 | 3 |
|
3 | 4 | /// A struct containing information about the location of a panic.
|
@@ -32,7 +33,12 @@ use crate::fmt;
|
32 | 33 | #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
33 | 34 | #[stable(feature = "panic_hooks", since = "1.10.0")]
|
34 | 35 | pub struct Location<'a> {
|
35 |
| - file: &'a str, |
| 36 | + // Note: this filename will have exactly one nul byte at its end, but otherwise |
| 37 | + // it must never contain interior nul bytes. This is relied on for the conversion |
| 38 | + // to `CStr` below. |
| 39 | + // |
| 40 | + // The prefix of the string without the trailing nul byte will be a regular UTF8 `str`. |
| 41 | + file_bytes_with_nul: &'a [u8], |
36 | 42 | line: u32,
|
37 | 43 | col: u32,
|
38 | 44 | }
|
@@ -125,9 +131,24 @@ impl<'a> Location<'a> {
|
125 | 131 | #[must_use]
|
126 | 132 | #[stable(feature = "panic_hooks", since = "1.10.0")]
|
127 | 133 | #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")]
|
128 |
| - #[inline] |
129 | 134 | pub const fn file(&self) -> &str {
|
130 |
| - self.file |
| 135 | + let str_len = self.file_bytes_with_nul.len() - 1; |
| 136 | + // SAFETY: `file_bytes_with_nul` without the trailing nul byte is guaranteed to be |
| 137 | + // valid UTF8. |
| 138 | + unsafe { crate::str::from_raw_parts(self.file_bytes_with_nul.as_ptr(), str_len) } |
| 139 | + } |
| 140 | + |
| 141 | + /// Returns the name of the source file as a nul-terminated `CStr`. |
| 142 | + /// |
| 143 | + /// This is useful for interop with APIs that expect C/C++ `__FILE__` or |
| 144 | + /// `std::source_location::file_name`, both of which return a nul-terminated `const char*`. |
| 145 | + #[must_use] |
| 146 | + #[unstable(feature = "file_with_nul", issue = "141727")] |
| 147 | + #[inline] |
| 148 | + pub const fn file_with_nul(&self) -> &CStr { |
| 149 | + // SAFETY: `file_bytes_with_nul` is guaranteed to have a trailing nul byte and no |
| 150 | + // interior nul bytes. |
| 151 | + unsafe { CStr::from_bytes_with_nul_unchecked(self.file_bytes_with_nul) } |
131 | 152 | }
|
132 | 153 |
|
133 | 154 | /// Returns the line number from which the panic originated.
|
@@ -181,22 +202,10 @@ impl<'a> Location<'a> {
|
181 | 202 | }
|
182 | 203 | }
|
183 | 204 |
|
184 |
| -#[unstable( |
185 |
| - feature = "panic_internals", |
186 |
| - reason = "internal details of the implementation of the `panic!` and related macros", |
187 |
| - issue = "none" |
188 |
| -)] |
189 |
| -impl<'a> Location<'a> { |
190 |
| - #[doc(hidden)] |
191 |
| - pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self { |
192 |
| - Location { file, line, col } |
193 |
| - } |
194 |
| -} |
195 |
| - |
196 | 205 | #[stable(feature = "panic_hook_display", since = "1.26.0")]
|
197 | 206 | impl fmt::Display for Location<'_> {
|
198 | 207 | #[inline]
|
199 | 208 | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
200 |
| - write!(formatter, "{}:{}:{}", self.file, self.line, self.col) |
| 209 | + write!(formatter, "{}:{}:{}", self.file(), self.line, self.col) |
201 | 210 | }
|
202 | 211 | }
|
0 commit comments