From eb7eb438531422ca974afd60e419f9e643bdff20 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 25 Mar 2021 16:45:21 -0400 Subject: [PATCH] Eliminate functionally duplicate vtable methods on rustc 1.51+ --- src/error.rs | 88 ++++++++++++++++++++++++++++++++++++++++++---------- src/ptr.rs | 30 ++++++++++++++++++ 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/src/error.rs b/src/error.rs index 8912505..f4f5bc2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,11 +1,15 @@ use crate::alloc::Box; use crate::backtrace::Backtrace; use crate::chain::Chain; -use crate::ptr::{Mut, Own, Ref}; +#[cfg(any(feature = "std", anyhow_no_ptr_addr_of))] +use crate::ptr::Mut; +use crate::ptr::{Own, Ref}; use crate::{Error, StdError}; use core::any::TypeId; use core::fmt::{self, Debug, Display}; use core::mem::ManuallyDrop; +#[cfg(not(anyhow_no_ptr_addr_of))] +use core::ptr; use core::ptr::NonNull; #[cfg(feature = "std")] @@ -81,9 +85,11 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::, object_ref: object_ref::, + #[cfg(anyhow_no_ptr_addr_of)] object_mut: object_mut::, object_boxed: object_boxed::, object_downcast: object_downcast::, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::, object_drop_rest: object_drop_front::, #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -103,10 +109,11 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, - #[cfg(feature = "std")] + #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: object_downcast::, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::, object_drop_rest: object_drop_front::, #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -127,10 +134,11 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, - #[cfg(feature = "std")] + #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: object_downcast::, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::, object_drop_rest: object_drop_front::, #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -153,9 +161,11 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, + #[cfg(anyhow_no_ptr_addr_of)] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: context_downcast::, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: context_downcast_mut::, object_drop_rest: context_drop_rest::, #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -176,9 +186,11 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::, object_ref: object_ref::, + #[cfg(anyhow_no_ptr_addr_of)] object_mut: object_mut::, object_boxed: object_boxed::, object_downcast: object_downcast::>, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: object_downcast_mut::>, object_drop_rest: object_drop_front::>, #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -284,10 +296,11 @@ impl Error { let vtable = &ErrorVTable { object_drop: object_drop::>, object_ref: object_ref::>, - #[cfg(feature = "std")] + #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: object_mut::>, object_boxed: object_boxed::>, object_downcast: context_chain_downcast::, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: context_chain_downcast_mut::, object_drop_rest: context_chain_drop_rest::, #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -396,14 +409,20 @@ impl Error { E: Display + Debug + Send + Sync + 'static, { let target = TypeId::of::(); + let inner = self.inner.by_mut(); unsafe { // Use vtable to find NonNull<()> which points to a value of type E // somewhere inside the data structure. - let addr = - match (vtable(self.inner.ptr).object_downcast_mut)(self.inner.by_mut(), target) { - Some(addr) => addr.extend(), - None => return Err(self), - }; + #[cfg(not(anyhow_no_ptr_addr_of))] + let addr = match (vtable(inner.ptr).object_downcast)(inner.by_ref(), target) { + Some(addr) => addr.by_mut().extend(), + None => return Err(self), + }; + #[cfg(anyhow_no_ptr_addr_of)] + let addr = match (vtable(inner.ptr).object_downcast_mut)(inner, target) { + Some(addr) => addr.extend(), + None => return Err(self), + }; // Prepare to read E out of the data structure. We'll drop the rest // of the data structure separately so that E is not dropped. @@ -477,7 +496,14 @@ impl Error { unsafe { // Use vtable to find NonNull<()> which points to a value of type E // somewhere inside the data structure. + + #[cfg(not(anyhow_no_ptr_addr_of))] + let addr = + (vtable(self.inner.ptr).object_downcast)(self.inner.by_ref(), target)?.by_mut(); + + #[cfg(anyhow_no_ptr_addr_of)] let addr = (vtable(self.inner.ptr).object_downcast_mut)(self.inner.by_mut(), target)?; + Some(addr.cast::().deref_mut()) } } @@ -537,10 +563,11 @@ impl Drop for Error { struct ErrorVTable { object_drop: unsafe fn(Own), object_ref: unsafe fn(Ref) -> Ref, - #[cfg(feature = "std")] + #[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] object_mut: unsafe fn(Mut) -> &mut (dyn StdError + Send + Sync + 'static), object_boxed: unsafe fn(Own) -> Box, object_downcast: unsafe fn(Ref, TypeId) -> Option>, + #[cfg(anyhow_no_ptr_addr_of)] object_downcast_mut: unsafe fn(Mut, TypeId) -> Option>, object_drop_rest: unsafe fn(Own, TypeId), #[cfg(all(not(backtrace), feature = "backtrace"))] @@ -571,12 +598,21 @@ where E: StdError + Send + Sync + 'static, { // Attach E's native StdError vtable onto a pointer to self._object. - Ref::new(&e.cast::>().deref()._object) + + let unerased = e.cast::>(); + + #[cfg(not(anyhow_no_ptr_addr_of))] + return Ref::from_raw(NonNull::new_unchecked( + ptr::addr_of!((*unerased.as_ptr())._object) as *mut E, + )); + + #[cfg(anyhow_no_ptr_addr_of)] + return Ref::new(&unerased.deref()._object); } // Safety: requires layout of *e to match ErrorImpl, and for `e` to be derived // from a `&mut` -#[cfg(feature = "std")] +#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] unsafe fn object_mut(e: Mut) -> &mut (dyn StdError + Send + Sync + 'static) where E: StdError + Send + Sync + 'static, @@ -602,14 +638,26 @@ where if TypeId::of::() == target { // Caller is looking for an E pointer and e is ErrorImpl, take a // pointer to its E field. - let unerased = e.cast::>().deref(); - Some(Ref::new(&unerased._object).cast::<()>()) + + let unerased = e.cast::>(); + + #[cfg(not(anyhow_no_ptr_addr_of))] + return Some( + Ref::from_raw(NonNull::new_unchecked( + ptr::addr_of!((*unerased.as_ptr())._object) as *mut E, + )) + .cast::<()>(), + ); + + #[cfg(anyhow_no_ptr_addr_of)] + return Some(Ref::new(&unerased.deref()._object).cast::<()>()); } else { None } } // Safety: requires layout of *e to match ErrorImpl. +#[cfg(anyhow_no_ptr_addr_of)] unsafe fn object_downcast_mut(e: Mut, target: TypeId) -> Option> where E: 'static, @@ -649,7 +697,7 @@ where } // Safety: requires layout of *e to match ErrorImpl>. -#[cfg(feature = "std")] +#[cfg(all(feature = "std", anyhow_no_ptr_addr_of))] unsafe fn context_downcast_mut(e: Mut, target: TypeId) -> Option> where C: 'static, @@ -705,6 +753,7 @@ where } // Safety: requires layout of *e to match ErrorImpl>. +#[cfg(anyhow_no_ptr_addr_of)] unsafe fn context_chain_downcast_mut(e: Mut, target: TypeId) -> Option> where C: 'static, @@ -805,7 +854,14 @@ impl ErrorImpl { pub(crate) unsafe fn error_mut(this: Mut) -> &mut (dyn StdError + Send + Sync + 'static) { // Use vtable to attach E's native StdError vtable for the right // original type E. - (vtable(this.ptr).object_mut)(this) + + #[cfg(not(anyhow_no_ptr_addr_of))] + return (vtable(this.ptr).object_ref)(this.by_ref()) + .by_mut() + .deref_mut(); + + #[cfg(anyhow_no_ptr_addr_of)] + return (vtable(this.ptr).object_mut)(this); } #[cfg(any(backtrace, feature = "backtrace"))] diff --git a/src/ptr.rs b/src/ptr.rs index 27a2235..6840833 100644 --- a/src/ptr.rs +++ b/src/ptr.rs @@ -91,6 +91,14 @@ where } } + #[cfg(not(anyhow_no_ptr_addr_of))] + pub fn from_raw(ptr: NonNull) -> Self { + Ref { + ptr, + lifetime: PhantomData, + } + } + pub fn cast(self) -> Ref<'a, U::Target> { Ref { ptr: self.ptr.cast(), @@ -98,6 +106,19 @@ where } } + #[cfg(not(anyhow_no_ptr_addr_of))] + pub fn by_mut(self) -> Mut<'a, T> { + Mut { + ptr: self.ptr, + lifetime: PhantomData, + } + } + + #[cfg(not(anyhow_no_ptr_addr_of))] + pub fn as_ptr(self) -> *const T { + self.ptr.as_ptr() as *const T + } + pub unsafe fn deref(self) -> &'a T { &*self.ptr.as_ptr() } @@ -127,6 +148,7 @@ impl<'a, T> Mut<'a, T> where T: ?Sized, { + #[cfg(anyhow_no_ptr_addr_of)] pub fn new(ptr: &'a mut T) -> Self { Mut { ptr: NonNull::from(ptr), @@ -141,6 +163,14 @@ where } } + #[cfg(not(anyhow_no_ptr_addr_of))] + pub fn by_ref(self) -> Ref<'a, T> { + Ref { + ptr: self.ptr, + lifetime: PhantomData, + } + } + pub fn extend<'b>(self) -> Mut<'b, T> { Mut { ptr: self.ptr,