Skip to content

impl<T> PointerLike for {Rc,Arc,Weak}<T> can't exist but should #134591

Closed
@kpreid

Description

@kpreid
Contributor

The unstable trait PointerLike must be implemented for any type which is to be coerced to a dyn* type. However, the only built-in smart pointer type it is currently implemented for is Box, and this is a special case in the compiler.

I believe it would be useful for PointerLike to be implemented for, among other things, Rc, Arc, and their corresponding Weak types. This would enable use cases such as polymorphic collections like Vec<dyn* SomeTrait> where each element consists of a (strong or weak) reference-counted pointer to other data structures, whereas the current available option is Vec<Box<dyn SomeTrait>> which results in an inefficient extra allocation and double-indirection for each item.

However, it is currently impossible even to modify the standard library to meet this requirement. This is because the compiler requires that the type implementing PointerLike be either primitive or repr(transparent), and types like Rc cannot be repr(transparent) because they have an allocator field:

pub struct Rc<
    T: ?Sized,
    #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
> {
    ptr: NonNull<RcInner<T>>,
    phantom: PhantomData<RcInner<T>>,
    alloc: A,
}

The only non-zero-sized field of Rc<T> is ptr, but Rc<T, SomeNonZstAllocator> is non-zero-sized, which disqualifies the entire Rc type from being able to have repr(transparent), and therefore means you can't even implement PointerLike for Rc<T> = Rc<T, Global>.

It seems to me that, therefore, it would be useful to adjust the design of PointerLike’s implementation restriction — or of repr(transparent), or something — so that impl PointerLike<T> for Rc<T> is possible. Box manages to implement PointerLike only by way of having been granted a unique “is Box” exception. This exception could be generalized to other standard library types, and that would address being able to use Rc and friends in dyn*, but it would privilege the standard library in a way that has no path to stabilization.

(If dyn* settles into being solely an async trait implementation detail and not a language feature, then this entire issue is arguably moot since users won't be getting to write Vec<dyn* Trait> at all — but PointerLike would still be potentially useful as a trait bound to people trying to solve similar problems in libraries.)


For an example of the kind of code I’m interested in writing:

#![allow(incomplete_features)]
#![feature(pointer_like_trait)]
#![feature(dyn_star)]

use std::cell::Cell;
use std::rc::{Rc, Weak};

pub trait Watcher<T> {
    fn notify(&self, value: &T);
}

pub struct Watched<T> {
    value: T,
    watchers: Vec<dyn* Watcher<T>>,
}

impl<T> Watched<T> {
    pub fn set(&mut self, value: T) {
        self.value = value;
        for watcher in self.watchers.iter() {
            watcher.notify(&self.value);
        }
    }
}

#[repr(transparent)]
struct CopyToCell<T>(Weak<Cell<T>>);
impl<T> core::marker::PointerLike for CopyToCell<T> {}
impl<T: Copy + 'static> Watcher<T> for CopyToCell<T> {
    fn notify(&self, value: &T) {
        if let Some(cell) = self.0.upgrade() {
            cell.set(*value);
        }
    }
}

fn main() {
    let c = Rc::new(Cell::new(0));
    let mut w = Watched {
        value: 0,
        watchers: vec![
            CopyToCell(Rc::downgrade(&c))
        ],
    };
    
    w.set(1);
    assert_eq!(c.get(), 1);
}

This code does not compile, but the only reason it does not is that the PointerLike implementation is rejected. You can prove this by wrapping the Weak in an extra Box, and, it will compile and run on current nightly.


@rustbot label +F-dyn_star

Activity

added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
F-dyn_star`#![feature(dyn_star)]`
on Dec 21, 2024
added
C-feature-requestCategory: A feature request, i.e: not implemented / a PR.
and removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on Dec 21, 2024
compiler-errors

compiler-errors commented on Dec 21, 2024

@compiler-errors
Member

Noting that we gotta be careful about the repr here.

Using repr(C) will make the type not pointer-like since it stores its fields as an aggregate by definition (or something like that -- it causes ICEs in codegen anywho), and I'm not certain we guarantee enough about the layout of repr(Rust) to ensure that it'll always be pointer-like if it's only non-1-ZST field is pointer-like. That's why I went with repr(transparent) here.

kpreid

kpreid commented on Dec 22, 2024

@kpreid
ContributorAuthor

I'm experimenting with persuading the compiler to accept these impls anyway (the “privilege the standard library” approach I mentioned above). I’ll take your remark as indicating that a PR for that had better have tests for actually being able to produce working code with the impls. I believe that repr(Rust) will never insert useless padding (not even under -Zrandomize-layout, in the current implementation, but that is not guaranteed), so its size and alignment, per se, will always remain pointer-like, but I don't myself really understand the scalar/aggregate thing. (Other than I think “in C calling convention, aggregates are never passed in registers”? Or I might be confusing it with a different distinction.)

workingjubilee

workingjubilee commented on Dec 25, 2024

@workingjubilee
Member

(Other than I think “in C calling convention, aggregates are never passed in registers”

@kpreid Well, it is inconsistent, and perhaps more importantly, not Scalar or ScalarPair.

viliml

viliml commented on Jun 1, 2025

@viliml
Contributor

How about adding a new repr, repr(try_transparent) that uses transparent if it satisfies the requirements and Rust otherwise? With an optional fallback repr like repr(try_transparent, C).

added a commit that references this issue on Jun 27, 2025

Rollup merge of rust-lang#143036 - compiler-errors:no-dyn-star, r=oli…

760c666
added a commit that references this issue on Jul 1, 2025

Auto merge of #143036 - compiler-errors:no-dyn-star, r=oli-obk

085c247
added a commit that references this issue on Jul 2, 2025
ae9fc91
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-feature-requestCategory: A feature request, i.e: not implemented / a PR.F-dyn_star`#![feature(dyn_star)]`

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @kpreid@viliml@compiler-errors@workingjubilee@rustbot

      Issue actions

        `impl<T> PointerLike for {Rc,Arc,Weak}<T>` can't exist but should · Issue #134591 · rust-lang/rust