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