Safe-to-use macro-free self-referential structs in stable Rust?

Recently ran into a situation where self referential structs would have been a nice solution, and while I found a decent amount of discussion around the topic I didn't find a satisfying solution. So begrudgingly I unpacked to unsafe hammer and got to work.

I'd really appreciate any feedback from API to soundness. Note, the documentation is still very rudimentary and I plan to properly document all functions and traits. But before that it would be great if some more experienced people than me could take a look at the unsafe in, going through the nomicon I couldn't find a way this could be used to trigger UB, and so far miri agrees with me

One of the core motivations for this was that rental is heavy to compile and no longer maintained, while this is pretty minimal:

Compiling once_cell v1.5.2
Compiling once_self_cell v0.1.0
Completed once_cell v1.5.2 in 0.9s
Completed once_self_cell v0.1.0 in 0.3s

This looks like something going wrong in safe code:

use once_self_cell::sync::OnceSelfCell;
use std::fmt::Debug;

struct Ref<'a, T: Debug>(&'a T);

enum Void {}

fn main() {

impl<'a, T: Debug> Drop for Ref<'a, T> {
    fn drop(&mut self) {
        println!("{:?}", self.0);
$ cargo run
   Compiling testing v0.0.0 (/git/repro)
    Finished dev [unoptimized + debuginfo] target(s) in 0.08s
     Running `target/debug/repro`
Illegal instruction (core dumped)
use once_self_cell::sync::OnceSelfCell;

fn main() {
    let c: OnceSelfCell<()> = OnceSelfCell::new(());
    let () = c.get_or_init_dependent(|_| ());
    let bad: &i32 = c.get_or_init_dependent(|_| 42);
    println!("{}", bad);
Segmentation fault (core dumped)

Also note, that such a question is perhaps more fitting on; with the code-review tag.


@dtolnay @steffahn thanks for the feedback. I've published a new version with both problems addressed. And also posted a code-review request here

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.