|
| 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