Skip to content

Commit db03ec6

Browse files
Rollup merge of rust-lang#126242 - yaahc:simplify-provider, r=jhpratt
Simplify provider api to improve llvm ir This PR seeks to resolve the last concern in rust-lang#99301 (comment) We resolve the issue by moving the type_id to be stored in the `Request` itself rather than being accessed through the `Erased` trait, letting the compiler infer that the value of the type id will not change between lookups. ### LLVM Codegen **Before** ``` ; <provider_test::MyError as core::error::Error>::provide ; Function Attrs: nonlazybind uwtable define void `@"_ZN61_$LT$provider_test..MyError$u20$as$u20$core..error..Error$GT$7provide17hd9c9de412063aa73E"(ptr` noalias nocapture noundef nonnull readonly align 1 %self, ptr noundef nonnull align 1 %request.0, ptr noalias nocapture noundef readonly align 8 dereferenceable(32) %request.1) unnamed_addr #0 personality ptr `@rust_eh_personality` { start: %0 = getelementptr inbounds i8, ptr %request.1, i64 24 %self.1.val.i = load ptr, ptr %0, align 8 %1 = tail call { i64, i64 } %self.1.val.i(ptr noundef nonnull align 1 %request.0), !noalias !15 %2 = extractvalue { i64, i64 } %1, 0 %3 = extractvalue { i64, i64 } %1, 1 %_18.i.i = icmp ne i64 %2, 1101338453689927725 %_2.i.i = icmp ne i64 %3, 472224167662714873 %or.cond.i.not.i = select i1 %_18.i.i, i1 true, i1 %_2.i.i br i1 %or.cond.i.not.i, label %_ZN4core5error7Request7provide17h8f8125d2543333e0E.exit, label %bb2.i ``` **After** ``` ; <provider_test::MyError as provider_test::Error>::provide ; Function Attrs: mustprogress nofree norecurse nosync nounwind nonlazybind willreturn memory(argmem: readwrite) uwtable define void `@"_ZN63_$LT$provider_test..MyError$u20$as$u20$provider_test..Error$GT$7provide17h5bbf091795a6d359E"(ptr` noalias nocapture noundef nonnull readonly align 1 %self, ptr nocapture noundef nonnull align 8 %request.0, ptr noalias nocapture noundef readonly align 8 dereferenceable(24) %request.1) unnamed_addr #2 personality ptr `@rust_eh_personality` { start: %_19.i = load i64, ptr %request.0, align 8, !noalias !3, !noundef !3 switch i64 %_19.i, label %_ZN13provider_test7Request7provide17heb3ee140962e3b2fE.exit [ i64 7665305208997882008, label %bb12.i i64 7050211241160863540, label %bb12.i3 i64 9112786072622981063, label %bb12.i11 ] ```
2 parents 956efde + 8b6f468 commit db03ec6

File tree

1 file changed

+23
-26
lines changed

1 file changed

+23
-26
lines changed

core/src/error.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,9 @@ fn request_by_type_tag<'a, I>(err: &'a (impl Error + ?Sized)) -> Option<I::Reifi
404404
where
405405
I: tags::Type<'a>,
406406
{
407-
let mut tagged = TaggedOption::<'a, I>(None);
407+
let mut tagged = Tagged { tag_id: TypeId::of::<I>(), value: TaggedOption::<'a, I>(None) };
408408
err.provide(tagged.as_request());
409-
tagged.0
409+
tagged.value.0
410410
}
411411

412412
///////////////////////////////////////////////////////////////////////////////
@@ -507,16 +507,9 @@ where
507507
///
508508
#[unstable(feature = "error_generic_member_access", issue = "99301")]
509509
#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435
510-
pub struct Request<'a>(dyn Erased<'a> + 'a);
510+
pub struct Request<'a>(Tagged<dyn Erased<'a> + 'a>);
511511

512512
impl<'a> Request<'a> {
513-
/// Create a new `&mut Request` from a `&mut dyn Erased` trait object.
514-
fn new<'b>(erased: &'b mut (dyn Erased<'a> + 'a)) -> &'b mut Request<'a> {
515-
// SAFETY: transmuting `&mut (dyn Erased<'a> + 'a)` to `&mut Request<'a>` is safe since
516-
// `Request` is repr(transparent).
517-
unsafe { &mut *(erased as *mut dyn Erased<'a> as *mut Request<'a>) }
518-
}
519-
520513
/// Provide a value or other type with only static lifetimes.
521514
///
522515
/// # Examples
@@ -940,37 +933,38 @@ pub(crate) mod tags {
940933
#[repr(transparent)]
941934
pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option<I::Reified>);
942935

943-
impl<'a, I: tags::Type<'a>> TaggedOption<'a, I> {
936+
impl<'a, I: tags::Type<'a>> Tagged<TaggedOption<'a, I>> {
944937
pub(crate) fn as_request(&mut self) -> &mut Request<'a> {
945-
Request::new(self as &mut (dyn Erased<'a> + 'a))
938+
let erased = self as &mut Tagged<dyn Erased<'a> + 'a>;
939+
// SAFETY: transmuting `&mut Tagged<dyn Erased<'a> + 'a>` to `&mut Request<'a>` is safe since
940+
// `Request` is repr(transparent).
941+
unsafe { &mut *(erased as *mut Tagged<dyn Erased<'a>> as *mut Request<'a>) }
946942
}
947943
}
948944

949945
/// Represents a type-erased but identifiable object.
950946
///
951947
/// This trait is exclusively implemented by the `TaggedOption` type.
952-
unsafe trait Erased<'a>: 'a {
953-
/// The `TypeId` of the erased type.
954-
fn tag_id(&self) -> TypeId;
955-
}
948+
unsafe trait Erased<'a>: 'a {}
956949

957-
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {
958-
fn tag_id(&self) -> TypeId {
959-
TypeId::of::<I>()
960-
}
950+
unsafe impl<'a, I: tags::Type<'a>> Erased<'a> for TaggedOption<'a, I> {}
951+
952+
struct Tagged<E: ?Sized> {
953+
tag_id: TypeId,
954+
value: E,
961955
}
962956

963-
impl<'a> dyn Erased<'a> + 'a {
957+
impl<'a> Tagged<dyn Erased<'a> + 'a> {
964958
/// Returns some reference to the dynamic value if it is tagged with `I`,
965959
/// or `None` otherwise.
966960
#[inline]
967961
fn downcast<I>(&self) -> Option<&TaggedOption<'a, I>>
968962
where
969963
I: tags::Type<'a>,
970964
{
971-
if self.tag_id() == TypeId::of::<I>() {
965+
if self.tag_id == TypeId::of::<I>() {
972966
// SAFETY: Just checked whether we're pointing to an I.
973-
Some(unsafe { &*(self as *const Self).cast::<TaggedOption<'a, I>>() })
967+
Some(&unsafe { &*(self as *const Self).cast::<Tagged<TaggedOption<'a, I>>>() }.value)
974968
} else {
975969
None
976970
}
@@ -983,9 +977,12 @@ impl<'a> dyn Erased<'a> + 'a {
983977
where
984978
I: tags::Type<'a>,
985979
{
986-
if self.tag_id() == TypeId::of::<I>() {
987-
// SAFETY: Just checked whether we're pointing to an I.
988-
Some(unsafe { &mut *(self as *mut Self).cast::<TaggedOption<'a, I>>() })
980+
if self.tag_id == TypeId::of::<I>() {
981+
Some(
982+
// SAFETY: Just checked whether we're pointing to an I.
983+
&mut unsafe { &mut *(self as *mut Self).cast::<Tagged<TaggedOption<'a, I>>>() }
984+
.value,
985+
)
989986
} else {
990987
None
991988
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy