Skip to content

Commit 59a117d

Browse files
authored
Rollup merge of rust-lang#135080 - Enselic:debug-ptr-metadata, r=thomcc
core: Make `Debug` impl of raw pointers print metadata if present Make Rust pointers appear less magic by including metadata information in their `Debug` output. This does not break Rust stability guarantees because `Debug` impl are explicitly exempted from stability: https://doc.rust-lang.org/std/fmt/trait.Debug.html#stability > ## Stability > > Derived `Debug` formats are not stable, and so may change with future Rust versions. Additionally, `Debug` implementations of types provided by the standard library (`std`, `core`, `alloc`, etc.) are not stable, and may also change with future Rust versions. Note that a regression test is added as a separate commit to make it clear what impact the last commit has on the output. Closes rust-lang#128684 because the output of that code now becomes: ``` thread 'main' panicked at src/main.rs:5:5: assertion `left == right` failed left: Pointer { addr: 0x7ffd45c6fc6b, metadata: 5 } right: Pointer { addr: 0x7ffd45c6fc6b, metadata: 3 } note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ```
2 parents c5f575e + 72b2e53 commit 59a117d

File tree

6 files changed

+86
-3
lines changed

6 files changed

+86
-3
lines changed

Cargo.lock

+26
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/src/fmt/mod.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -2771,7 +2771,14 @@ impl Display for char {
27712771
#[stable(feature = "rust1", since = "1.0.0")]
27722772
impl<T: ?Sized> Pointer for *const T {
27732773
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
2774-
pointer_fmt_inner(self.expose_provenance(), f)
2774+
if <<T as core::ptr::Pointee>::Metadata as core::unit::IsUnit>::is_unit() {
2775+
pointer_fmt_inner(self.expose_provenance(), f)
2776+
} else {
2777+
f.debug_struct("Pointer")
2778+
.field_with("addr", |f| pointer_fmt_inner(self.expose_provenance(), f))
2779+
.field("metadata", &core::ptr::metadata(*self))
2780+
.finish()
2781+
}
27752782
}
27762783
}
27772784

core/src/ptr/metadata.rs

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ pub trait Pointee {
6161
// NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
6262
// in `library/core/src/ptr/metadata.rs`
6363
// in sync with those here:
64+
// NOTE: The metadata of `dyn Trait + 'a` is `DynMetadata<dyn Trait + 'a>`
65+
// so a `'static` bound must not be added.
6466
type Metadata: fmt::Debug + Copy + Send + Sync + Ord + Hash + Unpin + Freeze;
6567
}
6668

core/src/unit.rs

+16
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,19 @@ impl FromIterator<()> for () {
1717
iter.into_iter().for_each(|()| {})
1818
}
1919
}
20+
21+
pub(crate) trait IsUnit {
22+
fn is_unit() -> bool;
23+
}
24+
25+
impl<T: ?Sized> IsUnit for T {
26+
default fn is_unit() -> bool {
27+
false
28+
}
29+
}
30+
31+
impl IsUnit for () {
32+
fn is_unit() -> bool {
33+
true
34+
}
35+
}

coretests/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ test = true
2525
[dev-dependencies]
2626
rand = { version = "0.9.0", default-features = false }
2727
rand_xorshift = { version = "0.4.0", default-features = false }
28+
regex = { version = "1.11.1", default-features = false }

coretests/tests/fmt/mod.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,39 @@ fn test_format_flags() {
1515
fn test_pointer_formats_data_pointer() {
1616
let b: &[u8] = b"";
1717
let s: &str = "";
18-
assert_eq!(format!("{s:p}"), format!("{:p}", s.as_ptr()));
19-
assert_eq!(format!("{b:p}"), format!("{:p}", b.as_ptr()));
18+
assert_eq!(format!("{s:p}"), format!("{:p}", s as *const _));
19+
assert_eq!(format!("{b:p}"), format!("{:p}", b as *const _));
20+
}
21+
22+
#[test]
23+
fn test_fmt_debug_of_raw_pointers() {
24+
use core::fmt::Debug;
25+
26+
fn check_fmt<T: Debug>(t: T, expected: &str) {
27+
use std::sync::LazyLock;
28+
29+
use regex::Regex;
30+
31+
static ADDR_REGEX: LazyLock<Regex> =
32+
LazyLock::new(|| Regex::new(r"0x[0-9a-fA-F]+").unwrap());
33+
34+
let formatted = format!("{:?}", t);
35+
let normalized = ADDR_REGEX.replace_all(&formatted, "$$HEX");
36+
37+
assert_eq!(normalized, expected);
38+
}
39+
40+
let plain = &mut 100;
41+
check_fmt(plain as *mut i32, "$HEX");
42+
check_fmt(plain as *const i32, "$HEX");
43+
44+
let slice = &mut [200, 300, 400][..];
45+
check_fmt(slice as *mut [i32], "Pointer { addr: $HEX, metadata: 3 }");
46+
check_fmt(slice as *const [i32], "Pointer { addr: $HEX, metadata: 3 }");
47+
48+
let vtable = &mut 500 as &mut dyn Debug;
49+
check_fmt(vtable as *mut dyn Debug, "Pointer { addr: $HEX, metadata: DynMetadata($HEX) }");
50+
check_fmt(vtable as *const dyn Debug, "Pointer { addr: $HEX, metadata: DynMetadata($HEX) }");
2051
}
2152

2253
#[test]

0 commit comments

Comments
 (0)