diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index e1ea98813031a..09be9aac95de8 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -6,6 +6,7 @@ use crate::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use crate::char::EscapeDebugExtArgs; use crate::marker::PhantomData; use crate::mem; +use crate::ptr::{self, DynMetadata}; use crate::num::fmt as numfmt; use crate::ops::Deref; use crate::result; @@ -2281,16 +2282,51 @@ impl Pointer for &mut T { // Implementation of Display/Debug for various core types +/// A local trait for pointer Debug impl so that we can have +/// min_specialization-compliant specializations for two types of fat ptrs. +trait PtrMetadataFmt { + fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result; +} + +// Regular pointer / default impl +impl PtrMetadataFmt for T { + #[inline] + default fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result { + Pointer::fmt(&ptr, f) + } +} + +// Pointer + length +impl PtrMetadataFmt for usize { + #[inline] + fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result { + write!(f, "({:p}, {})", ptr, *self) + } +} + +// Pointer + vtable +impl PtrMetadataFmt for DynMetadata { + #[inline] + fn fmt_ptr(&self, ptr: *const (), f: &mut Formatter<'_>) -> Result { + f.debug_tuple("") + .field(&ptr) + .field(self) + .finish() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *const T { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - Pointer::fmt(self, f) + let meta = ptr::metadata(*self); + meta.fmt_ptr(*self as *const (), f) } } #[stable(feature = "rust1", since = "1.0.0")] impl Debug for *mut T { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - Pointer::fmt(self, f) + let ptr: *const T = *self; + Debug::fmt(&ptr, f) } } diff --git a/library/core/tests/fmt/mod.rs b/library/core/tests/fmt/mod.rs index 7b281ce48e6aa..542867ac629cd 100644 --- a/library/core/tests/fmt/mod.rs +++ b/library/core/tests/fmt/mod.rs @@ -2,6 +2,10 @@ mod builders; mod float; mod num; +use core::any::Any; +use core::fmt; +use core::ptr; + #[test] fn test_format_flags() { // No residual flags left by pointer formatting @@ -19,6 +23,36 @@ fn test_pointer_formats_data_pointer() { assert_eq!(format!("{:p}", b), format!("{:p}", b.as_ptr())); } +#[test] +fn test_pointer_formats_debug_thin() { + let thinptr = &42 as *const i32; + assert_eq!(format!("{:?}", thinptr as *const ()), format!("{:p}", thinptr)); +} + +#[test] +fn test_pointer_formats_debug_slice() { + let b: &[u8] = b"hello"; + let s: &str = "hello"; + let b_ptr = &*b as *const _; + let s_ptr = &*s as *const _; + assert_eq!(format!("{:?}", b_ptr), format!("({:?}, 5)", b.as_ptr())); + assert_eq!(format!("{:?}", s_ptr), format!("({:?}, 5)", s.as_ptr())); + + // :p should format as a thin pointer / without metadata + assert_eq!(format!("{:p}", b_ptr), format!("{:p}", b.as_ptr())); + assert_eq!(format!("{:p}", s_ptr), format!("{:p}", s.as_ptr())); +} + +#[test] +fn test_pointer_formats_debug_trait_object() { + let mut any: Box = Box::new(42); + let dyn_ptr = &mut *any as *mut dyn Any; + assert_eq!(format!("{:?}", dyn_ptr), format!("({:?}, {:?})", dyn_ptr as *const (), ptr::metadata(dyn_ptr))); + + // :p should format as a thin pointer / without metadata + assert_eq!(format!("{:p}", dyn_ptr), format!("{:p}", dyn_ptr as *const ())); +} + #[test] fn test_estimated_capacity() { assert_eq!(format_args!("").estimated_capacity(), 0); @@ -33,8 +67,8 @@ fn test_estimated_capacity() { fn pad_integral_resets() { struct Bar; - impl core::fmt::Display for Bar { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + impl fmt::Display for Bar { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "1".fmt(f)?; f.pad_integral(true, "", "5")?; "1".fmt(f)