'cannot move out of dereference of raw pointer'

Isn’t struct inheritance with pointers possible?

error[E0507]: cannot move out of dereference of raw pointer
  --> src/main.rs:14:22
   |
14 |     let a = unsafe { *(Rc::into_raw(b) as *const A ) };
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         cannot move out of dereference of raw pointer

Input:

use std::rc::Rc;

struct A { x: i32 }

struct B {
    a: A,
    y: i32
}

fn main() {
    let b = Rc::new(B { a: A { x: 404 }, y: 0 });
    let a = unsafe { *(Rc::into_raw(b) as *const A ) };
    println!("{:?}", a.x);
}

It’s customary to include a question with a post…

Anyway, the error is because A is not Copy, which means that you’re doing a move - but “moving out of a raw-pointed-to content” is conceptually the same as “moving out of borrowed content”, which is also disallowed.

You can either keep a around in pointer form, and dereference individual fields - (*ptr).x is fine since i32 is Copy - or make A itself Copy.

1 Like

I didn’t want to copy the contents of A. A = base and B = A. Something like &b.a as *const usize must hold the entire B struct. When I read *b, I’ll never do Rc::new(*b) again, too… I’ll always dependend on the earlier Rc<B>.

My explanation got a bit confuse. What I mean is, I want to treat B as A and vice-versa. The most complex struct leads the core data in a Rc::.

Ah, now I got your answer. But is it reallyn’t possible to read without copying? E.g., read directly from the pointer, without passing the entire data anywhere else.

I am really unsure about what you would like to obtain, so my answer may be wrong for you. Nevertheless, how about this?

fn main() {
    let b = Rc::new(B { a: A { x: 404 }, y: 0 });
    let a = &b.a;
    println!("{:?}", a.x);
}
1 Like

With borrows I’m not able to pass A elsewhere and cast it to B back. I.e., after

let a = &b.a;

I can’t do this back:

let b = *(a as *const B);
//  b = *(a as &B); also fails

But, yep, sometimes I could use borrows!

It seems that you assume that struct B will start with struct A at offset 0. Turns out that Rust doesn’t guarantee anything about data layout! For example, currently in this case:

struct A { x: i32 }

struct B {
    a: A,
    y: i64,
    z: i32,
}

The fields in B will be reordered: y, a, z. Take a look at the data layout chapter in the nomicon (the whole nomicon is worth reading if you want to write unsafe Rust).

If you want to have anything guaranteed about the data layout, use #[repr(C)] annotation on a struct.


To avoid the “cannot move out” error in your original code, you can just make a a raw pointer, and perform a copy only of an int:

fn main() {
    let b = Rc::new(B { a: A { x: 404 }, y: 0 });
    unsafe {
        let a = Rc::into_raw(b) as *const A;
        println!("{:?}", (*a).x);
    }
}

Trying to force inheritance patterns into Rust is usually not a best idea. Can you perhaps share a more specific problem that you’re trying to solve here?

1 Like

Ok, you are trying to mix composition and inheritance, and you should really not do it.

Take the following:

struct A { x: i32 }

struct B {
    a: A,
    y: i64,
    z: i32,
}

fn from_a_to_b(a: &A) -> &B {
    unsafe { std::mem::transmute(a as *const A as *const B)}
}

fn make_boom() {
  let a = A { x: 42 };
  let _b = from_a_to_b(&a);
}

This code is completely unsound! And in make_boom, you are getting an UB.

1 Like

(I’m not touching the “this is probably not what you want to do” aspect here; the other posters are completely right about it, as long as you’re not doing FFI with C structs, which I was assuming you did, and left the gory details out for simplicity.)

The question is what you mean by “read”. Having a variable of type A is to own it. Which means that you must move it, since it might have meaning attached like “this is a Vec whose backing storage must be deleted on drop”.

If you just want to access things behind the pointer, don’t dereference it, but treat it like an ordinary reference. You wouldn’t do this with Rust references:

fn read_from_a_vec(arg: &Vec<T>) {
    let vec = *arg;
    // do something with vec
}

Instead, you’d access the contents through the reference.

1 Like